Kubernetes

K3s on Hetzner: What to Trust and Isolate

Running K3s on Hetzner is the cheapest path to real Kubernetes, but bare-metal means you own the security boundaries. What to trust, what to isolate, and how.

Part of Kubernetes Operations for Production Platforms
K3s on Hetzner, shown as a lean glowing node cluster on bare metal with an amber trusted isolation boundary

Running K3s on Hetzner is the cheapest credible path to real Kubernetes: a lightweight, fully-conformant distribution on Europe’s best price-to-performance hardware. The tradeoff is that bare metal means you own every security boundary a managed cloud would handle for you. Trust the things Hetzner actually guarantees, isolate everything else, and the savings are real without the footguns.

The mistake that bites self-hosters is assuming a private network or a default install gives you the isolation a managed Kubernetes service provides. It does not. On Hetzner you are the platform team, and the boundaries are yours to draw.

Why self-hosted Kubernetes needs a trust model

Managed Kubernetes (EKS, GKE) hides a lot of security work: the control plane is hardened for you, the network has sane defaults, backups of the control-plane datastore are handled. You pay for that, both in money and in lock-in.

Self-hosting on Hetzner removes the cost and the lock-in, and hands you the responsibility. Every boundary the managed service drew silently is now a boundary you must draw explicitly, or it does not exist. Getting the trust model right is the difference between a cheap, solid cluster and a cheap, exposed one. This post is part of the Kubernetes operations series, alongside Kubernetes Namespace Strategy for SaaS Platforms and Readiness Probes That Don’t Lie.

Is K3s production-ready on Hetzner?

Yes. K3s is a CNCF-conformant Kubernetes distribution, just packaged lean: a single binary, a lighter default datastore, and trimmed-down components. On Hetzner it runs production workloads well, as long as you own the parts Hetzner does not manage, namely the firewall, the network boundary, datastore backups, and node hardening.

The performance and cost story is the draw. Hetzner’s dedicated and cloud servers offer some of the best price-to-performance available, which is exactly why cost-conscious teams self-host there.

Is the Hetzner private network safe to trust?

No, not as a security boundary. The Hetzner private network (vSwitch / private cloud networks) is a convenience for routing internal traffic, not a guarantee of isolation. Do not assume traffic on it is automatically protected or that a private IP means a safe surface. Layer a firewall on top, and encrypt sensitive traffic in transit.

This is the single most common self-hosting misconception: “it’s on the private network, so it’s fine.” A private network reduces exposure; it does not replace a firewall, network policy, or encryption. Treat private connectivity as a routing tool and build your real boundaries explicitly on top of it.

What should you isolate when running K3s on Hetzner?

Isolate four things: the Kubernetes API server (bind it to a private interface, never the public one by default), node-to-node and control-plane traffic (behind Hetzner Cloud Firewalls), pod-to-pod traffic (default-deny with NetworkPolicy), and your etcd/datastore backups (stored off the cluster). The public surface should be exactly what you choose to expose, and nothing more.

A practical isolation layering:

  • Hetzner Cloud Firewall at the edge: deny everything inbound except the ports you actually serve, and the admin access you need (ideally over a VPN, not the open internet).
  • API server binding: the Kubernetes API should not be reachable from the public internet by default. Bind it privately and reach it over a VPN or a tunnel.
  • NetworkPolicy default-deny: as with any cluster, pods can talk to each other freely until you say otherwise. A default-deny policy per namespace makes the in-cluster network a real boundary, the same discipline covered in the namespace-strategy guide.
  • Edge in front of the origin: put public services behind a CDN/proxy so origin IPs stay private and TLS terminates at the edge, shrinking the attack surface that ever sees your Hetzner IPs.

K3s vs K8s on Hetzner: which should you use?

For most small-to-medium self-hosted clusters, K3s is the better choice: lighter, simpler to operate, and fully conformant, so your manifests and tooling work unchanged. Reach for full upstream Kubernetes only when you need components K3s trims, or you are operating at a scale and team size that can absorb the extra operational weight.

