Provider guide

How to secure a Hetzner Cloud server

Hetzner gives you a capable free firewall and three specific ways to misconfigure it that produce a false sense of safety.

The short answer

To secure a Hetzner Cloud server: attach a Cloud Firewall allowing only the ports you need, keep an OS-level firewall on the server as well, harden SSH to key-only authentication, keep packages patched, and monitor for what a firewall cannot stop. Three Hetzner-specific behaviours matter. Adding any outbound rule flips the outbound direction to implicit deny, so a single rule can silently break everything else the server talks to. Cloud Firewalls do not filter private network traffic, because Hetzner treats private networks as trusted, so a server reachable over a private network is unprotected on that interface. And each server has a stated ceiling of 80,000 concurrent connections and 10,000 new connections per second, which is a real limit during a flood.

Hetzner Cloud Firewalls: what they actually do

Hetzner does not charge for Cloud Firewalls, which alone puts them ahead of several providers. They are stateful, so they track connections rather than evaluating packets in isolation, and you can attach up to five firewalls to a server, with up to 500 effective rules each and up to 50 firewalls across all your projects.

The default with no rules is the sensible one: all inbound traffic is blocked and all outbound traffic is permitted. That means a server with an empty firewall attached is closed from the internet, which is a much better default than most.

Use them. An OS firewall on the box is still worth having, but a rule that drops traffic before it reaches your server costs you nothing in CPU and cannot be disabled by someone who has already got onto the machine.

Trap one: one outbound rule denies all the others

This is the behaviour that breaks production. With no outbound rules defined, all outbound traffic is permitted. The moment you create any outbound rule, the outbound direction changes to implicit deny and only traffic matching your rules passes.

So someone adds a single outbound rule to allow, say, SMTP, and immediately the server cannot resolve DNS, cannot reach package mirrors, cannot call any API, and cannot report to any monitoring service. Nothing announces this. The rule you added works perfectly and everything else stops.

If you are going to restrict outbound at all, write the full set at once: DNS on 53 UDP and TCP, HTTP and HTTPS on 80 and 443 for package updates and APIs, NTP on 123 UDP so the clock stays synchronised, and whatever your application actually talks to. Then test from the server, not from the console.

Trap two: private network traffic is not filtered

Hetzner states plainly that Cloud Firewalls cannot currently secure private network traffic, because they consider private networks to be secure. That is a defensible position for a provider to take and a dangerous assumption for you to inherit.

The practical consequence: if you put your servers on a private network and bind a database, a cache or an internal API to the private interface, your Cloud Firewall rules do not apply to that traffic at all. Any server on that private network can reach it, and any compromise of any one of those servers is a direct path to everything else.

The fix is not exotic. Run an OS-level firewall on each server with rules covering the private interface, bind internal services to the specific private address rather than to 0.0.0.0, and require authentication on internal services even though they are "internal". Treat the private network as a network, not as a trust boundary.

Trap three: the connection ceiling

Hetzner documents a limit of 80,000 concurrent connections per server and 10,000 new connections per second through the firewall. For normal traffic that is generous and you will never think about it.

Under a flood it is a number that matters, because it is where a connection-exhaustion attack aims. An attacker does not need to break anything; they need to occupy that budget with connections that go nowhere until legitimate traffic cannot get a slot.

Nothing in the firewall configuration prevents this on its own. What helps is blocking the sources quickly, which means something on or in front of the server has to notice the pattern and act faster than a human can. Rate limiting at the OS level buys some room, and an edge service in front of web traffic buys more, but neither covers SSH.

What to harden on the server itself

Hetzner Cloud images are clean rather than hardened, which is the right choice for them and leaves the work to you. The list below is the one that catches the real problems.

  • SSH: set PasswordAuthentication no and PermitRootLogin prohibit-password or no, after confirming your key works. Password authentication on a public IP is the single most attacked thing on a Hetzner server.
  • Keep the OS firewall enabled as well as the Cloud Firewall, particularly if you use private networks, where the Cloud Firewall does not apply.
  • Unattended upgrades for security patches, or a patching process you actually run. An unpatched public-facing package is how most compromises start.
  • Bind internal services to the private or loopback address, never 0.0.0.0, and check with ss -ltnp what is actually listening.
  • Confirm the clock is synchronised. timedatectl show should report NTP=yes and NTPSynchronized=yes. Drifting clocks make your logs unusable as evidence later.
  • Set up the Hetzner rescue system and a snapshot schedule before you need them, and test that a snapshot actually restores.

What a firewall on any provider cannot do

A firewall decides what can reach a port. It has no opinion about what happens afterwards, and most real incidents happen afterwards.

It does not notice a successful SSH login with a stolen key, a new setuid binary, a webshell dropped into a web root by an application vulnerability, a package with a known CVE, a change to sudoers, or a process quietly making outbound connections to somewhere new. All of that passes through a correctly configured firewall because it is either not network traffic at all or it is traffic you allowed.

That is the layer SecAI covers on a Hetzner server: authentication and privilege changes, file integrity, package vulnerabilities, webshells, rootkit indicators and outbound anomalies, with attacking sources blocked within seconds and fixes that verify themselves and roll back if they break a service. It installs with one command and does not care which provider the server is on.

Related

Questions people ask

See it on your own server

Install the SecAI agent with one command and watch it protect a Linux server in about 60 seconds. 14-day free trial, no credit card.