docs(deploy): runbook + fixes from the limonia.net cutover
Document what we learned doing the real NetBird+Traefik migration: - Keycloak realm/client names are operator-chosen; the realm-export.json's literal "colectivo-web" / "colectivo" values are illustrative, not required. - Legacy Keycloak /auth/ base path: PUBLIC_KEYCLOAK_URL must include the suffix when the deployment serves realms under /auth/realms/... (hit this on auth.fosil.eu). Verify with the discovery URL returning 200. - NetBird's installer deploys Traefik with idleTimeout=0 (unlimited) by default — verify instead of prescribing 3600s. - Runbook: --no-cache fixes the intermittent vite SSR "transforming..." hang that surfaces as a PostHog shutdown timeout. - Runbook: any PUBLIC_* change needs an app rebuild (build args); secret changes only need `docker compose restart auth`. - Runbook: TRUNCATE recipe for wiping all app + auth data while keeping schema + migration tracking intact. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -166,14 +166,15 @@ Defined in `keycloak/realm-export.json` and `supabase/seed.sql`. All use passwor
|
||||
- Test the shopping session mode on a real iPhone during development, not only in DevTools.
|
||||
|
||||
**Traefik (prod) — WebSocket for Realtime:**
|
||||
- Traefik routes `Host(erosi.limonia.net) && PathPrefix(/rest/v1, /auth/v1, /realtime/v1, ...)` to Kong via Docker-provider labels (priority 100); everything else on the same host falls through to the SvelteKit app (priority 1). Routing lives on the `kong` and `app` services' `labels:` block in `infra/docker-compose.erosi.yml` — no Traefik config files.
|
||||
- The HTTPS entrypoint must set `--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=3600s` in Traefik's static config (NetBird-managed container — edit once when setting up). Default is ~180s; without the bump, Realtime WebSockets drop mid-shopping-session and the client reconnects continuously.
|
||||
- Traefik routes `Host(erosi.limonia.net) && PathPrefix(/rest/v1, /auth/v1, /realtime/v1, ...)` to Kong via Docker-provider labels (priority 100); everything else on the same host falls through to the SvelteKit app (priority 1). Routing lives on the `kong` and `app` services' `labels:` block in `infra/docker-compose.erosi.yml` — no Traefik config files. NetBird's self-hosted installer (≥ v0.65) deploys Traefik with `--providers.docker=true` + `--providers.docker.exposedByDefault=false`, so our labeled services are auto-discovered on the `netbird_netbird` Docker network.
|
||||
- The HTTPS entrypoint needs `respondingTimeouts.idleTimeout` set to either `0` (unlimited, NetBird's default) or `≥3600s`. At the default ~180s, Realtime WebSockets drop mid-shopping-session and the client reconnects continuously. Verify with `docker inspect netbird-traefik --format '{{range .Args}}{{.}}{{"\n"}}{{end}}' | grep idleTimeout`.
|
||||
- Traefik auto-sets `X-Forwarded-{Proto,Host,Port,For}` when `tls.certresolver` is configured on the router, so no extra middleware is needed for the app.
|
||||
- CSP `connect-src` must include both `https://erosi.limonia.net` and `wss://erosi.limonia.net`.
|
||||
|
||||
**External Keycloak:**
|
||||
- Keycloak runs outside this stack; `PUBLIC_KEYCLOAK_URL` in `.env` points at it. Whatever proxy sits in front of it must forward `X-Forwarded-{Host,Port,Proto}` or Keycloak builds redirect URIs with internal ports and the OIDC flow breaks — that's the external operator's concern, not ours.
|
||||
- The realm + client configuration required on the external Keycloak is documented in `docs/deployment.md` and mirrored in `keycloak/realm-export.erosi.json` (kept as reference; not imported by this stack).
|
||||
- The realm + client configuration required on the external Keycloak is documented in `docs/deployment.md` and mirrored in `keycloak/realm-export.erosi.json` (kept as reference; not imported by this stack). Realm name, client id, and client secret are operator-chosen and wired in via `.env` — the file's literal `colectivo-web` / `colectivo` values are illustrative, not required.
|
||||
- **Legacy Keycloak `/auth/` base path**: Keycloak ≤ 16 (and some later distributions) serve realms under `/auth/realms/...` instead of `/realms/...`. In that case `PUBLIC_KEYCLOAK_URL` must include the suffix, e.g. `https://auth.example.com/auth`. Symptom of a missing `/auth` suffix: `GOTRUE_EXTERNAL_KEYCLOAK_URL/...well-known/openid-configuration` returns 404; the Supabase login redirect lands on a Keycloak error page. Verify before deploying: `curl -I ${PUBLIC_KEYCLOAK_URL}/realms/${PUBLIC_KEYCLOAK_REALM}/.well-known/openid-configuration` must return 200.
|
||||
|
||||
**Supabase Realtime self-hosted:**
|
||||
- Check `MAX_REPLICATION_SLOTS` in PostgreSQL and `REALTIME_MAX_CONNECTIONS` before going to production.
|
||||
|
||||
Reference in New Issue
Block a user