ignitionstack.pro v1.0 is out! Read the announcement →
Skip to Content

Supabase Self-Hosted Migration

This guide walks you through migrating your IgnitionStack project from Supabase Cloud to a self-hosted Supabase instance on your own VPS.

Why Self-Host Supabase?

BenefitDescription
Full ControlComplete ownership of your infrastructure and data
Cost EffectiveFixed monthly costs vs. usage-based pricing at scale
Data SovereigntyKeep data in specific regions for compliance
CustomizationFull access to PostgreSQL and all services
No Vendor Lock-inFreedom to migrate anywhere

Prerequisites

Before starting the migration:

Hostinger VPS

# Recommended plan: KVM 2 # - 8 GB RAM # - 4 vCPU # - 100 GB NVMe SSD # - ~$13.99/month

Other Providers

ProviderPlanRAMStoragePrice/mo
DigitalOceanDroplet4GB80GB SSD$24
HetznerCX318GB80GB SSD€8.49
VultrHigh Frequency4GB128GB NVMe$24
LinodeDedicated 4GB4GB80GB SSD$36
ContaboVPS M16GB400GB SSD€10.99

Step 1: Server Setup

1.1 Connect to Your VPS

ssh root@your-server-ip

1.2 Update System

# Ubuntu/Debian apt update && apt upgrade -y # Install essential packages apt install -y curl git ufw

1.3 Install Docker

# Install Docker curl -fsSL https://get.docker.com -o get-docker.sh sh get-docker.sh # Install Docker Compose apt install -y docker-compose-plugin # Verify installation docker --version docker compose version

1.4 Configure Firewall

ufw allow OpenSSH ufw allow 80 ufw allow 443 ufw allow 5432 # PostgreSQL (optional, for external access) ufw enable

Step 2: Install Supabase Self-Hosted

2.1 Clone Supabase Docker

# Create directory mkdir -p /opt/supabase cd /opt/supabase # Clone the official Supabase Docker setup git clone --depth 1 https://github.com/supabase/supabase cd supabase/docker

2.2 Configure Environment

# Copy example env cp .env.example .env # Generate secure keys # JWT Secret (must be at least 32 characters) JWT_SECRET=$(openssl rand -base64 32) echo "JWT_SECRET=$JWT_SECRET" # Anon Key ANON_KEY=$(docker run --rm supabase/gotrue:latest sh -c "echo '{\"role\":\"anon\",\"iss\":\"supabase\",\"iat\":'$(date +%s)',\"exp\":'$(($(date +%s) + 315360000))'}' | base64 -w 0") echo "ANON_KEY=$ANON_KEY" # Service Role Key SERVICE_ROLE_KEY=$(docker run --rm supabase/gotrue:latest sh -c "echo '{\"role\":\"service_role\",\"iss\":\"supabase\",\"iat\":'$(date +%s)',\"exp\":'$(($(date +%s) + 315360000))'}' | base64 -w 0") echo "SERVICE_ROLE_KEY=$SERVICE_ROLE_KEY"

2.3 Edit .env File

nano .env

Update these critical values:

############ # Secrets ############ POSTGRES_PASSWORD=your-super-secure-password-here JWT_SECRET=your-generated-jwt-secret ANON_KEY=your-generated-anon-key SERVICE_ROLE_KEY=your-generated-service-role-key ############ # Dashboard ############ DASHBOARD_USERNAME=admin DASHBOARD_PASSWORD=your-dashboard-password ############ # URLs ############ SITE_URL=https://your-domain.com API_EXTERNAL_URL=https://api.your-domain.com SUPABASE_PUBLIC_URL=https://api.your-domain.com ############ # SMTP (for auth emails) ############ SMTP_HOST=smtp.resend.com SMTP_PORT=465 SMTP_USER=resend SMTP_PASS=your-resend-api-key SMTP_SENDER_NAME=Your App SMTP_ADMIN_EMAIL=admin@your-domain.com

2.4 Start Supabase

