Deploying Self-Hosted Supabase on Hetzner Cloud: A Complete Guide

Deploy self-hosted Supabase on Hetzner Cloud step by step: server sizing, Docker setup, firewall, SSL, and backups—with real costs and honest trade-offs.

Cover Image for Deploying Self-Hosted Supabase on Hetzner Cloud: A Complete Guide

Ask r/selfhosted where to run a self-hosted Supabase instance and one name comes up more than any other: Hetzner. The price-to-performance ratio is hard to argue with—4 GB of RAM and 2 vCPUs for under €4/month, roughly a third of what comparable instances cost on AWS or DigitalOcean. That's why we ranked it highly in our best VPS providers for self-hosted Supabase roundup.

But cheap compute is only the starting point. Between server sizing, firewall configuration, Docker setup, SSL, and backups, there are plenty of places to get stuck—and a few Hetzner-specific quirks worth knowing before you commit. This guide walks through a complete production deployment on Hetzner Cloud, flags what's changed in the self-hosted stack in 2026, and is honest about where Hetzner isn't the right choice.

Why Hetzner for Self-Hosted Supabase?

Hetzner is a German provider with data centers in Germany, Finland, Singapore, and the US (Ashburn, Virginia and Hillsboro, Oregon). Three things make it popular with self-hosters:

  • Price. A CX22 (2 vCPU, 4 GB RAM, 40 GB NVMe) runs about €3.79/month. The ARM-based CAX11 is similar. A CPX31 (4 vCPU, 8 GB RAM)—comfortable for production Supabase—is around €14/month. Equivalent AWS EC2 instances cost 3–5x more, as we broke down in our true cost of self-hosting Supabase analysis.
  • Included traffic. 20 TB of egress on most cloud plans. Egress fees are the silent killer on AWS and GCP; on Hetzner they're effectively a non-issue.
  • EU data residency. If GDPR compliance is one of your reasons for self-hosting, German or Finnish data centers with a European provider simplify the conversation considerably.

The honest trade-offs: Hetzner offers no managed databases, no object storage in US regions (Object Storage is currently EU-only), and support is ticket-based and lean. You're buying raw infrastructure, not a platform. New accounts also occasionally face identity verification holds—annoying, but it keeps abuse (and IP reputation problems) down.

Sizing Your Server

Supabase's self-hosted stack runs a dozen services: Postgres, GoTrue (auth), PostgREST, Realtime, Storage, Kong (the API gateway—more on that below), Studio, and supporting containers. Our system requirements guide covers the details, but as a Hetzner-specific cheat sheet:

Use caseHetzner planSpecs~Price
Dev / hobbyCX22 or CAX112 vCPU, 4 GB RAM€3.79/mo
Small productionCPX21 / CAX213–4 vCPU, 4–8 GB€8–9/mo
ProductionCPX31 / CAX314–8 vCPU, 8–16 GB€14–17/mo

Two notes. First, the CAX line is ARM64 (Ampere). Supabase's images support ARM64 well these days, and the price-per-core is excellent—but if you rely on obscure Postgres extensions, verify ARM builds exist before committing. Second, 4 GB is genuinely the floor; the full stack idles around 2.5–3 GB. If you're squeezing into a small instance, disable services you don't use—running only what you need can cut memory usage dramatically.

Step 1: Create the Server and Firewall

In the Hetzner Cloud console, create a server with Ubuntu 24.04, add your SSH key (never use password auth), and pick a location close to your users.

Before doing anything else, create a Hetzner Cloud Firewall and attach it to the server. This is a free, network-level firewall—use it instead of relying solely on ufw:

  • Allow inbound: TCP 22 (ideally restricted to your IP), TCP 80, TCP 443
  • Deny everything else, including 5432 and 8000

This one step prevents the most common self-hosted Supabase disaster: Postgres or the API gateway exposed directly to the internet. Automated scanners find open 5432 ports within hours. If you need direct database access, tunnel over SSH or use a private network—we covered the VPN approach in our Tailscale guide.

Step 2: Install Docker and Fetch Supabase

SSH in and install Docker from the official repository:

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER

Then pull the Supabase Docker setup:

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

