Supabase is an open-source Firebase alternative built on PostgreSQL: a Postgres database with auto-generated REST and GraphQL APIs, authentication, row-level security, realtime subscriptions, file storage and edge functions, managed through the Studio dashboard. The hosted platform is popular, and the same stack can be self-hosted with Docker.

Lighter alternatives: PocketBase (a single binary) and Appwrite.

What you get (the containers)

Service Role
PostgreSQL The database (with Supabase extensions)
Kong API gateway, the single entry point
GoTrue (auth) Users, sessions, OAuth, magic links
PostgREST Auto-generated REST API from your schema
Realtime Changes over WebSockets
Storage + imgproxy Files with access policies, image transforms
Studio Admin dashboard
Edge runtime Deno functions
Supavisor / Meta / Analytics Pooling, metadata API, logs

Requirements

  • 4 GB RAM minimum (8 GB recommended), 2+ vCPU and SSD storage.
  • Docker and Docker Compose. See install Docker.
  • A domain with HTTPS (a reverse proxy in front of Kong).

Setup

git clone --depth 1 https://github.com/supabase/supabase /opt/supabase-src
mkdir -p /opt/supabase && cp -r /opt/supabase-src/docker/* /opt/supabase/
cp /opt/supabase-src/docker/.env.example /opt/supabase/.env
cd /opt/supabase

Generate secrets, before the first start

Edit .env and set at least:

  • POSTGRES_PASSWORD: a strong password;
  • JWT_SECRET: at least 32 random characters;
  • ANON_KEY and SERVICE_ROLE_KEY: JWTs signed with your JWT_SECRET (the Supabase self-hosting docs include a generator). Don’t keep the example keys;
  • DASHBOARD_USERNAME / DASHBOARD_PASSWORD: protects Studio through Kong basic auth;
  • SITE_URL (your app’s URL) and API_EXTERNAL_URL / SUPABASE_PUBLIC_URL (e.g. https://supabase.example.com);
  • SMTP settings (SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_ADMIN_EMAIL) for auth emails. See transactional email services.
docker compose pull
docker compose up -d
docker compose ps

Never expose the SERVICE_ROLE_KEY to browsers. It bypasses row-level security. Use it only on servers. See secrets management.

Reverse proxy and HTTPS

Kong listens on port 8000. Bind it to localhost (edit the compose port mapping), and put Nginx in front:

server {
    server_name supabase.example.com;
    client_max_body_size 100M;
    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-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    # listen 443 ssl; certbot --nginx -d supabase.example.com
}

Restrict Studio further (VPN or an IP allow-list) if possible. See Nginx WebSocket proxy and zero trust networking.

Don’t publish PostgreSQL’s port (5432) or the pooler to the internet unless needed, and then with strong passwords, TLS and a firewall allow-list.

Row-level security: the key concept

Supabase clients query Postgres directly through PostgREST using the anon key, so security lives in Postgres policies:

alter table notes enable row level security;
create policy "own notes" on notes
  for all using (auth.uid() = user_id) with check (auth.uid() = user_id);

Every table exposed to clients needs RLS enabled, plus appropriate policies. Studio warns you about tables without RLS.

Backups

Self-hosting means you handle backups (the cloud has managed ones):

docker compose exec -T db pg_dumpall -U postgres | gzip > /backups/supabase-$(date +%F).sql.gz

Also back up the storage volume (files) and .env. For point-in-time recovery, use WAL archiving with pgBackRest or WAL-G. See pgBackRest and backup strategy.

Self-hosted vs the cloud

Self-hosted Supabase Cloud
Cost Server only Free tier, then usage-based
Backups, PITR, upgrades You Managed
Branching, some dashboard features Limited Full
Data location and control Full Provider regions

Updates

Pull the latest docker/ folder from the repository, compare it with your docker-compose.yml and .env, then docker compose pull && docker compose up -d. Major Postgres version changes need dump and restore or pg_upgrade. See updating self-hosted apps.

Quick reference

Item Value
Gateway (Kong) port 8000
Studio login DASHBOARD_USERNAME / DASHBOARD_PASSWORD
Client key ANON_KEY (safe in browsers with RLS)
Server key SERVICE_ROLE_KEY (never in browsers)
Backup pg_dumpall + storage volume + .env

Related: PostgreSQL monitoring and JWT explained.

  • Self-Hosting
  • PostgreSQL
  • Docker