From 9e8e027137301021dc358d373aeec37d2350a9f0 Mon Sep 17 00:00:00 2001 From: bachhungcb Date: Thu, 9 Apr 2026 14:48:51 +0700 Subject: [PATCH 1/2] change mesh central proxy --- nginx/nginx.conf | 39 ++++++++++++++++++++--- src/components/cards/computer-card.tsx | 8 ++--- src/config/api.ts | 19 +++++++++-- src/routes/_auth/remote-control/index.tsx | 6 ++-- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 79a2346..3fc6a3c 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -28,6 +28,8 @@ server{ ssl_ciphers HIGH:!aNULL:!MD5; set $backend_server 172.18.10.8:8080; + # 2-container model: FE nginx proxies to MeshCentral container by Docker service name + set $mesh_server meshcentral:8082; root /usr/share/nginx/html; # Default file to serve for directory requests @@ -81,13 +83,42 @@ server{ proxy_read_timeout 1h; } - location /mesh-proxy/ { - proxy_pass https://202.191.59.59/; + location /api/meshcentral/proxy/ { + proxy_pass https://$mesh_server; + proxy_ssl_verify off; proxy_cookie_path / "/; HTTPOnly; Secure; SameSite=None"; - - # Cấu hình WebSocket cho commander.ashx + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Cấu hình WebSocket/SSE cho MeshCentral proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + } + + # FE production currently builds mesh proxy path as /meshapi/api/meshcentral/proxy/... + location /meshapi/api/meshcentral/proxy/ { + rewrite ^/meshapi/(.*)$ /$1 break; + proxy_pass https://$mesh_server; + proxy_ssl_verify off; + proxy_cookie_path / "/; HTTPOnly; Secure; SameSite=None"; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_buffering off; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; } } \ No newline at end of file diff --git a/src/components/cards/computer-card.tsx b/src/components/cards/computer-card.tsx index df5d394..09a21fb 100644 --- a/src/components/cards/computer-card.tsx +++ b/src/components/cards/computer-card.tsx @@ -8,7 +8,7 @@ import { useGetClientFolderStatusForDevice } from "@/hooks/queries"; import type { ClientFolderStatus } from "@/types/folder"; import { Button } from "@/components/ui/button"; import { getRemoteDesktopUrl } from "@/services/remote-control.service"; -import { BASE_URL } from "@/config/api"; +import { buildMeshProxyUrl } from "@/config/api"; import { toast } from "sonner"; export function ComputerCard({ device, @@ -52,11 +52,7 @@ export function ComputerCard({ const response = await getRemoteDesktopUrl(device.id); const originalUrl = new URL(response.url); const pathAndQuery = originalUrl.pathname + originalUrl.search; - const cleanPath = pathAndQuery.startsWith("/") - ? pathAndQuery.substring(1) - : pathAndQuery; - const baseWithoutApi = BASE_URL.replace("/api", ""); - const proxyUrlFull = `${baseWithoutApi}/api/meshcentral/proxy/${cleanPath}`; + const proxyUrlFull = buildMeshProxyUrl(pathAndQuery); setProxyUrl(proxyUrlFull); setShowRemote(true); diff --git a/src/config/api.ts b/src/config/api.ts index ef855c1..e93fe1a 100644 --- a/src/config/api.ts +++ b/src/config/api.ts @@ -1,12 +1,27 @@ const isDev = import.meta.env.MODE === "development"; +const trimTrailingSlash = (value: string) => value.replace(/\/+$/, ""); + export const BASE_URL = isDev ? import.meta.env.VITE_API_URL_DEV : "/api"; export const BASE_MESH_URL = isDev - ? import.meta.env.VITE_API_MESH_DEV - : "/meshapi"; + ? (import.meta.env.VITE_API_MESH || import.meta.env.VITE_API_MESH_DEV || "") + : (import.meta.env.VITE_API_MESH || ""); + +export const buildMeshProxyUrl = (meshPathAndQuery: string) => { + const cleanPath = meshPathAndQuery.startsWith("/") + ? meshPathAndQuery.substring(1) + : meshPathAndQuery; + const proxyPath = `/api/meshcentral/proxy/${cleanPath}`; + + if (BASE_MESH_URL && BASE_MESH_URL.startsWith("http")) { + return `${trimTrailingSlash(BASE_MESH_URL)}${proxyPath}`; + } + + return proxyPath; +}; export const API_ENDPOINTS = { AUTH: { diff --git a/src/routes/_auth/remote-control/index.tsx b/src/routes/_auth/remote-control/index.tsx index 9ea89f6..a8ed770 100644 --- a/src/routes/_auth/remote-control/index.tsx +++ b/src/routes/_auth/remote-control/index.tsx @@ -6,7 +6,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com import { Input } from "@/components/ui/input"; import { Button } from "@/components/ui/button"; import { getRemoteDesktopUrl } from "@/services/remote-control.service"; -import { BASE_URL } from "@/config/api"; +import { buildMeshProxyUrl } from "@/config/api"; export const Route = createFileRoute("/_auth/remote-control/")({ @@ -38,9 +38,7 @@ function RemoteControlPage() { // Chuyển URL MeshCentral thành proxy URL const originalUrl = new URL(data.url); const pathAndQuery = originalUrl.pathname + originalUrl.search; - const cleanPath = pathAndQuery.startsWith('/') ? pathAndQuery.substring(1) : pathAndQuery; - const baseWithoutApi = BASE_URL.replace('/api', ''); - const proxyUrlFull = `${baseWithoutApi}/api/meshcentral/proxy/${cleanPath}`; + const proxyUrlFull = buildMeshProxyUrl(pathAndQuery); console.log("[RemoteControl] Proxy URL:", proxyUrlFull); setProxyUrl(proxyUrlFull); From 6d3f8d4b4ca304e12eb4f2a7fbf6394617a246be Mon Sep 17 00:00:00 2001 From: bachhungcb Date: Fri, 10 Apr 2026 18:52:39 +0700 Subject: [PATCH 2/2] fix remote redirect to using server IP --- nginx/nginx.conf | 51 +++++++++++++++++++++++++++++++++++++++-------- src/config/api.ts | 12 +++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/nginx/nginx.conf b/nginx/nginx.conf index 3fc6a3c..0ceacca 100644 --- a/nginx/nginx.conf +++ b/nginx/nginx.conf @@ -28,8 +28,9 @@ server{ ssl_ciphers HIGH:!aNULL:!MD5; set $backend_server 172.18.10.8:8080; - # 2-container model: FE nginx proxies to MeshCentral container by Docker service name - set $mesh_server meshcentral:8082; + set $meshserver 172.18.10.8:8082; + # MeshCentral traffic should go through backend proxy controller + # (api/meshcentral/proxy/*) for consistent auth/cookie/header handling. root /usr/share/nginx/html; # Default file to serve for directory requests @@ -83,15 +84,44 @@ server{ proxy_read_timeout 1h; } - location /api/meshcentral/proxy/ { - proxy_pass https://$mesh_server; + # MeshCentral client builds WebSocket URL from current location, + # e.g. wss://comp.soict.io/control.ashx. Route these root endpoints + # to meshserver so browser URL stays on comp.soict.io while upstream + # is forced to 172.18.10.8:8082. + location ~ ^/(control|meshrelay|commander|mesh)\.ashx$ { + proxy_pass https://$meshserver; proxy_ssl_verify off; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + proxy_buffering off; + } + + location = /api/meshcentral/proxy { + return 301 /api/meshcentral/proxy/; + } + + location ^~ /api/meshcentral/proxy/ { + # Forward to backend MeshCentralProxyController (api/meshcentral/proxy/*) + # so backend can handle MeshCentral auth/session consistently. + proxy_pass http://$backend_server; proxy_cookie_path / "/; HTTPOnly; Secure; SameSite=None"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; # Cấu hình WebSocket/SSE cho MeshCentral proxy_http_version 1.1; @@ -103,16 +133,21 @@ server{ } # FE production currently builds mesh proxy path as /meshapi/api/meshcentral/proxy/... - location /meshapi/api/meshcentral/proxy/ { - rewrite ^/meshapi/(.*)$ /$1 break; - proxy_pass https://$mesh_server; - proxy_ssl_verify off; + location = /meshapi/api/meshcentral/proxy { + return 301 /meshapi/api/meshcentral/proxy/; + } + + location ^~ /meshapi/api/meshcentral/proxy/ { + # Legacy frontend path -> backend MeshCentralProxyController + rewrite ^/meshapi/api/meshcentral/proxy/(.*)$ /$1 break; + proxy_pass http://$backend_server; proxy_cookie_path / "/; HTTPOnly; Secure; SameSite=None"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; diff --git a/src/config/api.ts b/src/config/api.ts index e93fe1a..046f4d4 100644 --- a/src/config/api.ts +++ b/src/config/api.ts @@ -16,10 +16,22 @@ export const buildMeshProxyUrl = (meshPathAndQuery: string) => { : meshPathAndQuery; const proxyPath = `/api/meshcentral/proxy/${cleanPath}`; + // If an explicit mesh host is configured, always use it. + // This allows forcing proxy URLs to https://:/api/meshcentral/proxy/... if (BASE_MESH_URL && BASE_MESH_URL.startsWith("http")) { return `${trimTrailingSlash(BASE_MESH_URL)}${proxyPath}`; } + // In development, BASE_URL is usually absolute (e.g. http://localhost:5218/api). + // Build an absolute proxy URL to backend so iframe requests do not hit Vite dev server. + if (BASE_URL.startsWith("http")) { + const apiBase = trimTrailingSlash(BASE_URL); + const backendOrigin = apiBase.endsWith("/api") + ? apiBase.slice(0, -4) + : apiBase; + return `${backendOrigin}${proxyPath}`; + } + return proxyPath; };