Skip to main content

Self-Hosting Guide: Deploy Supabase Locally

·OSSAlt Team
supabasebackendself-hostingdockerguide

Self-Hosting Guide: Deploy Supabase Locally

Supabase is the open source Firebase alternative — PostgreSQL database, authentication, storage, edge functions, and real-time subscriptions. Self-hosting removes the 500 MB database limit, gives you unlimited API requests, and costs a fraction of Supabase Cloud's $25/month Pro plan.

Requirements

  • VPS with 4 GB RAM minimum (8 GB recommended)
  • Docker and Docker Compose
  • Domain name (e.g., supabase.yourdomain.com)
  • 30+ GB disk

Step 1: Clone Supabase Docker

git clone --depth 1 https://github.com/supabase/supabase.git
cd supabase/docker

# Copy environment
cp .env.example .env

Step 2: Generate Secrets

# Generate JWT secret
openssl rand -hex 32

# Generate anon key and service role key using the JWT secret
# Use https://supabase.com/docs/guides/self-hosting/docker#generate-api-keys
# Or generate manually with jwt.io

Step 3: Configure Environment

Edit .env:

# General
SITE_URL=https://supabase.yourdomain.com
API_EXTERNAL_URL=https://supabase.yourdomain.com

# JWT
JWT_SECRET=your-jwt-secret-min-32-chars
ANON_KEY=your-generated-anon-key
SERVICE_ROLE_KEY=your-generated-service-role-key

# Database
POSTGRES_PASSWORD=your-strong-password
POSTGRES_HOST=db
POSTGRES_DB=postgres
POSTGRES_PORT=5432

# Dashboard
DASHBOARD_USERNAME=admin
DASHBOARD_PASSWORD=your-dashboard-password

# SMTP
SMTP_HOST=smtp.resend.com
SMTP_PORT=587
SMTP_USER=resend
SMTP_PASS=re_your_api_key
SMTP_SENDER_NAME=Supabase
SMTP_ADMIN_EMAIL=admin@yourdomain.com

# Storage
STORAGE_BACKEND=file
FILE_SIZE_LIMIT=52428800

Step 4: Start Supabase

docker compose up -d

This starts all Supabase services:

ServicePortPurpose
Kong (API Gateway)8000API routing
GoTrue9999Authentication
PostgREST3000REST API from PostgreSQL
Realtime4000WebSocket subscriptions
Storage5000File storage API
Studio3001Dashboard UI
PostgreSQL5432Database
Meta8080Metadata API

Step 5: Reverse Proxy (Caddy)

# /etc/caddy/Caddyfile
supabase.yourdomain.com {
    # API Gateway
    reverse_proxy localhost:8000
}

studio.yourdomain.com {
    # Dashboard
    reverse_proxy localhost:3001
}
sudo systemctl restart caddy

Step 6: Access Dashboard

  1. Open https://studio.yourdomain.com
  2. Login with your dashboard credentials
  3. Create your first project

Step 7: Connect Your App

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

const supabase = createClient(
  'https://supabase.yourdomain.com',
  'your-anon-key'
)

// Query data
const { data, error } = await supabase
  .from('todos')
  .select('*')

// Insert data
const { data, error } = await supabase
  .from('todos')
  .insert({ title: 'My todo', completed: false })

// Auth
const { data, error } = await supabase.auth.signUp({
  email: 'user@example.com',
  password: 'password123',
})

// Storage
const { data, error } = await supabase.storage
  .from('avatars')
  .upload('user1/avatar.png', file)

// Realtime
supabase
  .channel('todos')
  .on('postgres_changes', { event: '*', schema: 'public', table: 'todos' },
    (payload) => console.log('Change:', payload)
  )
  .subscribe()

Step 8: Set Up Row Level Security

Enable RLS on your tables for production security:

-- Enable RLS
ALTER TABLE todos ENABLE ROW LEVEL SECURITY;

-- Users can only read their own todos
CREATE POLICY "Users read own todos"
ON todos FOR SELECT
USING (auth.uid() = user_id);

-- Users can only insert their own todos
CREATE POLICY "Users insert own todos"
ON todos FOR INSERT
WITH CHECK (auth.uid() = user_id);

-- Users can only update their own todos
CREATE POLICY "Users update own todos"
ON todos FOR UPDATE
USING (auth.uid() = user_id);

Production Hardening

Restrict Studio access:

  • Put Studio behind VPN or IP allowlist
  • Use strong dashboard credentials
  • Consider disabling Studio in production

Backups:

# Database backup (daily cron)
docker exec supabase-db pg_dump -U postgres postgres > /backups/supabase-$(date +%Y%m%d).sql

# Storage backup
tar czf /backups/supabase-storage-$(date +%Y%m%d).tar.gz ./volumes/storage

Updates:

cd supabase/docker
git pull
docker compose pull
docker compose up -d

Monitoring:

  • Monitor Kong API gateway (port 8000)
  • Monitor PostgreSQL connections and query performance
  • Set up disk space alerts (database grows)
  • Monitor GoTrue for auth failures

Resource Usage

ScaleRAMCPUDisk
Development4 GB2 cores20 GB
Small app (1K users)8 GB4 cores50 GB
Medium app (10K users)16 GB8 cores100 GB

VPS Recommendations

ProviderSpec (small app)Price
Hetzner4 vCPU, 8 GB RAM€8/month
DigitalOcean4 vCPU, 8 GB RAM$48/month
Linode4 vCPU, 8 GB RAM$48/month

Supabase is resource-intensive due to multiple services. Use Hetzner for the best price-performance ratio.


Compare backend platforms on OSSAlt — features, pricing, and self-hosting options side by side.