Skip to Content

Self-Host Supabase Docker: Your Complete Guide to Owning Your Backend

Deploy a production-ready Supabase stack with Docker Compose, custom domains, and real-world security—no managed platform required.

Self-Host Supabase Docker: Your Complete Guide to Owning Your Backend

You want the power of Supabase without the platform bills. You want your data on your servers. And you want it running in Docker, not some black-box managed service. This guide walks you through self-hosting the full Supabase stack—Postgres, Auth, Storage, Realtime, and Edge Functions—using Docker Compose. By the end, you'll have a production-ready backend you actually control.

For a deeper look at why self-hosting matters and the full architecture breakdown, check out our companion piece: Self-Host Supabase Docker: Run Your Own Firebase Alternative With Full Control.

What You'll Build

By the end of this guide, you'll have:

  • The complete Supabase stack running via Docker Compose
  • PostgreSQL with the Supavisor connection pooler
  • Auth, Storage, Realtime, and Edge Functions services
  • Supabase Studio dashboard accessible via your domain
  • Proper secrets, JWT keys, and HTTPS configuration
  • A working client connection from your frontend application

Prerequisites

Before you start, make sure you have:

  • Docker 24.0+ and Docker Compose v2 installed
  • Git installed for cloning the configuration
  • At least 4GB RAM (8GB+ recommended for production)
  • At least 2 CPU cores (4+ recommended)
  • 40GB SSD minimum (80GB+ recommended)
  • A server or VM with a static IP and ports 80, 443, and 8000 accessible
  • A domain name pointing to your server (for production)
  • Basic familiarity with Linux, networking, and environment variables

If you're looking for a from-scratch deep dive into every component, our detailed walkthrough covers it: Own Your Backend: How to Self-Host Supabase with Docker from Scratch.

Step 1: Get the Supabase Docker Configuration

Supabase distributes its Docker configuration as part of the official repository. You have two options: automated quick start (Linux only) or manual installation (any OS).

Option A: Quick Start (Linux)

If you're on Debian/Ubuntu or RHEL/CentOS/Fedora, the automated script handles everything:

curl -fsSL https://supabase.link/setup.sh | sh

This script installs prerequisites, clones the Docker configuration, generates all secrets and JWT keys, prompts for your URLs, and pulls the images. After it finishes:

cd supabase-project && \
sh run.sh start

Option B: Manual Installation (Any OS)

For non-Linux systems or if you prefer full control, clone the repository manually:

# Clone the Supabase repository
git clone --depth 1 https://github.com/supabase/supabase

# Create your project directory
mkdir supabase-project

