Self-Hosting Supabase
Supabase is fully open source, meaning you can deploy it on your own infrastructure for complete control over your data, compliance requirements, or cost optimization at scale. This guide covers Docker Compose deployment, required services, configuration, and production considerations.
🚀 When to Self-Host
- Data sovereignty: Keep data in specific regions or on-premises
- Compliance: Meet HIPAA, SOC2, or other regulatory requirements
- Cost optimization: Lower costs at very high scale
- Customization: Modify Supabase services to your needs
Architecture Overview
Supabase Self-Hosted Architecture:
┌─────────────────────────────────────────────┐
│ Kong (API Gateway) │
├─────────────┬──────────┬───────────┬────────┤
│ PostgREST │ GoTrue │ Realtime │Storage │
│ (REST API) │ (Auth) │(WebSocket)│ (S3) │
├─────────────┴──────────┴───────────┴────────┤
│ PostgreSQL Database │
│ (with extensions & migrations) │
└──────────────────────────────────────────────┘
Services:
• PostgreSQL — Core database
• PostgREST — Auto-generated REST API
• GoTrue — Authentication & JWT issuing
• Realtime — WebSocket server for subscriptions
• Storage API — File storage with S3 backend
• Kong — API gateway & routing
• Studio — Dashboard UI (optional)
• Meta — Database metadata API
Docker Compose Setup
# Clone the Supabase repository
git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
# Copy the example environment file
cp .env.example .env
# IMPORTANT: Update these values in .env
# - POSTGRES_PASSWORD (strong random password)
# - JWT_SECRET (min 32 characters, generate with: openssl rand -base64 32)
# - ANON_KEY (generate at https://supabase.com/docs/guides/self-hosting#api-keys)
# - SERVICE_ROLE_KEY (generate similarly)
# - DASHBOARD_USERNAME and DASHBOARD_PASSWORD
# Start all services
docker compose up -d
# Check that all services are running
docker compose ps
# Access:
# Studio: http://localhost:8000
# API: http://localhost:8000/rest/v1
# Auth: http://localhost:8000/auth/v1
# Storage: http://localhost:8000/storage/v1
Essential Configuration
# .env — Critical security settings
############
# Secrets
############
POSTGRES_PASSWORD=your-super-secret-password
JWT_SECRET=your-jwt-secret-at-least-32-characters-long
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
############
# Auth (GoTrue)
############
GOTRUE_SITE_URL=https://your-app.com
GOTRUE_URI_ALLOW_LIST=https://your-app.com/*
GOTRUE_SMTP_HOST=smtp.sendgrid.net
GOTRUE_SMTP_PORT=587
GOTRUE_SMTP_USER=apikey
GOTRUE_SMTP_PASS=your-sendgrid-api-key
GOTRUE_SMTP_SENDER_NAME=Your App
############
# Storage
############
STORAGE_BACKEND=s3 # or 'file' for local storage
GLOBAL_S3_BUCKET=your-storage-bucket
AWS_ACCESS_KEY_ID=your-key
AWS_SECRET_ACCESS_KEY=your-secret
AWS_DEFAULT_REGION=us-east-1
SSL/TLS with Reverse Proxy
# nginx.conf — Reverse proxy with SSL
server {
listen 443 ssl http2;
server_name supabase.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/supabase.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/supabase.yourdomain.com/privkey.pem;
# API and Auth
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# WebSocket for Realtime
location /realtime/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
Backup Strategies
# Automated daily backup with pg_dump
#!/bin/bash
# backup.sh — run via cron: 0 2 * * * /path/to/backup.sh
BACKUP_DIR="/backups/supabase"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
FILENAME="supabase_backup_${TIMESTAMP}.sql.gz"
# Dump and compress
docker exec supabase-db pg_dump -U postgres \
--clean --if-exists \
| gzip > "${BACKUP_DIR}/${FILENAME}"
# Upload to S3 (optional)
aws s3 cp "${BACKUP_DIR}/${FILENAME}" \
"s3://your-backup-bucket/supabase/${FILENAME}"
# Keep only last 30 days locally
find "${BACKUP_DIR}" -name "*.sql.gz" -mtime +30 -delete
echo "Backup completed: ${FILENAME}"
⚠️ Self-Hosting Considerations
Self-hosting means you are responsible for security updates, backups, monitoring, and scaling. The managed Supabase platform handles all of this for you. Only self-host if you have a strong reason (compliance, scale) and dedicated DevOps resources. Start with the managed platform and migrate later if needed.
💡 Key Takeaways
- • Supabase self-hosting uses Docker Compose with 7+ interconnected services
- • Always change default secrets (JWT_SECRET, POSTGRES_PASSWORD, API keys)
- • Use a reverse proxy (Nginx/Caddy) for SSL termination
- • Set up automated backups with pg_dump and offsite storage
- • Only self-host if you have compliance needs or dedicated DevOps capacity
📚 Learn More
-
Self-Hosting with Docker →
Official guide to deploying Supabase with Docker Compose.
-
Self-Hosting Overview →
Architecture, API keys, and configuration reference.