# API gateway The `monitor` Go binary (port 3001) is also a reverse-proxy gateway. HF exposes only one public port, so all three backend APIs are reached under one base URL by path prefix. ## Routing (`monitor/main.go`) | Public prefix | → forwards to | Prefix stripped | |---------------|---------------|-----------------| | `/gpt/…` | `127.0.0.1:9225` | `/gpt/api/chat` → `/api/chat` | | `/gemini/…` | `127.0.0.1:8000` | `/gemini/chat` → `/chat` | | `/flow/…` | `127.0.0.1:8101` | `/flow/generate/video` → `/generate/video` | `gatewayHandler(prefix, target)` builds one `httputil.ReverseProxy` whose `Director` rewrites the host and strips the prefix. The monitor's own routes (`/`, `/api/*`, `/chrome.log`) are untouched. ## Auth — `API_KEY` (fail-closed) `authOK()` gates the three prefixes: - Reads `API_KEY` from env once at startup. - Requires `Authorization: Bearer ` (also accepts `?key=`). - **Unset `API_KEY` → every gateway call returns `503`** (so accounts are never accidentally open). - Wrong/missing key → `401`. - The monitor UI stays open (no key) so the live view keeps working. Set it: HF secret `API_KEY` (Settings) or Docker `.env` `API_KEY=…`. Use a long random string, e.g. `openssl rand -hex 24`. ## Why not a separate Space for the servers? The extensions dial `ws://127.0.0.1:9225/9226/9227` — hardcoded localhost (`*/background.js`). A second Space is a different machine with a different `127.0.0.1`, so its servers could never receive the extension connections. Hence: one container, gateway out front. ## Adding a new route 1. Server listens on a new localhost port inside the container. 2. Launch it in `start_hf.sh` (step 6a). 3. Add `http.HandleFunc("/x/", gatewayHandler("/x", "http://127.0.0.1:PORT"))` in `monitor/main.go`.