Step 3: Configure Secrets (Don't Skip This)

The .env.example file ships with publicly known default credentials. Every value must be replaced before you start the stack:

# Generate strong secrets
openssl rand -base64 32   # POSTGRES_PASSWORD
openssl rand -base64 32   # JWT_SECRET (min 32 chars)

You'll also need to generate matching ANON_KEY and SERVICE_ROLE_KEY JWTs signed with your JWT_SECRET, plus set DASHBOARD_USERNAME and DASHBOARD_PASSWORD for Studio access. Set SITE_URL and API_EXTERNAL_URL to your real domain—we've covered how these values interact in our environment variables guide.

Two 2026-specific things to be aware of while you're in this file:

  1. Postgres 17 is now the default. As of June 2026, the upstream Docker Compose ships Postgres 17 instead of 15. Fresh deployments get 17 automatically; just don't blindly re-pull images on an existing 15-based deployment—major version upgrades need a dump/restore or pg_upgrade.
  2. Kong is being replaced by Envoy. Supabase has announced the default self-hosted API gateway switches from Kong to Envoy in August 2026. If you deploy today you'll likely get Kong; when you eventually upgrade, expect gateway configuration (custom routes, plugins) to need rework. If you've customized Kong heavily, pin your versions and plan the migration deliberately—we wrote a prep guide for this year's breaking changes.

Step 4: Start the Stack

docker compose pull
docker compose up -d
docker compose ps

All services should report healthy within a couple of minutes. If db is healthy but auth or rest are restarting, it's almost always a secrets mismatch—recheck your JWT configuration.

Step 5: Domain, SSL, and Reverse Proxy

Don't serve the API over a bare IP on port 8000. Point a domain at your server (an A record to the Hetzner IP), then put a reverse proxy in front with automatic TLS. Caddy is the least-effort option:

api.yourdomain.com {
    reverse_proxy localhost:8000
}

Caddy provisions and renews Let's Encrypt certificates automatically. Nginx and Traefik work fine too—our reverse proxy guide compares all three. Keep Studio off the public internet entirely, or at minimum behind additional auth; we covered the options in our guide to securing the Studio dashboard.

Step 6: Backups (Hetzner Snapshots Are Not Enough)

Hetzner offers server backups (7 rolling snapshots, +20% of the server price) and manual snapshots. Turn them on—they're cheap insurance. But treat them as disaster recovery for the server, not a database backup strategy:

  • Snapshots are crash-consistent, not application-consistent. Restoring a snapshot of a busy Postgres is roughly equivalent to recovering from a power failure.
  • They live in the same Hetzner project. An account compromise or billing lockout takes your backups with it.
  • Restore granularity is the whole server. You can't recover one project's database from Tuesday.

You still need proper logical backups (pg_dump), WAL archiving if you need point-in-time recovery, and—the piece almost everyone forgets—your Storage files, which live outside Postgres entirely. Ship them to an S3-compatible bucket outside Hetzner (Backblaze B2 and Cloudflare R2 are popular pairings; Hetzner's own Object Storage works if EU-only is acceptable). Our backup documentation covers the full setup.

Where Supascale Fits

Everything above is doable by hand—this guide proves it. The catch is that steps 3 through 6 are also where ongoing effort accumulates: rotating secrets, renewing certificates, verifying backups actually restore, and repeating all of it for every additional project on the box.

Supascale manages that layer for you on your own Hetzner server: it deploys projects with generated secrets, handles custom domains with automatic SSL, runs scheduled S3 backups (database and storage) with one-click restore, and lets you deploy only the services each project needs—which matters on a 4 GB Hetzner instance. It's a one-time $39.99 purchase with unlimited projects, so the economics stay aligned with why you chose Hetzner in the first place. The server is yours, the data is yours, and there's no lock-in.

Honest Trade-Offs

Hetzner + self-hosted Supabase is a great combination for cost-sensitive projects and EU data residency, but go in clear-eyed:

  • You're the ops team. Patching Ubuntu, monitoring disk space, and executing the Postgres 17 and Envoy migrations are on you.
  • Limited US/APAC footprint. Two US locations and one in Singapore; latency-sensitive apps elsewhere may need a different region strategy.
  • No managed anything. Unlike AWS, there's no RDS-style fallback if you decide self-managing Postgres isn't for you.
  • Single-node by default. This guide gives you one server. High availability requires meaningfully more architecture.

For most indie projects and small teams, none of these are dealbreakers—and the savings are real: a production-capable setup lands at €14–20/month all-in versus $25+ base plus per-project costs on managed platforms.

Conclusion

Hetzner is arguably the best-value home for a self-hosted Supabase instance in 2026: honest hardware, generous bandwidth, and EU residency at a price that makes multi-project self-hosting genuinely economical. The deployment itself is a well-trodden path—provision, firewall, Docker, secrets, reverse proxy—and the real work is what comes after: backups, SSL renewals, upgrades, and this year's Postgres and gateway transitions.

If you'd rather keep Hetzner's economics without carrying all of that operationally, Supascale turns your Hetzner server into a managed multi-project Supabase platform for a one-time $39.99. Either way: put the firewall up first, and test your restores before you need them.

Further Reading