Deploy Supabase on RamNode VPS

    Complete self-hosted Supabase deployment with PostgreSQL, authentication, storage, and real-time subscriptions

    Why Self-Host Supabase?

    Supabase is an open-source Firebase alternative that provides a complete backend platform including PostgreSQL database, authentication, instant APIs, real-time subscriptions, storage, and edge functions. Self-hosting gives you full control over your data and infrastructure.

    Core Features

    • • PostgreSQL database with REST API
    • • User authentication & authorization
    • • Real-time subscriptions
    • • File storage with CDN
    • • Edge functions (serverless)

    Self-Hosting Benefits

    • • Complete data ownership
    • • No vendor lock-in
    • • Customizable infrastructure
    • • Cost-effective at scale
    • • Compliance & privacy control

    Prerequisites and VPS Specifications

    Before beginning the deployment, ensure your RamNode VPS meets the requirements:

    Development/Testing

    • RAM: 4 GB minimum
    • CPU: 2 vCPU cores
    • Storage: 50 GB SSD
    • OS: Ubuntu 24.04 LTS
    Recommended: 4GB Standard Cloud VPS ($24/mo)

    Production

    • RAM: 8 GB+ recommended
    • CPU: 4+ vCPU cores
    • Storage: 100 GB+ SSD
    • OS: Ubuntu 24.04 LTS
    Recommended: 8GB Standard Cloud VPS ($48/mo)

    Additional Requirements

    • • Domain name pointing to your VPS IP address
    • • Basic Linux command line knowledge
    • • Docker and Docker Compose fundamentals

    Initial Server Setup

    Connect to your RamNode VPS via SSH and perform initial system configuration:

    # Connect to your VPS
    ssh root@your-ramnode-vps-ip
    
    # Update system packages
    apt update && apt upgrade -y
    
    # Install essential packages
    apt install -y curl wget git ufw fail2ban htop nano vim unzip

    Create a dedicated user for Supabase operations:

    # Create new user
    adduser supabase
    usermod -aG sudo supabase
    
    # Switch to new user
    su - supabase

    Configure the firewall:

    # Enable UFW
    sudo ufw enable
    
    # Allow SSH, HTTP, and HTTPS
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    
    # Temporarily allow Supabase API Gateway
    sudo ufw allow 8000/tcp
    
    # Check status
    sudo ufw status
    
    # Enable fail2ban for SSH protection
    sudo systemctl enable fail2ban
    sudo systemctl start fail2ban

    Docker Installation

    Install Docker and Docker Compose for container management:

    # Add Docker's official GPG key
    sudo apt-get update
    sudo apt-get install ca-certificates curl
    sudo install -m 0755 -d /etc/apt/keyrings
    sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    sudo chmod a+r /etc/apt/keyrings/docker.asc
    
    # Add the repository to Apt sources
    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
      $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    
    # Install Docker packages
    sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

    Configure Docker for non-root user:

    # Add user to docker group
    sudo usermod -aG docker supabase
    
    # Apply group changes
    newgrp docker
    
    # Verify installation
    docker --version
    docker compose version

    Configure Docker daemon for optimal logging:

    sudo nano /etc/docker/daemon.json

    Add the following configuration:

    {
      "log-driver": "json-file",
      "log-opts": {
        "max-size": "10m",
        "max-file": "3"
      },
      "storage-driver": "overlay2"
    }
    # Restart Docker
    sudo systemctl restart docker
    sudo systemctl enable docker

    Supabase Installation

    Clone and set up the Supabase Docker deployment:

    # Create directory for Supabase
    mkdir -p /home/supabase/supabase-deployment
    cd /home/supabase/supabase-deployment
    
    # Clone Supabase repository
    git clone --depth 1 https://github.com/supabase/supabase
    
    # Copy Docker files to project directory
    cp -rf supabase/docker/* .
    cp supabase/docker/.env.example .env
    
    # Remove the cloned repository to save space
    rm -rf supabase

    Pull Docker images and start services:

    # Pull all required Docker images
    docker compose pull
    
    # Start all services in detached mode
    docker compose up -d
    
    # Check service status
    docker compose ps
    
    # View logs
    docker compose logs

    Environment Configuration

    Edit the environment file with your configuration:

    nano .env

    Generate secure secrets:

    # Generate a secure JWT secret (40 characters minimum)
    openssl rand -base64 32
    
    # Generate SECRET_KEY_BASE (64+ characters)
    openssl rand -base64 48

    Configure the essential environment variables:

    # Secrets
    POSTGRES_PASSWORD=your_super_secure_postgres_password_here
    JWT_SECRET=your-generated-jwt-secret-here
    ANON_KEY=your-generated-anon-key-here
    SERVICE_ROLE_KEY=your-generated-service-role-key-here
    SECRET_KEY_BASE=your-generated-secret-key-base-here
    
    # Database
    POSTGRES_HOST=db
    POSTGRES_PORT=5432
    POSTGRES_DB=postgres
    
    # API Configuration
    KONG_HTTP_PORT=8000
    KONG_HTTPS_PORT=8443
    API_EXTERNAL_URL=https://your-domain.com
    
    # Dashboard
    STUDIO_DEFAULT_ORGANIZATION=Your Organization
    STUDIO_DEFAULT_PROJECT=Your Project
    STUDIO_PORT=3000
    SUPABASE_PUBLIC_URL=https://your-domain.com
    DASHBOARD_USERNAME=admin
    DASHBOARD_PASSWORD=your_secure_dashboard_password
    
    # Auth
    SITE_URL=https://your-domain.com
    ADDITIONAL_REDIRECT_URLS=https://your-domain.com
    JWT_EXPIRY=3600
    DISABLE_SIGNUP=false

    Important: For JWT keys generation, visit: Supabase API Keys Documentation

    Security Configuration

    Configure database security and authentication providers:

    # Access PostgreSQL container
    docker compose exec db psql -U postgres
    
    # Create additional database users with limited permissions
    CREATE USER app_user WITH PASSWORD 'secure_app_password';
    GRANT CONNECT ON DATABASE postgres TO app_user;
    GRANT USAGE ON SCHEMA public TO app_user;
    GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user;

    Configure OAuth providers in .env (optional):

    # GitHub OAuth
    AUTH_GITHUB_ENABLED=true
    AUTH_GITHUB_CLIENT_ID=your_github_client_id
    AUTH_GITHUB_SECRET=your_github_client_secret
    
    # Google OAuth
    AUTH_GOOGLE_ENABLED=true
    AUTH_GOOGLE_CLIENT_ID=your_google_client_id
    AUTH_GOOGLE_SECRET=your_google_client_secret

    Update network security:

    # Remove temporary port access after SSL setup
    sudo ufw delete allow 8000/tcp
    
    # Verify only necessary ports are open
    sudo ufw status numbered

    Production Optimizations

    Create a docker-compose.override.yml for resource limits:

    services:
      db:
        deploy:
          resources:
            limits:
              memory: 2G
              cpus: '1.0'
            reservations:
              memory: 1G
              cpus: '0.5'
    
      kong:
        deploy:
          resources:
            limits:
              memory: 512M
              cpus: '0.5'
            reservations:
              memory: 256M
              cpus: '0.25'
    
      auth:
        deploy:
          resources:
            limits:
              memory: 512M
              cpus: '0.5'
            reservations:
              memory: 256M
              cpus: '0.25'
    
      studio:
        deploy:
          resources:
            limits:
              memory: 512M
              cpus: '0.5'
            reservations:
              memory: 256M
              cpus: '0.25'

    Configure PostgreSQL performance tuning:

    # Create custom PostgreSQL configuration
    mkdir -p ./volumes/db/postgresql
    nano ./volumes/db/postgresql/postgresql.conf
    # Memory Configuration
    shared_buffers = 256MB
    effective_cache_size = 1GB
    maintenance_work_mem = 64MB
    work_mem = 4MB
    
    # Connection Configuration
    max_connections = 100
    superuser_reserved_connections = 3
    
    # Checkpoint Configuration
    checkpoint_completion_target = 0.9
    wal_buffers = 16MB
    
    # SSD Optimization
    random_page_cost = 1.1
    effective_io_concurrency = 200
    
    # Logging
    log_min_duration_statement = 1000
    log_checkpoints = on
    log_connections = on
    
    # Autovacuum
    autovacuum = on

    Configure connection pooling in .env:

    POOLER_TENANT_ID=your-app-name
    POOLER_PROXY_PORT_SESSION=5432
    POOLER_PROXY_PORT_TRANSACTION=6543
    POOLER_DEFAULT_POOL_SIZE=25
    POOLER_MAX_CLIENT_CONN=1000

    SSL/TLS Setup with Nginx

    Install Nginx and configure as a reverse proxy:

    sudo apt install nginx
    sudo nano /etc/nginx/sites-available/supabase

    Add the Nginx configuration:

    server {
        listen 80;
        server_name your-domain.com www.your-domain.com;
        return 301 https://$server_name$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        server_name your-domain.com www.your-domain.com;
    
        # SSL will be configured by Certbot
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_prefer_server_ciphers off;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
    
        # Security Headers
        add_header X-Frame-Options DENY;
        add_header X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    
        client_max_body_size 50M;
    
        location / {
            proxy_pass http://127.0.0.1:8000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            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;
            proxy_cache_bypass $http_upgrade;
            
            proxy_connect_timeout 60s;
            proxy_send_timeout 60s;
            proxy_read_timeout 60s;
        }
    
        # WebSocket support for Realtime
        location /realtime/v1/websocket {
            proxy_pass http://127.0.0.1:8000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            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;
        }
    }

    Enable the site and obtain SSL certificate:

    # Enable the site
    sudo ln -s /etc/nginx/sites-available/supabase /etc/nginx/sites-enabled/
    
    # Test configuration
    sudo nginx -t
    
    # Install Certbot and obtain SSL certificate
    sudo apt install certbot python3-certbot-nginx
    sudo certbot --nginx -d your-domain.com -d www.your-domain.com
    
    # Test automatic renewal
    sudo certbot renew --dry-run
    
    # Restart Nginx
    sudo systemctl restart nginx
    sudo systemctl enable nginx

    Update Supabase configuration for HTTPS:

    # Edit .env
    nano .env
    
    # Update URLs to use HTTPS
    SITE_URL=https://your-domain.com
    API_EXTERNAL_URL=https://your-domain.com
    SUPABASE_PUBLIC_URL=https://your-domain.com
    ADDITIONAL_REDIRECT_URLS=https://your-domain.com
    
    # Restart Supabase services
    docker compose down
    docker compose up -d

    Monitoring and Maintenance

    Create a health check script:

    nano ~/health-check.sh
    chmod +x ~/health-check.sh
    #!/bin/bash
    # Health check script for Supabase
    
    cd /home/supabase/supabase-deployment
    
    echo "=== Supabase Health Check - $(date) ==="
    
    echo "Docker Services Status:"
    docker compose ps
    
    echo -e "\nService Health Checks:"
    
    # API Gateway
    if curl -s -I http://localhost:8000/health | grep -q "200 OK"; then
        echo "✓ API Gateway: Healthy"
    else
        echo "✗ API Gateway: Unhealthy"
    fi
    
    # Database connectivity
    if docker compose exec -T db pg_isready -U postgres > /dev/null 2>&1; then
        echo "✓ PostgreSQL: Healthy"
    else
        echo "✗ PostgreSQL: Unhealthy"
    fi
    
    # Database size
    db_size=$(docker compose exec -T db psql -U postgres -d postgres -t -c "SELECT pg_size_pretty(pg_database_size('postgres'))")
    echo "✓ Database size: $db_size"
    
    # Container resource usage
    echo -e "\nResource Usage:"
    docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

    Set up cron jobs for automated tasks:

    crontab -e
    
    # Add these entries:
    # Daily backup at 2 AM
    0 2 * * * /home/supabase/backup.sh >> /home/supabase/backup.log 2>&1
    
    # Health check every 15 minutes
    */15 * * * * /home/supabase/health-check.sh >> /home/supabase/health.log 2>&1
    
    # Clean up old logs weekly
    0 1 * * 0 find /home/supabase/*.log -mtime +30 -delete

    Backup Strategy

    Create an automated backup script:

    nano ~/backup.sh
    chmod +x ~/backup.sh
    #!/bin/bash
    # Automated backup script for Supabase
    
    BACKUP_DIR="/home/supabase/backups"
    DATE=$(date +%Y%m%d_%H%M%S)
    POSTGRES_PASSWORD="your_postgres_password"
    
    # Create backup directory
    mkdir -p $BACKUP_DIR
    
    cd /home/supabase/supabase-deployment
    
    echo "Starting backup at $(date)"
    
    # Database backup
    echo "Backing up PostgreSQL database..."
    docker compose exec -T -e PGPASSWORD=$POSTGRES_PASSWORD db pg_dump -U postgres -d postgres > $BACKUP_DIR/db_$DATE.sql
    
    # Configuration backup
    echo "Backing up configuration..."
    cp .env $BACKUP_DIR/env_$DATE.backup
    
    # Storage backup (if using local storage)
    if [ -d "./volumes/storage" ]; then
        echo "Backing up storage files..."
        tar -czf $BACKUP_DIR/storage_$DATE.tar.gz ./volumes/storage/
    fi
    
    # Cleanup old backups (keep last 7 days)
    find $BACKUP_DIR -name "*.sql" -mtime +7 -delete
    find $BACKUP_DIR -name "*.backup" -mtime +7 -delete
    find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
    
    echo "Backup completed at $(date)"

    For offsite backups, consider syncing to S3 or RamNode Object Storage:

    # Install AWS CLI for S3 backups
    sudo apt install awscli
    aws configure
    
    # Create S3 sync script
    #!/bin/bash
    BACKUP_DIR="/home/supabase/backups"
    S3_BUCKET="your-backup-bucket"
    
    aws s3 sync $BACKUP_DIR s3://$S3_BUCKET/supabase-backups/ \
        --exclude "*.log" \
        --storage-class STANDARD_IA

    Troubleshooting

    Services Won't Start

    # Check service logs
    docker compose logs [service-name]
    
    # Common fixes:
    # 1. Port conflicts
    netstat -tulpn | grep :8000
    
    # 2. Permission issues
    sudo chown -R 1000:1000 ./volumes/
    
    # 3. Memory issues
    free -h
    docker system prune -f

    Database Connection Issues

    # Test database connectivity
    docker compose exec db pg_isready -U postgres
    
    # Check database logs
    docker compose logs db
    
    # Reset database if corrupted (WARNING: DATA LOSS)
    docker compose down -v
    docker compose up -d

    SSL Certificate Issues

    # Renew SSL certificate manually
    sudo certbot renew
    
    # Check certificate status
    sudo certbot certificates
    
    # Test SSL configuration
    openssl s_client -connect your-domain.com:443

    Performance Issues

    # Check container resource usage
    docker stats
    
    # Restart services to clear memory leaks
    docker compose restart
    
    # Identify CPU-intensive processes
    htop
    
    # Check for runaway queries
    docker compose exec db psql -U postgres -d postgres -c "
    SELECT pid, now() - pg_stat_activity.query_start AS duration, query
    FROM pg_stat_activity
    WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes';"

    Complete Service Restart

    # Full restart with latest images
    docker compose down
    docker compose pull
    docker compose up -d

    Ready to Deploy Supabase?

    Get started with a RamNode Cloud VPS optimized for self-hosted applications. Our Standard Cloud VPS plans provide the perfect balance of performance and value.