- Move db/schema.sql to supabase/migrations/ as the first supabase CLI migration (manual `db push` only, no automated runner); re-add the gebos_ingest role + grants there since init.sql never re-runs - Add gebos-postgres-passwords oneshot on db-host: syncs role passwords from sops (LoadCredential, journal-safe), makes supabase_admin SUPERUSER and hands the auth schema to supabase_auth_admin to match the upstream supabase/postgres image; add pg_hba rule for 10.0.0.0/8 - Vendor the official docker-compose (studio/kong/auth/rest/meta only, external Postgres, loopback Studio with no Kong dashboard route) plus kong.yml (trimmed) and kong-entrypoint.sh (verbatim); tested: compose config, Kong config parse, migration applied on TimescaleDB pg17 - Document decisions as ADRs 0001-0004 (migrations, passwords, vendored stack, JWT API keys incl. verify/mint procedure) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.4 KiB
ADR-0003: Vendor a trimmed Supabase compose stack against external Postgres
Date: 2026-07-08 Status: Accepted
Context
The Supabase stack on app-host was a placeholder skeleton. The official
self-hosting bundle assumes its own bundled db container and ships nine+
services (realtime, storage, imgproxy, edge functions, supavisor pooler,
Logflare analytics, …), most of which the UVI pilot does not use. Meanwhile
our Postgres lives on a separate NixOS host (db-host) with TimescaleDB.
Kong deserves a note, since "why is it even there" came up: Kong is the
single front door for api.gebos.online (Caddy → Kong on loopback :8000).
It routes paths to internal services (/auth/v1 → GoTrue, /rest/v1 →
PostgREST) and enforces the perimeter (key-auth + ACLs), so unauthenticated
internet traffic never reaches the backends. Replacing it would mean
re-implementing routing/auth/CORS in Caddy by hand instead of inheriting
Supabase's tested config.
Decision
Vendor the upstream docker/docker-compose.yml (and kong.yml +
kong-entrypoint.sh) into nix/supabase/, keeping only
studio, kong, auth (GoTrue), rest (PostgREST), meta (postgres-meta), with
these deviations — each also documented in the files' header comments:
- No
dbservice. Everything connects to${POSTGRES_HOST}:${POSTGRES_PORT}(db-host);depends_on: dbdropped. - No realtime / storage / imgproxy / functions / supavisor / analytics. Re-vendor from upstream when actually needed.
- Studio binds to loopback only, and Kong's catch-all dashboard route is
removed. Upstream fronts Studio with Kong basic-auth on
/; we expose no route to it at all. Access isssh -L 3000:127.0.0.1:3000— possession of the SSH key is the credential.supabase_dashboard_passwordis therefore currently unused. The public API surface is exactly/auth/v1,/rest/v1,/graphql/v1and two.well-knownendpoints. - meta connects as
supabase_admin, notpostgres. Upstream'spostgresrole is its cluster superuser; on db-hostpostgreskeeps a separate admin password, sosupabase_admin(made SUPERUSER by ADR-0002) fills that role with the shared service password. kong-entrypoint.shis vendored byte-identical. Kong's declarative YAML cannot read env vars, so the entrypoint substitutes$VARS(the API keys) into the config at container start; keeping it unmodified makes re-vendoring a plain copy.
Variable layering (the answer to "where does POSTGRES_HOST come from"):
- non-secret deployment config (
POSTGRES_HOST/PORT/DB,STUDIO_BIND) — systemd unitenvironmentingebos-supabase.nix, fed by module options; - secrets (
POSTGRES_PASSWORD,JWT_SECRET,ANON_KEY,SERVICE_ROLE_KEY) — sops-renderedEnvironmentFile; - gebos constants (public URLs, org name) — hardcoded in the vendored compose.
Consequences
- Deliberately small attack surface and dependency set; Studio reachable only through SSH.
- Upstream updates are a re-copy plus re-applying the five listed deviations;
all drift is concentrated in
docker-compose.ymlandkong.ymlheaders. - GoTrue has no SMTP configured yet — magic-link login cannot send email
until the
SMTP_*secrets are added (TODO marked in the compose file). anon/authenticatedstill hold zero grants; PostgREST serves nothing until the RLS/grants migration lands (future ADR).