diff --git a/docs/getting-started/self-hosted-install.md b/docs/getting-started/self-hosted-install.md index b9f413f..c56fa21 100644 --- a/docs/getting-started/self-hosted-install.md +++ b/docs/getting-started/self-hosted-install.md @@ -96,8 +96,16 @@ rather than run in a half-prepared state. ## 4. Put a proxy in front -Point your reverse proxy at `web` on port `3000` and terminate TLS there. The -web app reaches the API internally, so there is no need to publish port `8080`. +Terminate TLS at your reverse proxy and route **one hostname to two backends**: + +| Path | Backend | +| -------------------------------------------------------------------------------- | ------------- | +| `/api`, `/auth`, `/public`, `/install`, `/install.ps1`, `/update`, `/update.ps1` | `server:8080` | +| everything else | `web:3000` | + +Both rules are required. The web app forwards nothing to the API, so a proxy +that sends the whole hostname to `web:3000` serves the interface and answers +`404` to every request it makes — starting with the login form. Agents connect to port `9090`. Vantage does not terminate TLS itself, so put that port behind your proxy too, with a certificate valid for the name in diff --git a/docs/reference/ports-and-networking.md b/docs/reference/ports-and-networking.md index e1d9e49..2aaa4e2 100644 --- a/docs/reference/ports-and-networking.md +++ b/docs/reference/ports-and-networking.md @@ -9,7 +9,7 @@ sidebar_label: Ports and networking | Port | Service | Who connects | Expose publicly | | ------- | ----------- | -------------------------------- | --------------- | | `3000` | web | Browsers, via your reverse proxy | Yes, behind TLS | -| `8080` | server API | The web app | No, firewall it | +| `8080` | server API | Your reverse proxy | Not directly — proxied | | `9090` | server gRPC | Agents | **Yes** | | `4822` | guacd | The server | No, firewall it | | `27017` | MongoDB | The server | No | @@ -20,8 +20,8 @@ sidebar_label: Ports and networking ```mermaid flowchart LR B["Browser"] -->|HTTPS| P["Reverse proxy"] - P --> W["web :3000"] - W --> S["server :8080"] + P -->|"everything else"| W["web :3000"] + P -->|"/api /auth /public /install* /update*"| S["server :8080"] A["Agent on a managed server"] -->|"gRPC/TLS :9090, outbound"| S S --> G["guacd :4822"] G -->|"relayed over the :9090 stream"| A @@ -77,8 +77,20 @@ On a private network you can skip TLS instead, by setting `tls: false` in each ## Reverse proxy notes -- Point the proxy at `web:3000`. The web app reaches the API internally, so - `8080` does not need publishing. +- **The proxy routes two backends on one hostname**, and both are required: + + | Path | Backend | + | ------------------------------------------------------------- | ------------- | + | `/api`, `/auth`, `/public`, `/install`, `/install.ps1`, `/update`, `/update.ps1` | `server:8080` | + | everything else | `web:3000` | + + The web app forwards nothing to the API. Sending the whole hostname to + `web:3000` loads the interface and every request it makes answers `404` — + including the login form. + +- Both backends must be the **same** hostname and certificate. The browser + calls `/api` relative to the page it is on, and the session cookie is + host-only. - The console uses a **WebSocket** at `/api/console/tunnel`. A proxy that does not forward upgrade headers breaks the console and nothing else. - Workflow log streaming is a long-lived response. A short proxy read timeout diff --git a/docs/reference/troubleshooting.md b/docs/reference/troubleshooting.md index a539364..070ad21 100644 --- a/docs/reference/troubleshooting.md +++ b/docs/reference/troubleshooting.md @@ -20,6 +20,13 @@ or is not 64 hex characters. ## Nobody can sign in +**Every request 404s and the interface loads fine.** Your reverse proxy sends +the whole hostname to `web:3000`. `/api`, `/auth`, `/public`, `/install*` and +`/update*` belong to `server:8080` and the web app forwards nothing — see +[Ports and networking](./ports-and-networking.md#reverse-proxy-notes). The +tell is `curl -si https:///auth/bootstrap-status` returning HTML +with `x-powered-by: Next.js` instead of JSON. + **`/setup` appears when users already exist.** The server is pointed at a different database than you think. Check the database name in `MONGO_URI`, which is taken from the end of the URI. @@ -169,6 +176,11 @@ is `.vantage./status/`, the same per-instance subdomain everything else in Vantage uses. A wrong or missing subdomain resolves to no instance at all, which is also a 404. +Third possibility: `/public` is not routed to the server. Check with +`curl -si https://.vantage./public/status/` +— JSON is correct, HTML carrying `x-powered-by: Next.js` means the proxy sent +that prefix to the web app. + **Loads, but shows an explanation instead of components.** This is not a fault — it is the page working as designed. It means either the licence has lapsed (a self-hosted instance past its grace period, or a cloud instance