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
Production
- • RAM: 8 GB+ recommended
- • CPU: 4+ vCPU cores
- • Storage: 100 GB+ SSD
- • OS: Ubuntu 24.04 LTS
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 unzipCreate a dedicated user for Supabase operations:
# Create new user
adduser supabase
usermod -aG sudo supabase
# Switch to new user
su - supabaseConfigure 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 fail2banDocker 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-pluginConfigure 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 versionConfigure Docker daemon for optimal logging:
sudo nano /etc/docker/daemon.jsonAdd 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 dockerSupabase 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 supabasePull 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 logsEnvironment Configuration
Edit the environment file with your configuration:
nano .envGenerate secure secrets:
# Generate a secure JWT secret (40 characters minimum)
openssl rand -base64 32
# Generate SECRET_KEY_BASE (64+ characters)
openssl rand -base64 48Configure 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=falseImportant: 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_secretUpdate network security:
# Remove temporary port access after SSL setup
sudo ufw delete allow 8000/tcp
# Verify only necessary ports are open
sudo ufw status numberedProduction 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 = onConfigure 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=1000SSL/TLS Setup with Nginx
Install Nginx and configure as a reverse proxy:
sudo apt install nginx
sudo nano /etc/nginx/sites-available/supabaseAdd 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 nginxUpdate 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 -dMonitoring 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 -deleteBackup 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_IATroubleshooting
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 -fDatabase 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 -dSSL 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:443Performance 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 -dReady 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.
