Deployment guide

Hosting Supabase on a VPS in 2026

Deploy on a VPS Cloud →

Tutorial

Hosting Supabase on a VPS in 2026

Databases11 min read16 steps

Supabase is the open source alternative to Firebase built on PostgreSQL: database, authentication, storage, edge functions, and an auto-generated API. Since August 2026, the self-hosted stack has migrated from Kong to **Envoy Gateway** as its internal API proxy. Self-hosting on a VPS gives you a complete backend, with no project cap or usage-based billing, with your data in your own Postgres.

Contents· Why self-host Supabase on a VPS1/14
  1. 01Why self-host Supabase on a VPS
  2. 02Concrete benefits of a self-hosted Supabase
  3. 03Hardware and software requirements
  4. 04Deploy self-hosted Supabase with Docker
  5. 05Supabase vs Appwrite: which self-hosted BaaS to choose?
  6. 06Deploy from the official Supabase stack, not a homemade compose
  7. 07Back your instance up automatically
  8. 08Trimming the stack: the analytics service
  9. 09Kong→Envoy migration: what changes, and who it breaks
  10. 10Move to Envoy without breaking your gateway
  11. 11Kong and Envoy, point by point
  12. 12CVE-2026-31813: OIDC flaw in GoTrue — update now
  13. 13Update GoTrue to fix CVE-2026-31813
  14. 14Temporarily disable Social Auth if you cannot update immediately

Why self-host Supabase on a VPS

Supabase is not a black box: it is a set of open source services (PostgreSQL, GoTrue for auth, PostgREST for the API, Realtime, Storage, Kong as a gateway) orchestrated together. The cloud version bills per project and per monthly active user, and pauses inactive free projects. By self-hosting on a VPS, you get a complete backend-as-a-service without those limits, with direct access to your PostgreSQL for migrations, extensions (pgvector, PostGIS) and tuning. Ideal for an agency hosting several client apps, a bootstrapped SaaS looking to control costs, or any project requiring data sovereignty. You handle updates and backups yourself, in exchange for total freedom.

Concrete benefits of a self-hosted Supabase

  • Complete backend: Postgres, Auth, Storage, Realtime and REST/GraphQL API in one stack.
  • Direct access to the underlying PostgreSQL: SQL migrations, extensions and RLS policies without limits.
  • No pausing or billing per monthly active user.
  • Studio included: a web administration interface to manage tables, auth and buckets.
  • AI extensions via pgvector for RAG and semantic search, freely enabled.
  • Multi-projects on the same VPS: practical for an agency or development studio.

Hardware and software requirements

Self-hosted Supabase starts around ten containers (Postgres, Kong, GoTrue, PostgREST, Realtime, Storage, Studio, Meta, Imgproxy...), making it a more resource-intensive stack than a plain database. Count a minimum of 2 vCPU and 4 GB of RAM for a test environment, and prefer 4 vCPU with 8 GB of RAM and 80 GB of SSD for production. On the software side: Ubuntu 22.04/24.04 LTS, Docker and Docker Compose v2, a domain name pointing to the VPS (e.g. api.myapp.com) to expose the gateway over HTTPS, and a reverse proxy such as Caddy, Traefik or Nginx to handle SSL. Also plan to generate strong secrets (JWT_SECRET, anon and service_role keys).

