Docker Compose Reference: Supabase Self-Hosted

Type: Software Reference Confidence: 0.93 Sources: 7 Verified: 2026-02-27 Freshness: 2026-02-27

TL;DR

Constraints

Quick Reference

Service Architecture

ServiceImagePortsVolumesKey Env
db (PostgreSQL)supabase/postgres:15.8.1.0855432volumes/db/dataPOSTGRES_PASSWORD
kong (API Gateway)kong:2.8.18000, 8443volumes/api/kong.ymlDASHBOARD_USERNAME, DASHBOARD_PASSWORD
auth (GoTrue)supabase/gotrue:v2.186.0Internal onlyNoneGOTRUE_JWT_SECRET, GOTRUE_DB_DATABASE_URL
rest (PostgREST)postgrest/postgrest:v14.5Internal onlyNonePGRST_DB_URI, PGRST_JWT_SECRET
realtimesupabase/realtime:v2.76.54000 (internal)NoneSECRET_KEY_BASE, DB_HOST
storagesupabase/storage-api:v1.37.85000 (internal)volumes/storageSTORAGE_BACKEND, FILE_SIZE_LIMIT
imgproxydarthsim/imgproxy:v3.30.15001 (internal)volumes/storage (read)IMGPROXY_ENABLE_WEBP_DETECTION
studio (Dashboard)supabase/studio:2026.02.16Internal onlyNoneSTUDIO_DEFAULT_ORGANIZATION
meta (pg_meta)supabase/postgres-meta:v0.95.28080 (internal)NonePG_META_DB_HOST
functions (Edge)supabase/edge-runtime:v1.70.3Internal onlyvolumes/functionsSUPABASE_URL, SUPABASE_ANON_KEY
analytics (Logflare)supabase/logflare:1.31.24000 (internal)NoneLOGFLARE_API_KEY
vector (Logging)timberio/vector:0.53.0-alpine9001volumes/logs/vector.ymlVector pipeline config
supavisor (Pooler)supabase/supavisor:2.7.45432, 6543volumes/pooler.exsPOOLER_TENANT_ID, SECRET_KEY_BASE

Key Environment Variables

VariablePurposeRequirements
POSTGRES_PASSWORDDatabase superuser passwordLetters and numbers only
JWT_SECRETSigns and verifies all JWTsShared across auth, rest, realtime, kong
ANON_KEYClient-side API key (anon role)Generated from JWT_SECRET
SERVICE_ROLE_KEYServer-side API key (full access)Never expose publicly
SECRET_KEY_BASEEncrypts Realtime + Supavisor sessionsMinimum 64 characters
VAULT_ENC_KEYConfiguration encryptionExactly 32 characters
DASHBOARD_USERNAMEStudio HTTP basic auth usernameDefault: supabase
DASHBOARD_PASSWORDStudio HTTP basic auth passwordMust contain letters

Service Endpoints (via Kong on port 8000)

EndpointServiceDescription
/rest/v1/PostgRESTAuto-generated REST API from PostgreSQL schema
/auth/v1/GoTrueAuthentication (signup, login, OAuth, JWT refresh)
/realtime/v1/RealtimeWebSocket subscriptions to database changes
/storage/v1/Storage APIFile upload, download, and management
/functions/v1/Edge RuntimeServerless Deno functions
/ (Studio)StudioWeb dashboard for database management

Decision Tree

START: What is your deployment scenario?
├── Local development only?
│   ├── YES → Use default ports, skip SSL. Consider Supabase CLI instead.
│   └── NO ↓
├── Single server / VPS?
│   ├── YES → Full docker-compose + reverse proxy (Nginx/Traefik) + SSL certs
│   └── NO ↓
├── Need to reduce resource usage?
│   ├── YES → Remove optional services: analytics, imgproxy, functions, vector
│   └── NO ↓
├── Need external S3 storage?
│   ├── YES → Set STORAGE_BACKEND=s3 + S3 credentials in .env
│   └── NO ↓
├── Production with high availability?
│   ├── YES → Consider Supabase on Kubernetes or managed Supabase Cloud
│   └── NO ↓
└── DEFAULT → Full stack docker-compose with all services enabled

