fix(supabase): upgrade database to Postgres 17 - #1068
Merged
Conversation
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>
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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):
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.2026.06.03→2026.08.03-sha-022b374.3.9.1→3.9.3.POSTGRES_USER_READ_WRITE: postgresand pg-meta connects aspostgresinstead ofsupabase_admin, matching upstream's move away from superuser access.analytics(Logflare) andvector: upstream removed both from the default self-hosted stack (logs are now an optional overlay). This drops 2 heavy containers, removes thedocker.sockmount from the stack, and cuts boot time roughly in half (deploy completed in ~2 min vs ~4 min). Studio setsENABLED_FEATURES_LOGS_ALL: "false"accordingly, and the unusedLOGFLARE_*/DOCKER_SOCKET_LOCATIONenv vars andvector.ymlmount were removed.GOTRUE_JWT_ISSUER, PostgREST healthcheck (postgrest --ready) + admin server,SUPABASE_PUBLISHABLE_KEY/SUPABASE_SECRET_KEYpassthrough 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/datadirectory initialized by Postgres 15 will not start on the Postgres 17 image. Existing deployments must either dump/restore (pg_dumpallon 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)
select version()via the/pg/route (pg-meta aspostgresuser):PostgreSQL 17.6 on x86_64-pc-linux-gnu/project/default)/auth/v1/health: 200 (v2.189.0)/rest/v1/: 200/storage/v1/version: 200/realtime/v1/api/tenants/realtime-dev/health: 200,"healthy":truenode build-scripts/generate-meta.js --check: 506 templates validatedCloses #1067
🤖 Generated with Claude Code