FactorK3sFull K8s (kubeadm)
FootprintSingle lightweight binaryHeavier, more components
Ops complexityLowerHigher
ConformanceFullFull
Best forSmall/medium self-hostedLarge scale, dedicated platform team
Default datastoreLightweight (SQLite/etcd)etcd

For a solo operator or small team on Hetzner, K3s hits the sweet spot: you get real Kubernetes without the operational tax of running the full distribution yourself.

How much does K3s on Hetzner cost versus managed Kubernetes?

Dramatically less for the raw infrastructure, which is the whole reason to self-host. A managed Kubernetes service charges a control-plane fee per cluster plus a premium on every node, while Hetzner charges you for the servers and nothing for a control plane you run yourself. For a small cluster, the difference is routinely several times cheaper.

The honest accounting, though, includes the operational cost you take on. Managed Kubernetes bundles the price of a team that patches the control plane, handles upgrades, and manages backups. Self-hosting on Hetzner moves that labor to you, so the true comparison is “Hetzner hardware plus your time” against “managed price minus your time.” For a solo operator or small team comfortable with the operational work, the math strongly favors Hetzner; for a team that would rather buy back that time, managed can be worth the premium.

The decision is therefore not purely financial. Self-host on Hetzner when the savings are large relative to your scale and you are willing to own the platform work this guide describes. Choose managed when your engineers’ time is better spent on the product than on patching nodes. Either way, price the hardware against a managed quote with the operational labor made explicit, rather than comparing sticker prices alone.

A K3s-on-Hetzner hardening checklist

Before you run anything real on it:

  • Hetzner Cloud Firewall denies all inbound except deliberately exposed ports.
  • The Kubernetes API is not on the public internet; admin access is over VPN.
  • A default-deny NetworkPolicy is applied per namespace.
  • etcd/datastore is backed up automatically to off-cluster storage, and a restore has been tested.
  • Nodes are hardened: no password SSH, minimal packages, automatic security updates.
  • Public services sit behind an edge proxy so origin IPs stay private.
  • You have an upgrade plan for K3s and the OS; self-hosting means patching is your job.

Should you run a single-node or HA K3s cluster?

Run single-node only for non-critical workloads where downtime during a reboot or failure is acceptable; run a high-availability control plane (an odd number of server nodes, typically three) for anything you cannot afford to have go down with one machine. The choice is a direct tradeoff between cost and your tolerance for a single point of failure.

A single-node K3s cluster is the cheapest and simplest option, and it is genuinely fine for side projects, internal tools, and staging. Its weakness is obvious: that one node is a single point of failure, and when it reboots or dies, the cluster is down. For a solo project that is an acceptable risk; for anything customer-facing it usually is not.

An HA setup runs multiple server (control-plane) nodes with an embedded distributed datastore, so the loss of one node does not take down the cluster. On Hetzner this means paying for at least three servers instead of one, plus a load balancer in front of the API. That is more cost and more to operate, and it is the price of not having a single machine be your whole platform. Decide based on what an outage actually costs you, and remember that whichever you choose, tested off-cluster backups of the datastore are non-negotiable.

What actually breaks first on a self-hosted cluster?

Failures on self-hosted Kubernetes are predictable, and they are rarely Kubernetes itself. Knowing the order they arrive in lets you pre-empt most of them.

Disk fills, and it is almost always the first outage. Container images accumulate, logs grow without rotation, and etcd keeps history. A full disk on a control-plane node makes etcd read-only and the cluster stops accepting changes; a full disk on a worker makes the kubelet start evicting pods. Neither presents as “disk full” in the first symptom you see. Alert on disk usage before anything else — it is the highest-value single alert on a self-hosted cluster.

Memory pressure evicts things you did not expect. Without resource requests and limits on your workloads, the kubelet under pressure evicts by its own priority rules, which frequently means killing something important to protect something trivial. Setting requests and limits is what gives the scheduler and the eviction logic the information to make sensible choices, and it is skipped far more often on self-hosted clusters than on managed ones.

Certificates expire. K3s rotates most certificates automatically on restart, but a cluster that has not restarted in a year can reach expiry. The failure is abrupt and total — components stop authenticating to each other — and it happens on a date nobody has in a calendar. Check expiry dates on a schedule.

