Files
Lars Nolden 2ce68cb098
deploy / deploy (push) Successful in 5m57s
check / flake-check (push) Failing after 35m52s
Wire schema v1 into a manual Supabase migration and vendor the real stack
- 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>
2026-07-08 22:33:50 +02:00

3.2 KiB

Supabase compose stack

Vendored from the official self-hosting bundle (docker/docker-compose.yml in supabase/supabase), with deliberate changes:

  1. No db service. Every service reads POSTGRES_HOST / POSTGRES_PORT from the environment and connects to the external db-host. The systemd unit (nix/modules/gebos-supabase.nix) injects these; secrets come from the sops-rendered env file (see gebos-secrets.nix).

  2. Only auth + rest + studio (+ kong, meta). Realtime, storage, imgproxy, edge functions, supavisor and the Logflare analytics stack are not vendored — re-add from upstream when actually needed.

  3. Studio is bound to 127.0.0.1 only, with no Kong dashboard route. Upstream protects Studio with Kong basic-auth on a catch-all / route; we drop that route entirely (kong.yml here), so there is no public route to Studio and the api.gebos.online surface is only /auth/v1, /rest/v1, /graphql/v1 and the two .well-known endpoints. To use Studio:

    ssh -L 3000:127.0.0.1:3000 deploy@app.gebos.online
    open http://localhost:3000
    

    Studio itself has no login in this topology — possession of the SSH key is the credential. (supabase_dashboard_password in secrets.yaml is currently unused; it becomes relevant only if Studio ever gets fronted by basic auth again.)

  4. meta connects as supabase_admin, not postgres. In the upstream image postgres/supabase_admin is the superuser; on db-host the postgres superuser keeps its own password (postgres_admin_password), and the gebos-postgres-passwords oneshot makes supabase_admin SUPERUSER with the shared POSTGRES_PASSWORD to match upstream semantics.

What's in here

  • docker-compose.yml — the stack itself
  • init.sql — Supabase schemas, roles, and extensions Postgres needs before the compose services come up. Runs once at first initdb via nix/modules/gebos-postgres.nix. Application schema lives in supabase/migrations/ (applied manually — see supabase/README.md).
  • kong.yml — Kong's declarative routing, trimmed to the services we run
  • kong-entrypoint.sh — upstream helper, verbatim: substitutes $VARS into kong.yml (Kong has no native env interpolation) and builds the request-transformer Lua expressions

Passwords

No service role has a password in any SQL file. The gebos-postgres-passwords oneshot on db-host (see gebos-postgres.nix) syncs them from sops on every boot/deploy:

role secret
postgres postgres_admin_password
supabase_admin, supabase_auth_admin, authenticator supabase_postgres_password (= POSTGRES_PASSWORD in the compose env)
gebos_ingest ingester_postgres_password

Updating the vendored compose

When upstream ships a new layout, re-vendor by copying the upstream files and re-applying the deviations listed at the top of docker-compose.yml and kong.yml (both carry the list in their header comments). Then commit, deploy, and smoke-test Studio through the SSH tunnel.