Skip to content
appsgit

Deploy guide

How to self-host Supabase with Docker Compose

Supabase Docker Compose setup with the official self-hosting files: hardware needs, generated keys, Studio login, HTTPS via the Caddy overlay, backups, updates.

  • Updated
  • Intermediate
  • About 30 minutes

You will need

  • 2 vCPU / 4 GB RAM minimum (4 vCPU / 8 GB+ recommended)
  • 40 GB+ SSD storage
  • Docker + Docker Compose v2, git and openssl
  • A domain name pointing at the server

What is Supabase?

Supabase is an open source backend platform built on PostgreSQL. One stack gives you a Postgres database, auto-generated REST and GraphQL APIs, authentication, file storage, realtime subscriptions, edge functions and a web dashboard called Studio. It is the best-known open source alternative to Firebase and is licensed under Apache-2.0.

Be clear about the size before you start: self-hosted Supabase is not one container. The official stack runs around ten services (Studio, an Envoy API gateway, Auth, PostgREST, Realtime, Storage, imgproxy, postgres-meta, Edge Runtime, Supavisor and Postgres itself), and you are responsible for securing, backing up and upgrading all of it.

Requirements

  • From the official docs: at least 4 GB of RAM, 2 CPU cores and a 40 GB SSD. The recommendation is 8 GB or more, 4 cores and 80 GB or more.
  • Docker Engine, Docker Compose v2, git and openssl.
  • A domain with an A record for the server, for HTTPS.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed from the official Docker Engine guide. Supabase versions its self-hosting files with self-hosted/vX.Y.Z tags; pin one rather than tracking master:

git clone --depth 1 --branch self-hosted/v0.8.2 https://github.com/supabase/supabase
mkdir supabase-project
cp -rf supabase/docker/. supabase-project
cd supabase-project
cp .env.example .env
printf 'ref=self-hosted/v0.8.2\n' > .supabase-version

Supabase also offers a one-line installer (setup.sh) that does the same thing, but the manual route shows you exactly what lands on the server.

Step 2: Create the Docker Compose file

You do not write this Compose file by hand. The cloned docker-compose.yml is the official stack, with every image pinned to a tested version, and .env drives all of it. The important part is replacing every default secret before the first start. The example file warns that all of them must change, and the repo ships scripts that generate them:

sh utils/generate-keys.sh --update-env
sh utils/add-new-auth-keys.sh --update-env

The first script writes POSTGRES_PASSWORD, JWT_SECRET, the legacy ANON_KEY and SERVICE_ROLE_KEY, SECRET_KEY_BASE, VAULT_ENC_KEY, REALTIME_DB_ENC_KEY, PG_META_CRYPTO_KEY, DASHBOARD_PASSWORD and the Logflare and storage keys. The second derives the newer SUPABASE_PUBLISHABLE_KEY and SUPABASE_SECRET_KEY from the JWT secret. If you would rather set a value yourself, use openssl rand -hex 32 for 64-character secrets.

Then edit .env and set the public URLs:

SUPABASE_PUBLIC_URL=https://supabase.example.com
API_EXTERNAL_URL=https://supabase.example.com
SITE_URL=https://app.example.com
DASHBOARD_USERNAME=CHANGE_ME

SITE_URL is where your front end runs; Auth uses it for email links. Treat SUPABASE_SECRET_KEY and SERVICE_ROLE_KEY like database root passwords: they bypass row-level security and must never ship in client code.

Step 3: Start and open the app

docker compose pull
docker compose up -d
docker compose ps

The first pull is several gigabytes. Wait until every service reports healthy, then open http://YOUR_SERVER_IP:8000 and sign in with DASHBOARD_USERNAME and DASHBOARD_PASSWORD. Run sh run.sh secrets to see them again. In Studio, create a table, add a row-level security policy and copy the API URL and publishable key into your app.

Step 4: Put it behind HTTPS

The repo includes an official Caddy overlay that terminates TLS for your domain, removes the gateway's public port 8000 and protects Studio with the dashboard credentials. Set these in .env:

COMPOSE_FILE=docker-compose.yml:docker-compose.caddy.yml
PROXY_DOMAIN=supabase.example.com

Then run docker compose up -d. Caddy fetches a Let's Encrypt certificate and routes /auth/v1, /rest/v1, /storage/v1, /realtime/v1 and /functions/v1 to the API and everything else to Studio.

Supavisor still publishes Postgres on 5432 and 6543 on all interfaces. Docker-published ports bypass ufw, so block them in your cloud provider's firewall, or only allow your own IPs, unless your apps connect to the database directly from outside the server.

Backups and upgrades

Database dumps are the core of your backup:

docker compose exec -T db pg_dumpall -U supabase_admin > supabase-$(date +%F).sql

Also back up .env and volumes/storage (uploaded files). Without .env your JWT secret and encryption keys are gone, and existing tokens and encrypted values become unusable.

To update, read the self-hosted changelog, then run the bundled script, which merges new vendor files and adds missing .env keys without overwriting your values:

sh update.sh

Troubleshooting

  • A service keeps restarting: run docker compose logs <service>. Most first-start failures are placeholder secrets or a .env value with the wrong length.
  • "Invalid API key" from the client libraries: the keys were regenerated after the containers started. Run docker compose up -d --force-recreate.
  • Auth emails link to localhost: SITE_URL and API_EXTERNAL_URL still have their defaults.
  • Server runs out of memory: stop optional services you do not use, or move to the recommended 8 GB.

Next steps

Set SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS and SMTP_ADMIN_EMAIL in .env so Auth can send real emails, switch storage to S3 with the S3 overlay, schedule nightly pg_dumpall runs with off-site copies, and enable only the auth providers your app needs.

Spotted something out of date? Tell us and we will update the guide.

FAQ

Supabase questions

Still curious? Email info@appsgit.com.

What port does self-hosted Supabase use?

The API gateway listens on port 8000, which serves both Supabase Studio and the REST, Auth, Storage, Realtime and Functions APIs. Supavisor publishes Postgres on 5432 (session mode) and 6543 (transaction pooling).

What is the default Supabase Studio login?

Studio is protected by HTTP basic authentication using DASHBOARD_USERNAME and DASHBOARD_PASSWORD from .env. The example file ships placeholder values, so generate new ones before the first start; run sh run.sh secrets to see the current credentials.

How much RAM does self-hosted Supabase need?

Supabase's docs list 4 GB of RAM, 2 CPU cores and a 40 GB SSD as the minimum, and recommend 8 GB, 4 cores and 80 GB or more. The stack runs around ten containers, so it is much heavier than a single Postgres database.

Is self-hosted Supabase free?

Yes. Supabase is open source under the Apache-2.0 license and the self-hosted stack has no license fee. Supabase Cloud adds managed backups, branching and support, with a free tier and paid plans.

What is missing in self-hosted Supabase compared to Supabase Cloud?

Self-hosted Supabase has one project per stack, and you operate backups, scaling, upgrades and monitoring yourself. Some platform features, such as managed point-in-time recovery and multiple projects in one dashboard, are Cloud-only.

Supabase vs Firebase?

Supabase is built on PostgreSQL, so you get SQL, relations, row-level security and a database you can self-host or move anywhere. Firebase is a proprietary Google service built on NoSQL document stores. Supabase is the usual open source Firebase alternative.