Skip to content
<-- back
| 7 min | antonio maiolo
// devops, kubernetes, architecture, infrastructure

Germany Doesn't Have a Heroku — So I Built My Own on Hetzner

I needed to host Noidoc.de in Germany. GDPR compliance — data had to stay on German soil, with a German hoster. Requirements were straightforward: a scalable backend, PostgreSQL, Redis, and deploys that don’t require SSH-ing into a server. Should be a solved problem in 2026.

It isn’t. Not really. Coming from Railway or Render, where you git push and get a running app with managed Postgres, managed Redis, automatic deploys, and logs in a dashboard — I expected a German equivalent. I looked. I didn’t find one that covered the full stack.

So I built my own platform on Hetzner with k3s. A weekend of setup, months of payoff. Here’s how it went and what I’d do differently.

The German PaaS Gap

German PaaS options exist. IONOS Deploy Now, Sliplane, Cloudfleet, Open Telekom Cloud — real products with real customers. None of them give you the complete integrated experience.

PlatformGit-push deployManaged DBManaged RedisIntegrated loggingGerman hoster
HerokuYesYesYesYesVia Private Spaces
RailwayYesYesYesYesEU available
IONOS Deploy NowStatic/PHP/SPAMariaDB (PHP only)NoNoYes
SliplaneContainersYes (self-hosted)Via containersBasicYes
CloudfleetNo (CI/CD needed)BYOBYOBasicYes
Open Telekom CloudEnterprise cloudYesYesYesYes

The gap isn’t existence — it’s integration. You can piece together a stack from German services, but nobody gives you the “push and forget” experience. Heroku’s Frankfurt region requires Private Spaces (read: enterprise pricing — minimum ~$1,000/month). Railway has EU regions (Amsterdam) but no German-specific data residency guarantees. Sliplane gets closer than most — 1-click presets for PostgreSQL, MySQL, MariaDB, and MongoDB, and you can run Redis as a container — but it’s self-hosted containers, not fully managed services. Cloudfleet is managed Kubernetes, not a PaaS — you’re setting up your own CI/CD pipelines, not doing git push. Open Telekom Cloud has managed everything but it’s an enterprise cloud platform, not something you spin up for a side project on a Saturday afternoon. The moment you need managed DB plus managed Redis plus logging plus git-push deploys from a German hoster at startup-friendly prices, you’re assembling it yourself.

Why k3s and Not the Real Thing

Full Kubernetes — EKS, GKE, managed k8s — is overkill when your project fits on two servers. The operational overhead alone costs more than the infrastructure. k3s strips Kubernetes down to a single binary. Same kubectl commands, same manifests, same ecosystem. Just less ceremony and less RAM.

hetzner-k3s made the setup almost too easy. One config file, one command, and you have a cluster running on Hetzner Cloud:

# hetzner-k3s cluster config
cluster_name: noidoc
kubeconfig_path: "./kubeconfig"
k3s_version: v1.31.4+k3s1
networking:
  ssh:
    port: 22
    use_agent: false
  allowed_networks:
    ssh:
      - 0.0.0.0/0
    api:
      - 0.0.0.0/0
masters_pool:
  instance_type: cpx21
  instance_count: 1
  location: fsn1

Run hetzner-k3s create --config cluster.yaml and you get a kubeconfig. That’s it. Add worker nodes later when you need to scale — change a number in the config and re-run. No Terraform modules, no CloudFormation stacks, no 200-line bash scripts.

Git Push, Docker Build, kubectl Apply

The CI/CD pipeline is GitHub Actions doing what it does best. Push to main, build a Docker image, push to a registry, kubectl set image, done. Because k3s speaks standard kubectl, any Kubernetes GitHub Action works out of the box. No vendor-specific tooling, no ArgoCD, no custom deploy scripts. A rolling update with automatic rollback if the health check fails.

The part Heroku abstracts away: wiring auth. You base64-encode the kubeconfig, store it as a GitHub secret, and reference it in the workflow. Not hard, but it’s the kind of plumbing PaaS handles for you. Wire it once, forget about it.

Observability You’d Actually Miss

Running your own infrastructure without observability is flying blind. The whole promise of PaaS is that someone else watches the dashboards. If you’re DIY, you need your own — and the Kubernetes ecosystem makes this surprisingly painless.

The stack: Loki for log aggregation, Promtail for log shipping, Prometheus for metrics, Grafana for dashboards. All deployed via Helm charts — grafana/loki-stack and prometheus-community/kube-prometheus-stack — on the same k3s cluster. Four Helm commands total.

The observability stack is not lightweight. Expect it to consume 2-3GB of RAM, especially Prometheus and Loki. I run it on a dedicated node so it doesn’t compete with the application for resources. The payoff justifies the overhead: query logs across all services with LogQL, set up Slack alerts for error rate spikes, see CPU and memory trends before they become outages. Better visibility than most PaaS dashboards.

The lesson that arrived as a storage alert at 2am: kube-prometheus-stack auto-discovers and scrapes every service in the cluster. Default retention is 15 days. On a small cluster generating modest metrics, my 20GB volume hit 90% in two weeks. Set --storage.tsdb.retention.time=7d and be deliberate about scrape targets. Self-managed infrastructure means self-managed alerting — if you don’t monitor the monitoring, nobody will.

The Real Cost

The math is the strongest argument for this setup.

Hetzner + k3sHerokuRailway
Monthly cost (small project)~20 EUR~50 USD~30 USD
Setup timeWeekend30 minutes30 minutes
Ongoing maintenance1-2 hrs/monthZeroZero
ScalingAdd nodes in configSliderAutomatic
Data residencyGermanyUS/EU (Private Spaces for DE)US/EU

That ~20 EUR accounts for two CPX21 nodes — one for the application, one for the observability stack. A single-node setup would be ~10 EUR, but the monitoring overhead (Prometheus and Loki alone eat 2-3GB RAM) makes a dedicated node worthwhile. Heroku and Railway costs are usage-dependent and can vary, but these are reasonable estimates for a small project.

The hidden cost is your time. Initial setup took a weekend — most of it reading docs, not writing code. Ongoing maintenance is maybe 1-2 hours a month: updating k3s, checking Grafana, renewing certificates (though cert-manager handles that automatically once configured).

The trade-off is control versus convenience. PaaS gives you convenience at the cost of vendor lock-in and data residency uncertainty. k3s gives you control at the cost of a weekend and some ongoing attention. For Noidoc.de, GDPR made the choice for me — and the monthly savings compound. After six months, the weekend of setup had paid for itself several times over.

When to Just Use Railway

Build your own k3s stack ifUse a managed PaaS if
Data must stay in Germany (compliance)Speed-to-market matters more than location
You want full control over infrastructureYou don’t want to think about infrastructure
Your project will scale and cost predictability mattersYour project is small and your time is expensive
You’re comfortable with Docker and kubectlKubernetes sounds like a weekend you’d rather skip

The German PaaS gap is real but narrowing. Sliplane already covers databases and arbitrary containers — if you don’t need fully managed services, it’s a legitimate option. Cloudfleet gives you managed Kubernetes without the provisioning headache, though you’ll wire your own CI/CD. For now, k3s on Hetzner is the most capable option per euro spent — a stack that scales when I need it, costs less than a Heroku hobby plan, and keeps every byte of data on German soil. The weekend I spent setting it up was the last time I thought about infrastructure hosting.


Cluster provisioning: hetzner-k3s by Vito Botta


x|telegram

next
Your AI Reads Customer Data — A Proxy Solved My GDPR Problem
-->