Skip to content

fix(supabase): upgrade database to Postgres 17 - #1068

Merged
Siumauricio merged 1 commit into
canaryfrom
fix/supabase-postgres17
Aug 6, 2026
Merged

fix(supabase): upgrade database to Postgres 17#1068
Siumauricio merged 1 commit into
canaryfrom
fix/supabase-postgres17

Conversation

@Siumauricio

Copy link
Copy Markdown
Contributor

Summary

Resolves the Postgres 17 / architecture parity request in #1067 by aligning the Supabase template with the current upstream self-hosted stack (supabase/supabase docker-compose.yml):

  • Database: supabase/postgres:17.6.1.136 — the exact image the official self-host compose ships today (the template's DB image now tracks upstream 1:1). A comment documents the major-upgrade caveat.
  • Studio: 2026.06.032026.08.03-sha-022b374.
  • Kong: 3.9.13.9.3.
  • Superuser removal parity (supabase discussion #46081): Studio now sets POSTGRES_USER_READ_WRITE: postgres and pg-meta connects as postgres instead of supabase_admin, matching upstream's move away from superuser access.
  • Removed analytics (Logflare) and vector: upstream removed both from the default self-hosted stack (logs are now an optional overlay). This drops 2 heavy containers, removes the docker.sock mount from the stack, and cuts boot time roughly in half (deploy completed in ~2 min vs ~4 min). Studio sets ENABLED_FEATURES_LOGS_ALL: "false" accordingly, and the unused LOGFLARE_* / DOCKER_SOCKET_LOCATION env vars and vector.yml mount were removed.
  • Smaller upstream alignments: GOTRUE_JWT_ISSUER, PostgREST healthcheck (postgrest --ready) + admin server, SUPABASE_PUBLISHABLE_KEY/SUPABASE_SECRET_KEY passthrough on Studio.

The Dokploy-specific hardening from #872/#961 (kong-entrypoint.sh with Lua key-mapping expressions, JWKS route, basic-auth-protected dashboard, MCP blocker, healthchecks) is preserved unchanged.

Migration note for existing installs

A Postgres major version upgrade is not in-place: an existing files/volumes/db/data directory initialized by Postgres 15 will not start on the Postgres 17 image. Existing deployments must either dump/restore (pg_dumpall on the old version, restore into a fresh volume) or start fresh. New installs from the template are unaffected. See https://github.com/orgs/supabase/discussions/46080.

Verification (deployed on a Dokploy instance)

  • 11/11 containers running (analytics/vector no longer present), deploy done in 125s
  • select version() via the /pg/ route (pg-meta as postgres user): PostgreSQL 17.6 on x86_64-pc-linux-gnu
  • Studio: HTTP 200 through Kong basic auth (redirect to /project/default)
  • GoTrue /auth/v1/health: 200 (v2.189.0)
  • PostgREST /rest/v1/: 200
  • Storage /storage/v1/version: 200
  • Realtime /realtime/v1/api/tenants/realtime-dev/health: 200, "healthy":true
  • node build-scripts/generate-meta.js --check: 506 templates validated

Closes #1067

🤖 Generated with Claude Code

Align the template with the current upstream self-hosted stack
(supabase/postgres 17.6.1.136, studio 2026.08.03, kong 3.9.3),
remove the deprecated analytics/vector services and switch
Studio/pg-meta to the postgres role per upstream guidance.

Closes #1067

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
built with Refined Cloudflare Pages Action

⚡ Cloudflare Pages Deployment

Name Status Preview Last Commit
templates ✅ Ready (View Log) Visit Preview 17a53fa

@Siumauricio
Siumauricio merged commit 8ad0f91 into canary Aug 6, 2026
4 checks passed
whollacsek added a commit to whollacsek/dokploy-templates that referenced this pull request Aug 6, 2026
The template has carried the plumbing for Supabase's new opaque API keys
since Dokploy#872 — kong-entrypoint.sh builds the Lua translation expressions and
kong.yml registers the keys as key-auth credentials — and Dokploy#1068 added the
studio/kong compose references while aligning with upstream.

But four of the variables that plumbing reads have never been declared in
template.toml, so they never reached the Environment tab:

  SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY,
  ANON_KEY_ASYMMETRIC, SERVICE_ROLE_KEY_ASYMMETRIC

kong-entrypoint.sh gates on the first two being non-empty, so every deploy
silently took the legacy-only branch and users had no field to fill in.

Generate them from [variables] instead:

- SUPABASE_PUBLISHABLE_KEY / SUPABASE_SECRET_KEY as opaque sb_* strings
- ANON_KEY / SERVICE_ROLE_KEY move to [variables] so ANON_KEY_ASYMMETRIC
  and SERVICE_ROLE_KEY_ASYMMETRIC can reuse the same JWT

Kong substitutes whatever token those hold and every backend already
verifies HS256 with JWT_SECRET, so the opaque keys work without an EC
keypair (which the dokploy helpers cannot generate). Clients still only
ever hold an opaque string. JWT_KEYS / JWT_JWKS stay empty as a
documented opt-in for real ES256.

Also fixed while in here:

- JWT_JWKS was missing entirely. GOTRUE_JWT_KEYS was already enabled, so
  anyone setting a real JWKS got Auth signing ES256 tokens that PostgREST,
  Storage, Realtime and Functions had no way to verify. Wire it into all
  four verifiers.
- Restore two routes kong.yml dropped: /realtime/v1/api/tenants and
  /realtime/v1/api/openapi were reachable with the anon key, and the
  PostgREST OpenAPI root at /rest/v1/ was anon-readable (supabase#42949).
  Needs KONG_ROUTER_FLAVOR: expressions, as upstream sets.
- graphql-v1 had key-auth hide_credentials: true. key-auth runs before
  request-transformer, so the apikey header was stripped before the Lua
  expression could read it and service_role GraphQL requests were
  silently downgraded to anon.
- DB_ENC_KEY was hardcoded to the well-known "supabaserealtime" default;
  generate REALTIME_DB_ENC_KEY instead.
- functions/main/index.ts was the old remote-JWKS version pinned to
  deno.land/x/jose@4.14.4; sync with upstream (jsr:@panva/jose@6 and
  local SUPABASE_JWKS).

Verified against all 11 services running locally: an RLS-protected table
confirms anon and publishable keys are blocked while service_role and
secret keys read the row, so the opaque keys really are translated and
not downgraded. Storage and Realtime still verify HS256 with JWT_JWKS
empty. 21/22 end-to-end checks pass; the last was the test not following
Studio's redirect.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Siumauricio pushed a commit that referenced this pull request Aug 7, 2026
#1069)

* fix(supabase): generate the new API keys and wire up JWKS verification

The template has carried the plumbing for Supabase's new opaque API keys
since #872 — kong-entrypoint.sh builds the Lua translation expressions and
kong.yml registers the keys as key-auth credentials — and #1068 added the
studio/kong compose references while aligning with upstream.

But four of the variables that plumbing reads have never been declared in
template.toml, so they never reached the Environment tab:

  SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY,
  ANON_KEY_ASYMMETRIC, SERVICE_ROLE_KEY_ASYMMETRIC

kong-entrypoint.sh gates on the first two being non-empty, so every deploy
silently took the legacy-only branch and users had no field to fill in.

Generate them from [variables] instead:

- SUPABASE_PUBLISHABLE_KEY / SUPABASE_SECRET_KEY as opaque sb_* strings
- ANON_KEY / SERVICE_ROLE_KEY move to [variables] so ANON_KEY_ASYMMETRIC
  and SERVICE_ROLE_KEY_ASYMMETRIC can reuse the same JWT

Kong substitutes whatever token those hold and every backend already
verifies HS256 with JWT_SECRET, so the opaque keys work without an EC
keypair (which the dokploy helpers cannot generate). Clients still only
ever hold an opaque string. JWT_KEYS / JWT_JWKS stay empty as a
documented opt-in for real ES256.

Also fixed while in here:

- JWT_JWKS was missing entirely. GOTRUE_JWT_KEYS was already enabled, so
  anyone setting a real JWKS got Auth signing ES256 tokens that PostgREST,
  Storage, Realtime and Functions had no way to verify. Wire it into all
  four verifiers.
- Restore two routes kong.yml dropped: /realtime/v1/api/tenants and
  /realtime/v1/api/openapi were reachable with the anon key, and the
  PostgREST OpenAPI root at /rest/v1/ was anon-readable (supabase#42949).
  Needs KONG_ROUTER_FLAVOR: expressions, as upstream sets.
- graphql-v1 had key-auth hide_credentials: true. key-auth runs before
  request-transformer, so the apikey header was stripped before the Lua
  expression could read it and service_role GraphQL requests were
  silently downgraded to anon.
- DB_ENC_KEY was hardcoded to the well-known "supabaserealtime" default;
  generate REALTIME_DB_ENC_KEY instead.
- functions/main/index.ts was the old remote-JWKS version pinned to
  deno.land/x/jose@4.14.4; sync with upstream (jsr:@panva/jose@6 and
  local SUPABASE_JWKS).

Verified against all 11 services running locally: an RLS-protected table
confirms anon and publishable keys are blocked while service_role and
secret keys read the row, so the opaque keys really are translated and
not downgraded. Storage and Realtime still verify HS256 with JWT_JWKS
empty. 21/22 end-to-end checks pass; the last was the test not following
Studio's redirect.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(supabase): match dokploy hash helper semantics (length = chars, not bytes)

Dokploy's generateHash(length) returns exactly `length` hex characters,
not `length` random bytes hex-encoded. Realtime requires DB_ENC_KEY to be
exactly 16 characters (AES-128), so ${hash:8} produced an 8-char key and
the realtime container crash-looped. Bump to ${hash:16}, and bump the
opaque API key segments to ${hash:22}/${hash:8} to match the intended
sb_<role>_<22>_<8> shape.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Supabase template should be using Postgres 17

1 participant