Deploy your own Supabase instance with Docker for complete data control and privacy
Before starting, ensure you have the following:
Self-hosting requires proper security configuration. Ensure your server is properly secured with firewalls, regular updates, and strong authentication.
# Check Docker version (should be 20.10+)
docker --version
# Verify Docker is running
docker ps
Get the official Supabase self-hosting setup:
# Create directory for Supabase
mkdir ~/supabase-selfhosted
cd ~/supabase-selfhosted
# Clone the repository
git clone --depth 1 https://github.com/supabase/supabase.git
cd supabase/docker
# Copy example environment file
cp .env.example .env
Install Docker and Docker Compose on Ubuntu:
# Update package index
sudo apt update
# Install required packages
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# Add user to docker group
sudo usermod -aG docker $USER
# Log out and back in for group changes to take effect
Generate secure secrets for your installation:
# Generate JWT secret (save this!)
openssl rand -base64 32
# Generate anonymous key (save this!)
openssl rand -base64 32
# Generate service role key (save this!)
openssl rand -base64 32
# Generate PostgreSQL password
openssl rand -base64 32
version: "3.8"
Authentication & Email (Gmail SMTP)
Step 1
Adjust Your Configuration
Open the .env
file in your supabase/docker
directory and set the following variables to match your environment. This is the most important step for customizing your self-hosted Supabase instance.
.env Example
# Basic Configuration
volumes:
# Custom PostgreSQL configuration
- ./postgresql.conf:/etc/postgresql/postgresql.conf
command: >
postgres
-c config_file=/etc/postgresql/postgresql.conf
-c log_statement=all
-c log_destination=stderr
-c log_min_duration_statement=0
kong:
ports:
# Bind to specific interfaces for security
- "127.0.0.1:8000:8000"
- "127.0.0.1:8443:8443"
studio:
environment:
# Additional studio configuration
- SUPABASE_REST_URL=http://kong:8000/rest/v1/
Authentication Configuration
Step 1
Access Supabase Studio
Open your browser and navigate to Supabase Studio:
Studio Access
URL: http://localhost:3000
Username: admin (or your DASHBOARD_USERNAME)
Password: your_dashboard_password_here
Step 2
Configure Authentication Settings
In Studio, go to Authentication > Settings:
Setting
Value
Description
Site URL
https://your-domain.com
Your production domain
Redirect URLs
https://your-domain.com/**
Allowed redirect patterns
JWT Expiry
3600
Token expiry in seconds
Enable signup
Enabled
Allow new registrations
Step 3
Test Authentication
Create a test user to verify authentication works:
Create Test User
# Using curl to test signup
curl -X POST 'http://localhost:8000/auth/v1/signup' \
-H "apikey: YOUR_ANON_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "test@example.com",
"password": "testpassword123"
}'
SSL Setup with Let's Encrypt
Step 1
Install Certbot
Install Let's Encrypt certbot for SSL certificates:
Install Certbot
# Install certbot
sudo apt install certbot
# Install nginx plugin
sudo apt install python3-certbot-nginx
Step 2
Configure Nginx Reverse Proxy
Create an nginx configuration for SSL termination:
/etc/nginx/sites-available/supabase
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://localhost:3000;
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;
}
location /rest/ {
proxy_pass http://localhost:8000/rest/;
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;
}
location /auth/ {
proxy_pass http://localhost:8000/auth/;
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;
}
location /storage/ {
proxy_pass http://localhost:8000/storage/;
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;
}
}
Step 3
Obtain SSL Certificate
Get a free SSL certificate from Let's Encrypt:
SSL Certificate
# Enable the site
sudo ln -s /etc/nginx/sites-available/supabase /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
# Obtain SSL certificate
sudo certbot --nginx -d your-domain.com
# Test automatic renewal
sudo certbot renew --dry-run
Monitoring and Maintenance
Step 1
Health Check Script
Create a script to monitor service health:
health-check.sh
#!/bin/bash
# Health check script for Supabase
echo "=== Supabase Health Check ==="
echo "Timestamp: $(date)"
# Check if all containers are running
echo "Checking container status..."
docker-compose ps
# Check database connectivity
echo "Checking database connectivity..."
docker-compose exec -T db pg_isready -U postgres
# Check API endpoints
echo "Checking API endpoints..."
curl -f http://localhost:8000/rest/v1/ > /dev/null 2>&1 && echo "REST API: OK" || echo "REST API: FAILED"
curl -f http://localhost:8000/auth/v1/health > /dev/null 2>&1 && echo "Auth API: OK" || echo "Auth API: FAILED"
# Check disk space
echo "Checking disk space..."
df -h /
# Check memory usage
echo "Checking memory usage..."
free -h
echo "=== Health Check Complete ==="
Step 2
Log Management
Set up log rotation and monitoring:
View and Manage Logs
# View logs for all services
docker-compose logs
# View logs for specific service
docker-compose logs db
docker-compose logs kong
docker-compose logs auth
# Follow logs in real-time
docker-compose logs -f
# Limit log output
docker-compose logs --tail=100
Step 3
Performance Monitoring
Monitor system performance and database stats:
Database Performance
# Connect to database and check stats
docker-compose exec db psql -U postgres -d postgres -c "
SELECT
schemaname,
tablename,
attname,
n_distinct,
correlation
FROM pg_stats
WHERE schemaname = 'public';"
# Check active connections
docker-compose exec db psql -U postgres -d postgres -c "
SELECT count(*) as active_connections
FROM pg_stat_activity
WHERE state = 'active';"
# Check database size
docker-compose exec db psql -U postgres -d postgres -c "
SELECT pg_size_pretty(pg_database_size('postgres')) as database_size;"
Backup Strategy
Health Check
To check if Supabase is healthy, just run:
docker-compose ps
If all services show Up, everything is working.
backup-volumes.sh
#!/bin/bash
# Volume backup script
BACKUP_DIR="/backups/volumes"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
# Stop services temporarily
docker-compose stop
# Backup volumes
docker run --rm -v supabase_db_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/db_data_$DATE.tar.gz -C /data .
docker run --rm -v supabase_storage_data:/data -v $BACKUP_DIR:/backup alpine tar czf /backup/storage_data_$DATE.tar.gz -C /data .
# Restart services
docker-compose start
# Remove old volume backups (keep 7 days)
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete
echo "Volume backup completed"
Step 3
Automated Backup Schedule
Set up cron jobs for automated backups:
Crontab Setup
# Edit crontab
crontab -e
# Add these lines for automated backups:
# Daily database backup at 2 AM
0 2 * * * /path/to/backup-database.sh
# Weekly volume backup on Sundays at 3 AM
0 3 * * 0 /path/to/backup-volumes.sh
# Daily health check at 6 AM
0 6 * * * /path/to/health-check.sh >> /var/log/supabase-health.log
Updating Supabase
Step 1
Check for Updates
Regularly check for Supabase updates:
Update Process
# Navigate to Supabase directory
cd ~/supabase-selfhosted/supabase/docker
# Check current version
git log --oneline -1
# Fetch latest changes
git fetch origin
# Check what's new
git log --oneline HEAD..origin/master
# Create backup before updating
./backup-database.sh
./backup-volumes.sh
Step 2
Perform Update
Update to the latest version:
Update Commands
# Stop services
docker-compose down
# Pull latest changes
git pull origin master
# Pull new Docker images
docker-compose pull
# Start with new images
docker-compose up -d
# Check if everything is working
docker-compose ps
./health-check.sh
Step 3
Rollback if Needed
If something goes wrong, rollback to previous version:
Rollback Process
# Stop services
docker-compose down
# Rollback to previous commit
git reset --hard HEAD~1
# Restore from backup if needed
docker-compose exec -T db psql -U postgres -c "DROP DATABASE IF EXISTS postgres;"
docker-compose exec -T db psql -U postgres -c "CREATE DATABASE postgres;"
zcat /backups/supabase/latest_backup.sql.gz | docker-compose exec -T db psql -U postgres postgres
# Start services
docker-compose up -d
Troubleshooting
Services Won't Start
Problem: Docker containers fail to start
Solutions:
- Check Docker daemon is running:
sudo systemctl status docker
- Verify port availability:
sudo netstat -tulpn | grep :8000
- Check disk space:
df -h
- Review logs:
docker-compose logs
- Restart Docker:
sudo systemctl restart docker
Database Connection Issues
Problem: Cannot connect to PostgreSQL
Solutions:
- Verify database container is running:
docker-compose ps db
- Check database logs:
docker-compose logs db
- Test connection:
docker-compose exec db pg_isready -U postgres
- Verify password in .env file
- Check firewall settings
SSL Certificate Issues
Problem: SSL certificate not working
Solutions:
- Verify domain DNS points to your server
- Check nginx configuration:
sudo nginx -t
- Renew certificate:
sudo certbot renew
- Check certificate status:
sudo certbot certificates
- Verify firewall allows ports 80 and 443
High Memory Usage
Problem: System running out of memory
Solutions:
- Increase server RAM
- Optimize PostgreSQL settings
- Add swap space:
sudo fallocate -l 2G /swapfile
- Monitor container usage:
docker stats
- Clean up old Docker images:
docker system prune
Performance Issues
Problem: Slow response times
Solutions:
- Add database indexes for frequently queried columns
- Increase PostgreSQL shared_buffers
- Use connection pooling
- Monitor slow queries:
pg_stat_statements
- Upgrade server hardware
- ✅ Complete data sovereignty and privacy
- ✅ Administrative dashboard
- ✅ SSL encryption and security
Step 1
Health Check Script
To check if Supabase is healthy, just make sure all Docker containers are running:
health-check.sh
#!/bin/bash
Security Reminder
Remember to regularly update your system, monitor logs, and maintain backups. Self-hosting requires ongoing maintenance and security vigilance.