Why I Self-Host My SaaS Apps on Hetzner

Boon aka Hwee-Boon Yar April 7, 2026
Source
Update, May 21, 2026: I have moved more projects since writing this. My main products and most older projects now run on Hetzner + Kamal. A few projects are still exceptions, but Hetzner is the default now. I also published a newer cost breakdown: Hetzner vs Vercel: What I Pay to Run My SaaS Apps. I run my SaaS apps on Hetzner with Kamal. I used Heroku years ago, then Render for a couple of years. Both were fine for deployment. I switched to self-hosting for cost, control, and performance. COST My base Hetzner bill is low enough that I can run multiple apps with PostgreSQL, background workers, and the whole stack on small ARM servers without thinking about per-project hosting cost. The cost stays flat. More traffic doesn't change my bill — I'm paying for the server, not per-request or per-seat. If I need more capacity, I bump to the next server tier. Still cheaper than any PaaS. CONTROL On my server, I pick the OS, the Docker version, the PostgreSQL config, the backup schedule, the firewall rules. And I make those decisions once — they're encoded in Terraform and Kamal configs. Spinning up a new project is the same setup, same commands. I'm not dependent on a platform's roadmap or pricing decisions. PERFORMANCE My app and database run on the same machine. Database queries are sub-millisecond — no network hop. On most PaaS setups, the database is a separate service with network overhead on every query. A small Hetzner ARM server gives me dedicated vCPUs and RAM. DEVOPS IN 2026 Setting up a server in 2015 meant configuring Nginx, managing SSL certificates by hand, writing systemd service files, and hoping you didn't miss a security update. Now it's Docker and Kamal. I define my app in a Dockerfile, my infrastructure in Terraform, and my deployment in a Kamal config. One command provisions the server. One command deploys the app. SSL is automatic via Let's Encrypt through kamal-proxy. I spend maybe 30 minutes a month on maintenance — OS updates, checking disk space, reviewing logs. My Telegram bot pings me if anything needs attention. SCALING A single Hetzner ARM server handles far more traffic than most indie SaaS apps will see. PostgreSQL on one server can do thousands of queries per second. If I outgrow one server — a great problem to have — Kamal supports multi-server deployments. Move the database to its own box, add a second web server, and kamal-proxy load-balances between them. WHAT I SELF-HOST (AND DON'T) * My main products and most older projects — Vue frontends, Fastify APIs, PostgreSQL, background workers * Automated daily PostgreSQL dumps to object storage * Monitoring via Uptime Robot and PostHog What I don't self-host: * This blog — Jekyll on GitHub Pages, because it's static and free * Email — transactional email goes through a service. Self-hosting email is a deliverability nightmare * CDN/edge — Cloudflare sits in front of the server for caching and DDoS protection GETTING STARTED I wrote about the specific tools in detail: * Terraform setup — provision a Hetzner server with four files * Kamal deployment — zero-downtime deploys with one command The whole thing took about two days the first time. Subsequent projects take an hour or two — and most of that time is setting up API keys for external services, not the hosting itself. After that, every deploy is kamal deploy.

Discussion in the ATmosphere

Loading comments...