docker compose up -d # Check status docker compose ps # View logs docker compose logs -f

Step 3: Configure Reverse Proxy (Caddy)

3.1 Install Caddy

apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list apt update apt install caddy

3.2 Configure Caddy

nano /etc/caddy/Caddyfile
# API and Studio api.your-domain.com { reverse_proxy localhost:8000 } # Studio Dashboard studio.your-domain.com { reverse_proxy localhost:3000 } # Storage/S3 storage.your-domain.com { reverse_proxy localhost:5000 }

3.3 Reload Caddy

systemctl reload caddy

Step 4: Migrate Data from Supabase Cloud

4.1 Export from Supabase Cloud

# Install Supabase CLI locally npm install -g supabase # Login to Supabase supabase login # Link to your cloud project supabase link --project-ref your-project-ref # Dump the database supabase db dump -f supabase_backup.sql --data-only

4.2 Import to Self-Hosted

# Copy backup to server scp supabase_backup.sql root@your-server-ip:/opt/supabase/ # Import to self-hosted PostgreSQL docker exec -i supabase-db psql -U postgres -d postgres < /opt/supabase/supabase_backup.sql

4.3 Migrate Storage Files

# Download files from Supabase Cloud Storage using their API # Or use the Supabase dashboard to download and re-upload # Using s3cmd or rclone for bulk transfer rclone sync supabase-cloud:bucket-name self-hosted:bucket-name

Step 5: Update IgnitionStack Configuration

5.1 Update Environment Variables

# .env.production NEXT_PUBLIC_SUPABASE_URL=https://api.your-domain.com NEXT_PUBLIC_SUPABASE_ANON_KEY=your-self-hosted-anon-key SUPABASE_SERVICE_ROLE_KEY=your-self-hosted-service-role-key

5.2 Update Auth Callback URLs

In your self-hosted Supabase dashboard:

  1. Go to Authentication → URL Configuration
  2. Update Site URL: https://your-app-domain.com
  3. Add Redirect URLs:
    • https://your-app-domain.com/**
    • https://your-app-domain.com/auth/callback

5.3 Test the Connection

# From your development machine npm run dev # Test database connection npm run db:gen

Step 6: Production Hardening

6.1 Enable Automatic Backups

# Create backup script cat > /opt/supabase/backup.sh << 'EOF' #!/bin/bash BACKUP_DIR=/opt/supabase/backups DATE=$(date +%Y%m%d_%H%M%S) mkdir -p $BACKUP_DIR docker exec supabase-db pg_dump -U postgres postgres > $BACKUP_DIR/backup_$DATE.sql # Keep only last 7 days find $BACKUP_DIR -name "backup_*.sql" -mtime +7 -delete EOF chmod +x /opt/supabase/backup.sh # Add to crontab (daily at 2 AM) (crontab -l 2>/dev/null; echo "0 2 * * * /opt/supabase/backup.sh") | crontab -

6.2 Set Up Monitoring

# Install Netdata for real-time monitoring bash <(curl -Ss https://my-netdata.io/kickstart.sh)

6.3 Enable Log Rotation

cat > /etc/logrotate.d/supabase << EOF /opt/supabase/supabase/docker/volumes/logs/*.log { daily rotate 7 compress delaycompress missingok notifempty } EOF

Troubleshooting

Common Issues

Container won’t start:

docker compose logs [service-name] docker compose down && docker compose up -d

Database connection refused:

# Check if PostgreSQL is running docker exec supabase-db pg_isready # Check ports netstat -tlnp | grep 5432

Auth emails not sending:

# Test SMTP connection docker exec supabase-auth /bin/sh -c "echo test | mail -s 'Test' your@email.com"

Studio not accessible:

# Check if Kong is routing correctly curl -i http://localhost:8000/rest/v1/

Maintenance Commands

# Update Supabase cd /opt/supabase/supabase/docker git pull docker compose pull docker compose up -d # View realtime logs docker compose logs -f # Restart specific service docker compose restart [service-name] # Full restart docker compose down && docker compose up -d