TechLead
Lesson 21 of 22
5 min read
Supabase

Self-Hosting Supabase

Deploy Supabase on your own infrastructure with Docker Compose, configuration, backups, and monitoring

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

Continue Learning