Step-by-Step Guide

1. Clone and prepare the project directory

Clone the Supabase repository and copy the Docker configuration files to your project directory. [src1]

# Clone the repository (shallow clone for speed)
git clone --depth 1 https://github.com/supabase/supabase

# Create your project directory and copy Docker files
mkdir supabase-project
cp -rf supabase/docker/* supabase-project/
cp supabase/docker/.env.example supabase-project/.env
cd supabase-project

Verify: ls -la .env docker-compose.yml → both files should exist in the project directory.

2. Generate and configure secrets

Never use the default placeholder values. Generate unique secrets for all sensitive environment variables. [src1]

# Generate all secrets automatically
sh ./utils/generate-keys.sh

# Or generate manually with openssl:
openssl rand -base64 32  # JWT_SECRET

Verify: grep -c 'your-super-secret' .env → should return 0 (no placeholder values remain).

3. Pull images and start services

Pull the latest images and start all services in detached mode. [src2]

docker compose pull
docker compose up -d
docker compose ps

Verify: docker compose ps → all services should show Up (healthy).

4. Access and verify services

Once all services are healthy, verify each endpoint through the Kong gateway. [src1]

# Test Auth API health
curl -s http://localhost:8000/auth/v1/health
# Expected: {"status":"ok"}

Verify: curl -s http://localhost:8000/auth/v1/health{"status":"ok"}.

5. Connect client SDK

Initialize the Supabase client SDK pointing to your self-hosted instance. [src1]

import { createClient } from '@supabase/supabase-js'  // ^2.39.0
const supabase = createClient(
  'http://localhost:8000',  // Kong gateway URL
  'your-anon-key-here'     // ANON_KEY from .env
)

Verify: Client connects without JWT or network errors.

6. Configure reverse proxy for production

For production, place Nginx or Traefik in front of Kong to handle SSL termination. [src7]

# Nginx config with WebSocket support for Realtime
location /realtime/v1/ {
    proxy_pass http://localhost:8000/realtime/v1/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

Verify: curl -s https://supabase.yourdomain.com/auth/v1/health{"status":"ok"} over HTTPS.

Code Examples

Docker Compose: Minimal Core Services

# docker-compose.override.yml -- Disable optional services to save resources
services:
  analytics:
    profiles: ["disabled"]
  vector:
    profiles: ["disabled"]
  imgproxy:
    profiles: ["disabled"]
  functions:
    profiles: ["disabled"]

Bash: Automated Backup Script

#!/bin/bash
# Backup PostgreSQL from the db container
BACKUP_DIR="./backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
docker compose exec -T db pg_dump \
  -U postgres --clean --if-exists --no-owner \
  postgres > "${BACKUP_DIR}/supabase_${TIMESTAMP}.sql"
echo "Backup: ${BACKUP_DIR}/supabase_${TIMESTAMP}.sql"

JavaScript: Health Check All Services

const BASE = process.env.SUPABASE_URL || 'http://localhost:8000';
const KEY = process.env.SUPABASE_ANON_KEY;
const endpoints = [
  { name: 'Auth',    path: '/auth/v1/health' },
  { name: 'REST',    path: '/rest/v1/', headers: { apikey: KEY } },
  { name: 'Storage', path: '/storage/v1/status' },
];
for (const ep of endpoints) {
  const res = await fetch(`${BASE}${ep.path}`, { headers: ep.headers });
  console.log(`${ep.name}: ${res.ok ? 'OK' : 'FAIL'} (${res.status})`);
}

Python: Connect to Self-Hosted Supabase

from supabase import create_client  # supabase>=2.0.0

supabase = create_client(
    "http://localhost:8000",
    "your-anon-key-here"
)
result = supabase.table("users").select("*").limit(1).execute()
print(f"Connected: {len(result.data)} rows")

Anti-Patterns

Wrong: Starting with default secrets

# BAD -- .env.example has publicly known placeholder values
cp .env.example .env
docker compose up -d
# Anyone who reads the Supabase repo now has your JWT_SECRET

Correct: Generate unique secrets before first boot

# GOOD -- generate unique secrets before starting
cp .env.example .env
sh ./utils/generate-keys.sh
docker compose up -d

Wrong: Exposing service ports directly

# BAD -- exposing internal service ports
services:
  rest:
    ports: ["3000:3000"]
  auth:
    ports: ["9999:9999"]
  db:
    ports: ["5432:5432"]

Correct: Route all traffic through Kong

# GOOD -- only Kong is exposed
services:
  kong:
    ports:
      - "${KONG_HTTP_PORT:-8000}:8000/tcp"
      - "${KONG_HTTPS_PORT:-8443}:8443/tcp"

Wrong: Special characters in POSTGRES_PASSWORD

# BAD -- special characters break connection string parsing
POSTGRES_PASSWORD=p@ss!w0rd#2026

Correct: Alphanumeric passwords only

# GOOD -- letters and numbers only
POSTGRES_PASSWORD=SuperSecure2026RandomString

Wrong: Using docker compose down -v to "restart"

# BAD -- -v removes all volumes including database data
docker compose down -v  # ALL DATA IS NOW GONE

Correct: Restart without removing volumes

# GOOD -- restart without touching data
docker compose down
docker compose up -d

Common Pitfalls

Diagnostic Commands

# Check health of all services
docker compose ps

# View logs for a specific service
docker compose logs --tail 100 auth

# Check if PostgreSQL is accepting connections
docker compose exec db pg_isready -U postgres

# Verify JWT_SECRET consistency across services
docker compose exec auth printenv | grep JWT
docker compose exec rest printenv | grep JWT

# Test Kong routing to auth service
curl -v http://localhost:8000/auth/v1/health

# Monitor real-time resource usage
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

# Check Kong declarative config
docker compose exec kong kong config parse /var/lib/kong/kong.yml

# Verify database extensions
docker compose exec db psql -U postgres -c "SELECT * FROM pg_extension;"

Version History & Compatibility

ComponentCurrent VersionImageKey Change
PostgreSQL15.8.1supabase/postgres:15.8.1.085Includes pg_net, pg_graphql, pgvector extensions
GoTrue (Auth)v2.186.0supabase/gotrue:v2.186.0PKCE flow, anonymous auth, SSO/SAML support
PostgRESTv14.5postgrest/postgrest:v14.5Improved aggregate functions, spreads
Realtimev2.76.5supabase/realtime:v2.76.5Broadcast, Presence, Postgres Changes
Storage APIv1.37.8supabase/storage-api:v1.37.8S3-compatible backend, resumable uploads
Kong2.8.1kong:2.8.1Pinned version; declarative config via kong.yml
Studio2026.02supabase/studio:2026.02.16SQL editor, table editor, auth UI
Edge Runtimev1.70.3supabase/edge-runtime:v1.70.3Deno-based functions, npm compatibility
Supavisor2.7.4supabase/supavisor:2.7.4Replaced PgBouncer; session + transaction modes
imgproxyv3.30.1darthsim/imgproxy:v3.30.1WebP/AVIF auto-detection
Vector0.53.0timberio/vector:0.53.0-alpineLog aggregation pipeline
Logflare1.31.2supabase/logflare:1.31.2Analytics and log querying
pg_metav0.95.2supabase/postgres-meta:v0.95.2Database introspection for Studio

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Need full control over data residency and complianceQuick prototyping or MVP with small teamSupabase Cloud (free tier available)
Deploying in air-gapped or restricted networksBudget under $20/month for infrastructureSupabase Cloud Pro plan
Custom PostgreSQL extensions or configurations neededNo DevOps expertise on the teamSupabase Cloud or managed hosting
Cost optimization at scale (many projects, high traffic)Need automatic updates and zero maintenanceSupabase Cloud with automatic upgrades
Regulatory requirement for on-premises hostingSingle developer with limited timeSupabase Cloud + CLI for local dev

Important Caveats

Related Units