A single control-plane node becomes the outage. With one server node, that machine is the cluster. Its failure is not degraded service; it is complete loss of control-plane function, and recovery depends entirely on whether your etcd backup works. This is the strongest argument for either HA control plane or genuinely rehearsed restores.

Network policy is absent, so one compromise is total. Covered above, and worth repeating in this list because it is the failure with the worst consequences and the least visibility until it matters.

The pattern across all five: on a managed cluster, most of these are silently handled by the provider. They do not appear on your radar because someone else’s automation is preventing them. Self-hosting means inheriting them, and the ones that hurt are the ones with no symptom until they are an outage. A short list of boring alerts — disk, memory, certificate expiry, backup success — covers the majority, and setting them up on day one is far cheaper than deriving them from incidents.

What is the minimum hardening a public-cloud K3s node needs?

A Hetzner node arrives with a public IP and no firewall in front of it, which is the fundamental difference from a managed cluster where the control plane is not exposed to begin with. The baseline below is not optional, and each item closes a hole that is actively scanned for within hours of a node coming online.

Close the Kubernetes API to the internet. The API server on port 6443 must not be publicly reachable. Bind it to the private network or restrict it with a cloud firewall to your own addresses and a bastion or VPN. An exposed API server with a leaked or weak credential is a complete cluster compromise, and exposed API servers are scanned for continuously.

Use the cloud firewall, not only the host firewall. Hetzner’s firewall filters before traffic reaches the machine, which means a misconfigured host-level rule cannot silently expose a port. Default-deny inbound, then allow only what you need: your ingress ports, SSH from restricted sources, and node-to-node traffic on the private network.

Do not trust the private network as a security boundary by itself. A private network reduces exposure and it is not encryption or authentication. Anything sensitive crossing it should still be authenticated, and the cluster’s own inter-node traffic should use the encryption K3s can provide rather than assuming the network is safe.

Harden SSH immediately. Key-only authentication, root login disabled, and ideally access restricted to a bastion or a VPN. This is the single most-attacked surface on a public node.

Enforce Pod Security Standards and NetworkPolicies from the start. Self-hosted clusters frequently skip both because there is no platform team requiring them. The result is a cluster where any compromised container can reach anything, and where privileged containers are permitted — which turns a container escape into a node compromise.

Encrypt secrets at rest and back up etcd off-node. K3s can encrypt secrets in its datastore; enable it. And a backup stored on the same machine as the cluster protects you from nothing that matters.

The mental model that makes these decisions consistent: on a managed cluster the provider owns the network perimeter; on Hetzner you own it, and the default is open. Every item above is something a managed service did for you silently, and the failure mode of skipping them is not degraded performance but a compromised cluster — which is why this list belongs in the build, not in a follow-up ticket.

What do you have to operate yourself that a managed cluster handles?

The cost comparison between self-hosted and managed usually stops at the invoice, which is the least interesting part. The real difference is the list of responsibilities that transfer to you, and each one is work that has to happen whether or not anyone scheduled it.

ResponsibilityManagedSelf-hosted on Hetzner
Control-plane availabilityProvider’s problemYours — a single-node control plane is a single point of failure
etcd backups and restoreAutomatic, testedYou configure, verify, and rehearse restoring
Kubernetes version upgradesOne click, stagedYou plan, sequence, and roll back
Node OS patchingManaged node poolsYour patch schedule and your reboots
Certificate rotationAutomaticK3s handles much of it; you monitor expiry
Load balancer / ingressProvider LB integrationYou run it, and you have no cloud LB to fall back on
Persistent storage durabilityReplicated block storageVolume durability is yours to reason about

The row that causes the most real damage is backup restore, because it fails silently. A backup that has never been restored is a hypothesis. On a managed cluster the provider tests theirs; on your own, an untested etcd backup is genuinely likely to fail when you need it, and you find out at the worst possible time. Rehearse a restore into a scratch cluster on a schedule — quarterly is enough, and it is the single highest-value operational habit in this list.

The honest framing of the trade: self-hosted Kubernetes on Hetzner is dramatically cheaper in euros and meaningfully more expensive in attention. For a solo operator or a small team, that trade is frequently correct — the savings are large, the workloads are modest, and the operational surface is manageable. It stops being correct when the hours spent on cluster maintenance exceed what the savings are worth, and that crossover arrives sooner than most people estimate because the work is bursty rather than steady.