# Copy Docker files
cp -rf supabase/docker/* supabase-project/
cp supabase/docker/.env.example supabase-project/.env

# Switch to project directory
cd supabase-project

# Pull latest images
docker compose pull

Step 2: Generate Secrets and Configure URLs

Never run Supabase with the example passwords. Generate secure secrets and configure your environment properly.

Generate Keys and Secrets

# Generate random passwords and secrets
sh utils/generate-keys.sh

# Add new API keys and asymmetric JWT key pair
sh utils/add-new-auth-keys.sh

Review the generated output and check your .env file before proceeding.

Configure Supabase URLs

Edit the .env file and set these critical variables:

# Base URL for accessing Supabase from the internet
SUPABASE_PUBLIC_URL=https://api.yourdomain.com

# Used by Auth service for callback URLs
API_EXTERNAL_URL=https://api.yourdomain.com

# Default redirect URL for Auth
SITE_URL=https://app.yourdomain.com

# Dashboard credentials (must contain at least one letter)
DASHBOARD_USERNAME=admin
DASHBOARD_PASSWORD=your-secure-password-here

Security note: The dashboard password must include at least one letter—don't use numbers only or special characters.

Step 3: Start the Supabase Stack

With secrets generated and URLs configured, start the stack:

sh run.sh start

This is equivalent to docker compose up -d --wait. It starts all services and waits until they're healthy. Check the status:

docker compose ps

All services should show Up [...] (healthy). If any container shows created but not Up, inspect the logs:

sh run.sh logs auth
sh run.sh logs storage
sh run.sh logs realtime

Step 4: Access Your Services

Once everything is healthy, access your services through the Kong API gateway.

Supabase Studio Dashboard

Open https://api.yourdomain.com (or http://your-server-ip:8000 without HTTPS). You'll be prompted for basic auth using the DASHBOARD_USERNAME and DASHBOARD_PASSWORD from your .env file.

API Endpoints

All APIs are available through the same gateway:

  • REST: https://api.yourdomain.com/rest/v1/
  • Auth: https://api.yourdomain.com/auth/v1/
  • Storage: https://api.yourdomain.com/storage/v1/
  • Realtime: https://api.yourdomain.com/realtime/v1/

Connect to PostgreSQL

Supabase includes the Supavisor connection pooler. Connect via session mode (direct equivalent):

psql 'postgres://postgres.your-tenant-id:[email protected]:5432/postgres'

Or transaction mode (connection pooling):

psql 'postgres://postgres.your-tenant-id:[email protected]:6543/postgres'

Step 5: Configure HTTPS with a Reverse Proxy

For production, you need HTTPS. The recommended approach is placing a reverse proxy in front of Kong.

Caddy Example

# Caddyfile
api.yourdomain.com {
  reverse_proxy localhost:8000
}

Nginx Example

server {
  listen 443 ssl http2;
  server_name api.yourdomain.com;

  ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;

  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;
  }
}

After setting up the reverse proxy, update your .env URLs to use https://api.yourdomain.com and restart the stack.

Step 6: Connect Your Application

Now connect your frontend to your self-hosted Supabase instance.

JavaScript/TypeScript Client

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = 'https://api.yourdomain.com'
const supabaseKey = 'your-publishable-anon-key'

const supabase = createClient(supabaseUrl, supabaseKey)

// Example: fetch data
const { data, error } = await supabase
  .from('posts')
  .select('*')

Find your credentials by running:

sh run.sh secrets

The key values you need:

  • SUPABASE_PUBLISHABLE_KEY — for client-side code (safe to expose)
  • SUPABASE_SECRET_KEY — for server-side only (never expose this)
  • POSTGRES_PASSWORD — for direct database connections
  • SUPABASE_PUBLIC_URL — the URL passed to createClient

Security Hardening Checklist

Before calling this production-ready:

Change All Default Secrets

Run sh utils/generate-keys.sh and sh utils/add-new-auth-keys.sh to replace every placeholder in .env. Never commit the .env file.

Enable HTTPS

Always use HTTPS in production. Set up a reverse proxy with valid TLS certificates (Let's Encrypt is free).

Secure the Dashboard

Use a strong, unique password for DASHBOARD_PASSWORD. Consider restricting dashboard access by IP or VPN.

Database Access

Don't expose Postgres directly to the internet. Use Supavisor or connect via your application's internal network. If you must expose it, restrict to specific IPs:

# In docker-compose.yml, under the db service
ports:
  - "127.0.0.1:5432:5432"  # Local only
  # OR specific IP
  - "10.0.0.5:5432:5432"

Backups

Set up automated PostgreSQL backups:

#!/bin/bash
# backup-supabase.sh
CONTAINER=supabase-db
BACKUP_DIR=/backups
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

docker exec $CONTAINER pg_dump -U supabase postgres \
  | gzip > "$BACKUP_DIR/supabase-$TIMESTAMP.sql.gz"

# Keep only last 7 days
find $BACKUP_DIR -name 'supabase-*.sql.gz' -mtime +7 -delete

Add to crontab for daily backups:

0 2 * * * /path/to/backup-supabase.sh

Tips and Troubleshooting

Service won't start or shows unhealthy

Check container logs first:

sh run.sh logs 
# or
docker compose logs --tail=100 

Common culprits: insufficient memory, port conflicts, or missing environment variables.

Port 8000 already in use

sudo lsof -i :8000
# or
ss -tlnp | grep 8000

Change the host port in docker-compose.yml or stop the conflicting service.

Out of memory errors

Supabase is resource-intensive. If you see OOM kills:

  • Upgrade to 8GB+ RAM
  • Remove unused services from docker-compose.yml (Realtime, Storage, imgproxy, Edge Functions)
  • Add swap space as a temporary buffer

Auth redirects failing

Ensure SITE_URL and API_EXTERNAL_URL in .env exactly match your actual domain. Auth callbacks are strict about URL matching.

Edge Functions not updating

A plain restart doesn't pick up function changes. Force recreate:

sh run.sh recreate functions

Updating Supabase

Supabase releases stable Docker versions monthly. To update:

# Pull latest images
sh run.sh pull

# Recreate containers with new images
sh run.sh recreate

Always check the self-hosted changelog before updating.

Reset everything (destructive)

If you need to start completely fresh:

sh reset.sh

Warning: This destroys all data, including the database and storage volumes. It backs up .env to .env.old first.

Next Steps

You now have a self-hosted Supabase instance running on Docker. From here, you can:

  • Set up Row Level Security (RLS) policies in your database
  • Configure OAuth providers (Google, GitHub, etc.) in Auth settings
  • Enable Storage buckets with proper access controls
  • Deploy custom Edge Functions for serverless logic
  • Set up Realtime subscriptions for live data
  • Enable Logs & Analytics for monitoring

For a comprehensive walkthrough of the full architecture and advanced configuration, read our deep-dive guide: Own Your Backend: How to Self-Host Supabase with Docker from Scratch.

And if you want to understand why Supabase is becoming the go-to backend for modern development, check out our coverage of their momentum: Supabase Doubles Its Valuation to $10B in Just 8 Months, Riding the Vibe-Coding Wave.

Already comfortable with the basics and want the full control overview? See: Self-Host Supabase Docker: Run Your Own Firebase Alternative With Full Control.

Need Help With Production Supabase?

Self-hosting Supabase gives you full control, but it also means you're responsible for security, backups, scaling, and uptime. If your team needs help architecting a production-grade Supabase deployment, configuring SSO, setting up monitoring, or migrating from managed Supabase to self-hosted, get in touch with our team at Sysbrix. We've built and maintained self-hosted backends for startups and enterprises—and we can get yours running right.

Deploy n8n on Coolify: Self-Hosted Workflow Automation Without the SaaS Bill
Spin up a production-ready n8n instance on Coolify with PostgreSQL, Redis, SSL, and queue mode — unlimited executions, full data control, zero monthly fees.