diff --git a/README.md b/README.md index 4d7a35cc..ea6157da 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,6 @@ Depth lives in [`docs/`](docs/) — pick the one matching your task: | config-edit + approval state machine | [`docs/approvals.md`](docs/approvals.md) | | what survives destroy / purge / restart | [`docs/persistence.md`](docs/persistence.md) | | naming, wire protocol, commit style | [`docs/conventions.md`](docs/conventions.md) | -| nginx vhost map + sub-domain routing | [`docs/gateway.md`](docs/gateway.md) | | NixOS / nspawn gotchas | [`docs/gotchas.md`](docs/gotchas.md) | ## Host config diff --git a/docs/gateway.md b/docs/gateway.md deleted file mode 100644 index 698d681c..00000000 --- a/docs/gateway.md +++ /dev/null @@ -1,78 +0,0 @@ -# hive-gateway - -Single nginx in front of every hyperhive web surface. Container `hive-gateway`, shared host netns, system-config (not meta-flake managed). Configured via `services.hyperhive.gateway.*` + per-subsystem opt-in flags in `services.hyperhive.{forge,matrix,...}`. - -## Vhost map - -| URL | vhost | upstream | source | -| --- | --- | --- | --- | -| `/` | `_` (catch-all) | hive-c0re dashboard (`7000`) | always | -| `/agent//` | `_` | per-agent harness on `agent_web_port(name)` | `agentPortsFile` JSON, #15 | -| `/.well-known/matrix/{client,server}` | `_` | inline JSON (no upstream) | `matrix.enable && domain != null`, #660 / #747 | -| `/matrix/` (deprecated) | `_` | 301 → `matrix./` | `matrix.gui.enable`, #772 | -| `forge./` | `forge.` | forgejo (`3000`) | `forge.behindGateway`, #754 | -| `matrix./_matrix/*` | `matrix.` | tuwunel (`8008`) | `matrix.gatewayHost != null`, #764 | -| `matrix./` | `matrix.` | fluffychat-web static | `matrix.gui.enable`, #772 | -| `matrix./config.json` | `matrix.` | inline JSON (FluffyChat boot config) | `matrix.gui.enable && domain != null`, #736 | - -Per-agent UIs stay sub-path because they're hyperhive-internal and base-path-aware (iris #731). External standard apps (forge / matrix) get sub-domains because their defaults work cleanly at sub-domain root + per-origin cookies / storage isolation matters. - -## Discovery flow (matrix) - -Operator points client at ``. Sequence: - -1. Client fetches `http:///.well-known/matrix/client` → `{"m.homeserver":{"base_url":"http://matrix."}}` (no port suffix when gateway listens on 80). -2. Client connects to `matrix./_matrix/client/...`. -3. Gateway routes `/_matrix/*` → tuwunel at `127.0.0.1:8008`. - -Federation peers fetch `.well-known/matrix/server` → `{"m.server":"matrix."}` and connect to `matrix.:8448` per spec default. Gateway only listens on configured `port`; cross-hive federation needs either an SRV record (`_matrix._tcp.matrix.` → port 80) OR `matrix.openFirewall = true` so peers reach tuwunel's federation port directly. Hyperhive is mostly closed/internal, so this rarely bites. - -## SPA fallback (Accept-header pattern) - -The `` catch-all and the `matrix.` vhost both serve a flutter SPA (per-agent UI, fluffychat). Two requirements collide: - -- hard-refresh on a sub-route must serve `index.html` (SPA's client-side router takes over after JS bootstrap) -- missing assets must surface as 404, not as HTML with wrong content-type (the original #643 bug) - -Solution: an `nginx http`-context `map $http_accept $matrix_spa_target { ... }` keyed on the request's Accept header. Browser navigations (`Accept: text/html,...`) get `index.html`; asset fetches (`Accept: image/*`, `*/*`, etc.) get a sentinel nonexistent path → `try_files` falls through to `=404`. No extension allowlist, no `if` block, no regex heuristics. #686 + #729 thread for the design history. - -## Local dev (`localHostsEntry`) - -`services.hyperhive.gateway.localHostsEntry = true` adds entries to the host's `/etc/hosts`: - -- `` → `127.0.0.1` -- `forge.` → `127.0.0.1` (when forge.behindGateway) -- `matrix.` → `127.0.0.1` (when matrix.gatewayHost set) - -`lib.unique` de-dupes if any sub-domain happens to equal another entry. Operators with real DNS leave it off. - -## Sub-domain shape (rationale) - -mara verdict at #749:9609 + #747:9722: sub-domain over sub-path for forge + matrix, sub-path for per-agent UIs. - -- forgejo's default `ROOT_URL = http:///` works without any `X-Forwarded-Prefix` gymnastics — sub-domain hosting is the canonical Forgejo deploy shape. -- matrix-spec deployments universally use `matrix.` for the actual API listener — federation already expects this. -- per-agent UIs are hyperhive-internal; iris's #731 made them base-path-aware specifically for `/agent//`. Sub-domain per agent would multiply DNS + TLS-per-subdomain cost without per-app config wins. -- cookie / storage isolation: a future forge XSS can't reach the dashboard session because they're different origins. - -`services.hyperhive.{forge.domain,matrix.gatewayHost}` take the full hostname (`forge.darkest.space`, `git.example.com`) rather than a label that gets concatenated with hive-domain — mara on #754:9684 wanted operator control over the full shape, not a forced `