Deploy self-hosted Supabase with Docker

  1. Clone the official repository and prepare the environment

    Fetch the docker folder from the Supabase repository, copy .env.example to .env, then generate unique secrets: POSTGRES_PASSWORD, JWT_SECRET, and the ANON_KEY / SERVICE_ROLE_KEY keys derived from the JWT. Never deploy with the example values.

  2. Configure URLs and the Studio password

    In .env, set SITE_URL, API_EXTERNAL_URL and SUPABASE_PUBLIC_URL with your domain, and secure Supabase Studio with DASHBOARD_USERNAME and DASHBOARD_PASSWORD: Studio gives full admin access to your project.

  3. Launch the stack

    Start with docker compose up -d, then follow service startup via docker compose ps. The first Postgres initialisation and internal migration application take one to two minutes; check for the absence of errors in docker compose logs.

  4. Place a reverse proxy with SSL

    Put Caddy or Traefik in front of Kong (the gateway's port 8000) to expose your API over HTTPS. Caddy automatically obtains and renews Let's Encrypt certificates: a simple myapp.com { reverse_proxy localhost:8000 } block is enough. Never expose Postgres (5432) publicly.

  5. Enable RLS policies

    Connect to Studio, create your tables, then enable Row Level Security on each one and define your policies. Without RLS, your anon key exposes all your data: this is the setting to configure before exposing anything.

  6. Back up Postgres and Storage

    Schedule a daily pg_dump of the database and archive the Storage volume (file buckets) to external storage. Test a full restoration on a staging VPS before relying on it in production.

Supabase vs Appwrite: which self-hosted BaaS to choose?

Scroll the table

CriterionSupabaseAppwrite
DatabaseNative PostgreSQL, full SQLMariaDB internally, document/collection API
Data modelRelational, Postgres RLSDocuments and collections, rule-based permissions
Auto-generated APIREST (PostgREST) + GraphQLREST, GraphQL and multiple SDKs
AuthenticationGoTrue, OAuth, magic linksIntegrated auth, OAuth, teams, JWT
Resource footprintHeavier (~10 containers)Moderate, more compact stack
Vector search / AINative via pgvectorNot native, must be externalised
Best forRelational apps, RAG, advanced SQLMobile/web apps oriented around documents
Learning curveComfortable if you know SQLFast for front/mobile developers

Update Supabase with care: since images are versioned in docker-compose.yml, always do a full pg_dump and a VPS snapshot before a docker compose pull && docker compose up -d. Some version bumps touch the internal service schema. For production, isolate Postgres on a dedicated high-IOPS volume and enable pgvector from the start if you plan on semantic search: adding it later requires a schema migration.

Deploy from the official Supabase stack, not a homemade compose

It is tempting to write a minimal docker-compose with only the few services you need. In practice, this breaks: the supabase/postgres image runs its own migration script (migrate.sh) that provisions the base roles (supabase_admin, authenticator, supabase_auth_admin...) and the entire auth schema, and expects Supabase SQL initialisation files to be mounted as files with variable expansion at run time. A standalone inline compose cannot reproduce this (Docker Compose interpolates variables inside inline configs, leaving the auth schema half-migrated and GoTrue failing with 'must be owner of function auth.uid()'). The robust approach — the one ServOrbit uses — is to deploy the official Supabase Docker files, pinned to a specific version, and let migrate.sh do the bootstrapping exactly as upstream intends.

Back your instance up automatically

Supabase's Docker deployment backs up nothing on its own — it is the gap self-hosters report most. Two mechanisms complement each other. The first, pg_dump, produces a full logical copy: run it from the host on a cron, write it to a volume separate from the database's own, and keep several generations. The second, WAL archiving, journals every transaction and lets you rewind to a precise moment rather than to the last dump. The first is enough for most projects; the second becomes necessary as soon as losing a day of writes is unacceptable. Either way, a backup is only worth what a restore proves: spin up a blank instance and replay your dump into it before you actually need to.

Trimming the stack: the analytics service

The official Docker composition ships Logflare, Supabase's built-in analytics service, under the name analytics. It is required by neither the API, nor auth, nor storage — it is an observability tool. On a resource-tight VPS it commonly reports unhealthy without the rest of the stack suffering, and many self-hosters end up commenting it out of their docker-compose.yml. Measure what it actually costs you with docker stats before deciding: if your monitoring already runs through an external tool you lose nothing; if you were relying on its logs, disable it only once a replacement is wired in.

Kong→Envoy migration: what changes, and who it breaks

In the week of 9 August 2026, Supabase made Envoy the default API gateway for self-hosted installations; Kong moves to an optional override. Envoy had already shipped for several releases via docker-compose.envoy.yml — what changes is the default.

In docker-compose.yml the service is now called api-gw and the container supabase-envoy, but the kong network alias is kept: services that call the gateway by that name keep working. The HTTP port stays 8000, set through API_GW_HTTP_PORT, so your Caddy or Nginx reverse proxy needs no change.

⚠️ Supabase calls this a breaking change for a SUBSET of self-hosters, and you need to know whether you are one. Three cases: you relied on Kong's built-in HTTPS port 8443 — it is no longer shipped by default, TLS termination now goes through docker-compose.caddy.yml or docker-compose.nginx.yml; you had a customised volumes/api/kong.yml — routes and plugins must be ported to the Envoy configuration, which lives in volumes/api/envoy/; your scripts reference the gateway by service name. In all three cases you can also stay on Kong: sh run.sh config add kong.

Move to Envoy without breaking your gateway

  1. Find out what you are running

    Run docker compose ps. A supabase-kong container means you are still on Kong; supabase-envoy means the switch is done. Also check whether volumes/api/kong.yml differs from the repository's — that file decides whether the migration costs you any work.

  2. Back up before touching the compose file

    Take a full pg_dump and, if your host allows it, a VPS snapshot. Switching gateway does not touch the PostgreSQL schema, but it changes the entry path of every request: a fast rollback beats a live diagnosis.

  3. Decide: port or stay

    If your kong.yml is the repository's, there is nothing to port. If it holds routes or plugins of your own, two paths: translate them into Envoy configuration under volumes/api/envoy/, or stay on Kong with sh run.sh config add kong while you do. Staying is a legitimate decision, not a failure.

  4. Pull the new compose and restart

    Pull the latest docker folder from the official Supabase repository, then docker compose down && docker compose up -d. Check that api-gw reaches healthy and that the API answers on port 8000.

  5. Restore TLS if you relied on Kong's 8443

    The built-in HTTPS port is no longer shipped. Add TLS termination with docker-compose.caddy.yml or docker-compose.nginx.yml, or let your existing reverse proxy handle it in front of port 8000. This is the most common breakage, and it only shows on the first direct HTTPS call.

  6. Check storage and signed URLs

    Test a download from a private bucket through a pre-signed URL. If you get a 403 after the switch, look first at Host header rewriting and at your storage service's public URL setting: that is where the two gateways differ.

Kong and Envoy, point by point

Scroll the table

AspectKong (before August 2026)Envoy (default since)
Service in `docker-compose.yml``kong``api-gw` — `kong` kept as a network alias
Container`supabase-kong``supabase-envoy`
HTTP port80008000 — via `API_GW_HTTP_PORT`
Built-in HTTPS port8443**removed** — TLS via `docker-compose.caddy.yml` / `.nginx.yml`
Configuration`volumes/api/kong.yml``volumes/api/envoy/` (versioned YAML)
Opting back out`sh run.sh config add kong`

CVE-2026-31813: OIDC flaw in GoTrue — update now

A vulnerability was disclosed in 2026 in GoTrue (Supabase's authentication service) under the reference CVE-2026-31813. The flaw lies in the validation of the iss claim during OIDC authentication: a JWT signed by a third-party identity provider (Apple or Azure) but with an iss different from the one configured in GoTrue was accepted under certain configuration conditions.

In practice, an attacker who controls an OIDC provider registered in the client application can issue valid tokens for arbitrary users on your Supabase instance. The actual scope depends on configuration: only instances with at least one third-party OAuth provider enabled (Social Auth) are affected. Instances using only email/password authentication or magic links are not exposed.

The fix is included in Supabase Auth (GoTrue) 2.185.0. To check your version: docker compose exec auth gotrue version. If your gotrue version is below 2.185.0, update immediately.

Update GoTrue to fix CVE-2026-31813

  1. Identify the current version

    From your Supabase stack directory: docker compose exec auth gotrue version. If the output shows a version < 2.185.0, your instance is exposed to CVE-2026-31813. Also note the overall stack version: grep 'SUPABASE_VERSION' .env (if pinned) or docker compose images | grep supabase.

  2. Back up before updating

    Before any update, back up the database: docker compose exec db pg_dumpall -U postgres > /tmp/supabase-backup-$(date +%F).sql. Updating GoTrue does not involve a PostgreSQL schema migration, but a prior backup remains the rule before any version change in production.

  3. Update Supabase Auth to 2.185.0 or newer

    In your docker-compose.yml, update the supabase/gotrue image tag to v2.185.0 or newer, or if following the full stack, pull the latest compatible version: docker compose pull && docker compose up -d auth. Updating GoTrue alone does not require restarting other services. Verify with docker compose exec auth gotrue version that the new version is active.

  4. Verify OIDC authentication

    After the update, test a complete authentication flow with each configured OIDC provider : login, logout, re-login. Check in GoTrue logs (docker compose logs auth) that no error messages related to iss validation appear under normal usage conditions.

Temporarily disable Social Auth if you cannot update immediately

If an immediate update is not possible (maintenance window required), you can reduce the attack surface by temporarily disabling third-party OAuth providers in Supabase Studio: Authentication → Providers, then disable each Social provider. Email/password authentication remains functional. This workaround is temporary: it does not fix the vulnerability, it only reduces the attack surface while you prepare the update.

Self-host your Supabase backend

The ServOrbit Cloud VPS with a preconfigured Docker template and generous RAM hosts the entire Supabase stack: Postgres, Auth, Storage, and API over HTTPS.

Need help?

Browse our help center and FAQ, or reach our team — callback, WhatsApp or email. Support in French, English and Arabic.

Message us on WhatsAppopens in a new tab