From dfbc43a43e76529da165ae6ee3ae436c42cf96ce Mon Sep 17 00:00:00 2001 From: danamir Date: Thu, 6 Aug 2026 14:15:15 +0300 Subject: [PATCH] Make client API calls relative instead of hardcoded localhost:5144 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client always called a hardcoded http://localhost:5144, which only worked when browser and server shared the same "localhost" — breaks for any real remote deployment, since the browser would try to reach that port on the visitor's own machine instead of the actual server. Now every environment routes /api/* to the server under the same origin the page was loaded from, so the client code needs no per-environment URL: - Docker (client container's own nginx) proxies /api/ to the server container. - `npm run dev` (Vite) proxies /api to localhost:5144 via server.proxy. - Production nginx (reverse proxy + TLS) just needs to forward everything to the client container, which already knows how to route /api itself. Also incidentally removes CORS from the picture everywhere, since none of these setups make a cross-origin request anymore. --- src/Client/Shared/JsonWire.fs | 8 +++++++- src/Client/nginx.conf | 11 +++++++++++ vite.config.js | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Client/Shared/JsonWire.fs b/src/Client/Shared/JsonWire.fs index 358d415..fa64c06 100644 --- a/src/Client/Shared/JsonWire.fs +++ b/src/Client/Shared/JsonWire.fs @@ -10,7 +10,13 @@ open Fable.Core open Fable.Core.JsInterop open Domain -let private serverUrl = "http://localhost:5144" +// Relative on purpose — the server is always reached through whatever's +// serving this page under `/api/*`: the client's own nginx in Docker +// (see Client/nginx.conf), Vite's dev-server proxy (vite.config.js) for +// `npm run dev`, or the host reverse proxy in production. This also means +// the browser never makes a cross-origin request, so CORS never enters +// into it for any of these setups. +let private serverUrl = "" [] let hasKey (_o: obj) (_key: string) : bool = jsNative diff --git a/src/Client/nginx.conf b/src/Client/nginx.conf index 73ade1e..9a5e186 100644 --- a/src/Client/nginx.conf +++ b/src/Client/nginx.conf @@ -2,6 +2,17 @@ server { listen 80; root /usr/share/nginx/html; + # No trailing slash on proxy_pass here — the full matched URI (including + # the /api/ prefix) is forwarded unchanged, matching Giraffe's route + # definitions in Server/Routes.fs, which all start with /api/. + location /api/ { + proxy_pass http://server:8080; + 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; + } + location / { try_files $uri $uri/ /index.html; } diff --git a/vite.config.js b/vite.config.js index d5deae5..0363bc1 100644 --- a/vite.config.js +++ b/vite.config.js @@ -4,5 +4,11 @@ export default defineConfig({ root: "src/Client", server: { port: 5173, + proxy: { + "/api": { + target: "http://localhost:5144", + changeOrigin: true, + }, + }, }, });