The pragmatic middle ground worth considering: self-host the workloads, but not the stateful infrastructure. Running your services on K3s while using managed Postgres and managed object storage removes the two responsibilities with the worst failure modes — data durability and backup correctness — while keeping most of the cost advantage. Losing a stateless node is an inconvenience; losing a database you were backing up incorrectly is a different category of event entirely.

When should you stop self-hosting?

Worth deciding in advance, because the transition is much easier to plan than to perform under duress.

Four signals that the trade has flipped:

You are spending more than a few hours a month on cluster maintenance. At a solo operator’s effective rate, a handful of hours quickly exceeds the difference between a Hetzner bill and a managed one. The savings were the entire premise.

An outage has been caused by the cluster rather than by your code. One is a learning experience. A pattern means you are operating infrastructure at a level you have not staffed for, and the incidents are being paid for by your users.

You need multi-region or genuine HA. The cost and complexity of running that yourself rises sharply, while managed offerings absorb most of it. This is where the economics change fastest.

Compliance requires artefacts you cannot produce. Audit logging, certified backup procedures, and documented access controls are things managed providers supply as a product. Building the evidence yourself is a project, not a configuration change.

The reframing that makes the decision easier: self-hosting is a cost optimisation, and it stops making sense the moment the constraint changes from money to time or risk. For a bootstrapped project where cash is the binding constraint and workloads are modest, running K3s on Hetzner is a genuinely good decision. When the binding constraint becomes your attention or your reliability obligations, continuing to self-host is optimising for the wrong resource — and the honest move is to migrate the stateful pieces first, which is where both the risk and the operational burden concentrate.

What I’d do differently

The lesson self-hosters learn the hard way is treating the private network as security and discovering an exposed API server or an unencrypted internal hop after the fact. The cost savings of Hetzner are real, but they come bundled with responsibilities a managed service quietly handled, and skipping them turns a cheap cluster into a liability.

If I were standing up K3s on Hetzner again, I would draw the trust boundaries before deploying a single workload: firewall first, private API binding, default-deny networking, tested backups. Self-hosting is a great deal precisely when you do the platform-team work that the price excludes, and a poor deal when you pretend that work is optional.

Sources

Frequently asked questions

Is K3s production-ready on Hetzner?

Yes, K3s is a fully conformant Kubernetes distribution and runs well on Hetzner for production, provided you own the parts Hetzner does not manage: the private network boundary, the firewall, etcd/datastore backups, and node hardening. The savings are real, but so is the operational responsibility.

Is the Hetzner private network safe to trust?

Treat the Hetzner private network (vSwitch) as a convenience, not a security boundary. Do not assume traffic on it is automatically isolated from other tenants or safe to send unencrypted. Use a firewall and, for sensitive traffic, encryption in transit on top of it.

What should you isolate when running K3s on Hetzner?

Isolate the control plane and node-to-node traffic from the public internet with Hetzner Cloud Firewalls, bind the Kubernetes API to a private interface, deny pod traffic by default with NetworkPolicy, and keep etcd backups off the cluster. The public surface should be only what you deliberately expose.

K3s vs K8s on Hetzner, which should you use?

For a small-to-medium self-hosted cluster, K3s is usually the better choice: it is lighter, simpler to operate, and fully Kubernetes-conformant. Full upstream K8s makes sense when you need components K3s trims or you are running at large scale with a dedicated platform team.

What is the minimum hardening for K3s on a public cloud node?

Close the Kubernetes API on port 6443 to the internet, use the provider firewall with default-deny inbound rather than only a host firewall, harden SSH to key-only with no root login, enforce Pod Security Standards and NetworkPolicies, encrypt secrets at rest, and store etcd backups off the node.

What do you have to operate yourself with self-hosted Kubernetes?

Control-plane availability, etcd backups and tested restores, Kubernetes upgrades, node OS patching, ingress and load balancing, and storage durability. The one that fails silently is backup restore: an untested backup is a hypothesis, so rehearse restoring into a scratch cluster.