Self-hosting Supabase in a Proxmox LXC
What you get: a full self-hosted Supabase stack — Postgres, Auth (GoTrue), REST (PostgREST), Realtime, Storage, Studio, Edge Functions, the Kong gateway and the Supavisor pooler — running in a single lightweight Proxmox container, behind your reverse proxy, for dev/experimentation. Footprint is small: the whole stack idles around ~1.3 GB RAM.
This guide also covers the thing that trips people up in 2026: Supabase’s new asymmetric (ES256) JWT + opaque API keys, and how to enable them without breaking existing clients.
1. Create the container (unprivileged Docker LXC)
An unprivileged LXC with nesting is fine for Docker and is the safer default:
# on the PVE host, adjust storage/IP
pct create 101 local:vztmpl/debian-12-standard_*.tar.zst \
--hostname supabase --cores 4 --memory 6144 --rootfs local-lvm:40 \
--net0 name=eth0,bridge=vmbr0,ip=192.168.15.160/24,gw=192.168.15.1 \
--features nesting=1,keyctl=1 --unprivileged 1 --onboot 1
pct start 101
pct exec 101 -- bash -c 'apt-get update && apt-get install -y ca-certificates curl git && \
curl -fsSL https://get.docker.com | sh'
2. Pull + configure the stack
pct exec 101 -- bash
git clone --depth 1 https://github.com/supabase/supabase /opt/supabase
cd /opt/supabase/docker
cp .env.example .env
Edit .env — the essentials: POSTGRES_PASSWORD, JWT_SECRET, DASHBOARD_USERNAME/DASHBOARD_PASSWORD (Studio
is behind Kong basic-auth), and set the public URLs to your domain:
SITE_URL=https://supabase.example.com
API_EXTERNAL_URL=https://supabase.example.com
SUPABASE_PUBLIC_URL=https://supabase.example.com
Modern Supabase dropped the old analytics/Logflare + vector services, so there’s nothing heavy to trim anymore — just bring the compose up as-is.
docker compose up -d
docker compose ps # db, kong, auth, rest, realtime, storage, studio, meta, supavisor, edge-functions...
3. Reverse-proxy it (front door = Kong on :8000)
Point your proxy at the Kong gateway (CONTAINER_IP:8000) — that’s the single entry for the REST/Auth/Storage
APIs and Studio. Example intent (Traefik or nginx): supabase.example.com → http://192.168.15.160:8000, TLS at
the edge, and (recommended for a homelab) restrict it to LAN-only. Add a local DNS record so the hostname
resolves internally. Studio’s root returns a 307 → /project/default once authenticated — that’s normal.
4. The 2026 gotcha — turn on ES256 asymmetric keys
Supabase is moving from legacy symmetric-only JWTs (the classic anon/service_role keys) to asymmetric
ES256 signing + opaque API keys (sb_publishable_… and sb_secret_…). The legacy keys are deprecated end-2026,
so enable the new system now. Supabase ships a helper that does it non-breakingly:
cd /opt/supabase
./utils/add-new-auth-keys.sh --update-env
docker compose up -d
What it does: populates JWT_KEYS / JWT_JWKS, adds SUPABASE_PUBLISHABLE_KEY (anon) and SUPABASE_SECRET_KEY
(service_role) plus the *_KEY_ASYMMETRIC variants, and uncomments GOTRUE_JWT_KEYS in the compose. Because the
published JWKS still includes your legacy symmetric key, old anon/service_role tokens keep verifying — so
nothing breaks. (Verify: hit /rest/v1/ with the old anon key and the new publishable key — both should return
200.) Rotate the opaque keys later with ./utils/rotate-new-api-keys.sh.
Store the secrets properly: POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, the new
publishable/secret keys, SECRET_KEY_BASE, VAULT_ENC_KEY — into your password manager, not git. The operational
copy lives only in the container’s /opt/supabase/docker/.env (gitignored).
Gotchas recap
- Unprivileged LXC +
nesting=1,keyctl=1— Docker + Supabase run fine; no need for a privileged container. - Proxy to Kong
:8000, not the individual services — Kong is the gateway for everything incl. Studio. - Enable the ES256 key system now with
add-new-auth-keys.sh --update-env— it’s non-breaking and future-proofs you before the end-2026 legacy-key deprecation. - LAN-only unless you really need it public — Studio + the service_role key are powerful; don’t expose them to the internet without an auth gate in front.
Written from a working dev deployment: Supabase in an unprivileged Docker LXC on a Proxmox node (Postgres 17 + Kong), LAN-only behind Traefik, migrated to the ES256 publishable/secret key system. Adjust IPs/domain/versions to your setup.
Written by James Brooks — I run ThatNerdKnows (IT support + websites for small businesses). This is the deep end; if you’d rather just have it handled, that’s the day job.