How to install Supabase on a VPS
Supabase packages PostgreSQL with authentication, APIs, storage and a dashboard for application backends. Its self-hosted deployment is a multi-service Docker stack, so this guide focuses on using the official Compose files, protecting secrets and exposing only the public gateway.
Prerequisites
Choose Ubuntu 22.04 or 24.04 with SSH, a public IP and a dedicated domain such as api.example.com. Official minimums are 4 GB RAM minimum (8 GB recommended), 2+ CPU cores, 40+ GB SSD. A development installation can use a modest machine, while production needs room for PostgreSQL, logs, storage and migrations.
You need Docker Compose, a secure way to generate secrets and storage outside the VPS for backups. Supabase self-hosting assumes that you can maintain the operating system and database. It is not a managed database service.
Step 1, Connecting to your server
Connect and create a protected working directory:
ssh root@SERVER_IP
apt update && apt upgrade -y
apt install -y ca-certificates curl git
mkdir -p /opt/supabase
cd /opt/supabase
chmod 750 /opt/supabaseOpen only SSH, HTTP and HTTPS at the provider level. Avoid installing another reverse proxy or PostgreSQL instance until you understand the ports used by the official stack.
Step 2, Installing Docker and Docker Compose
Install Docker Engine and the Compose plugin using Docker's official Ubuntu instructions. Verify them:
docker --version
docker compose version
systemctl enable --now dockerCheck available disk and memory before pulling images:
df -h
free -hStep 3, Running the official Supabase stack
Supabase maintains the self-hosted Docker configuration in its official repository. The recommended way to start is the official setup script:
curl -fsSL https://supabase.link/setup.sh | shAlternatively, clone the repository manually:
git clone --depth 1 https://github.com/supabase/supabase.git source
cd source/docker
cp .env.example .envSecrets and JWT keys
Supabase now uses asymmetric JWT key pairs instead of a single JWT_SECRET. After cloning, generate the required keys with the included helper scripts:
./docker/utils/generate-keys.sh
./docker/utils/add-new-auth-keys.shThese scripts create the RSA keypair for JWT signing and add the new keys to the auth configuration. The files docker/volumes/api/kong.yml manages the Gateway and docker/volumes/db/init/ handles the database.
Critical environment variables
Open .env and replace every placeholder value. The default .env.example values are DANGEROUS and must never be used in production.
| Variable | Requirements |
|---|---|
DASHBOARD_PASSWORD |
Must contain at least one letter (numbers-only passwords are rejected) |
POSTGRES_PASSWORD |
Use letters and numbers only to avoid URL-encoding issues |
All other placeholder values in .env must also be replaced with unique generated values. Never publish the file.
Windows users: If you clone the repository on Windows, ensure line endings are LF (Unix style). CRLF line endings break the Kong Gateway entrypoint. Use
git config --global core.autocrlf falsebefore cloning, or convert withdos2unix.
Validate the complete official project before starting it:
docker compose config
docker compose pull
docker compose up -d
docker compose psThe official Compose file is the example deployment for this guide. Do not replace it with a short custom file, because removing a gateway, migration or storage service can produce a partially working backend.
Step 4, Configuring the reverse proxy
Supabase ships official Caddy and Nginx override files. Enable them with:
sh run.sh config add caddy
# or
sh run.sh config add nginxRoute api.example.com to the gateway's localhost port from the official Compose file. Update these variables in .env to match your domain:
SUPABASE_PUBLIC_URL=https://api.example.com
API_EXTERNAL_URL=https://api.example.com
SITE_URL=https://api.example.comTerminate TLS at the proxy, forward the original host and protocol headers and keep PostgreSQL and internal services private. If Studio is needed remotely, protect it with the access method documented for your version instead of opening every container port.
WebSocket: Supabase Realtime requires WebSocket support in your proxy. Ensure your reverse proxy configuration allows WebSocket upgrades (Caddy does by default; Nginx needs explicit
proxy_set_header Upgrade $http_upgradeandproxy_set_header Connection "upgrade").
Test the HTTPS endpoint, an authenticated API request and a storage operation. A valid dashboard page alone does not prove that database migrations, authentication or object storage are healthy.
Step 5, First access and initial setup
Open the Studio address through the protected route and sign in with the credentials configured in .env. Create a test project or use the default project only for evaluation. Record the project URL and public anonymous key in your application configuration, but keep service-role keys on the server.
Create a table, apply a migration and test authentication from a disposable application. Confirm that row-level security is enabled where it should be. Never use a service-role key in browser code.
Maintenance
Back up PostgreSQL, storage objects and all environment secrets. Review the upstream release notes before updating the repository and images. Take a database snapshot before migrations, run the update in a maintenance window and verify auth, APIs and storage afterward.
Monitor database connections, disk, object storage, gateway errors and container health. If a service fails, collect docker compose ps, the service logs and the effective Compose configuration before restarting or deleting anything.
Tools mentioned
Supabase
โPostgres backend with database, auth, storage, realtime and edge functions.
2 projects, 500 MB database, 1 GB storage, 5 GB egress and 50,000 monthly active users.