DEV Community

ClawSetup
ClawSetup

Posted on • Originally published at clawsetup.co.uk

Secure OpenClaw on Hetzner (Basic Setup): Cloud Firewall + SSH Keys + fail2ban, with a Minimal Port Surface

OpenClaw is only as safe as the VPS it runs on. This article walks through a practical “secure-by-default” baseline for a Hetzner Cloud VM: deny-by-default inbound at the cloud perimeter, mirror that posture on the host with UFW, enforce SSH key-only access for an unprivileged sudo user, and add fail2ban to reduce noisy internet traffic. The aim is a minimal exposed surface (usually SSH only, restricted by source IP), while keeping the OpenClaw Gateway/dashboard private unless you explicitly choose a private-access method like Tailscale.

Secure OpenClaw on Hetzner (Basic Setup): Cloud Firewall + SSH Keys + fail2ban, with a Minimal Port Surface

Design goal (what we’re optimizing for)

For a single-tenant VPS running OpenClaw, the highest-leverage security posture is:

  • Only one public entrypoint: SSH
  • SSH is key-only (no passwords), ideally no root login
  • Inbound is deny-by-default at both the Hetzner perimeter and the VM
  • OpenClaw’s Gateway UI stays on loopback/private by default
  • Remote usage happens via Telegram and/or private networking (e.g., Tailscale), not by exposing admin UIs to the open internet

This matches how SetupClaw’s Basic Setup (£249) is intended to run: secure defaults first, then optional expansions when you have a clear reason.


Step 1 — Put a deny-by-default perimeter around the VPS (Hetzner Cloud Firewall)

Hetzner Cloud Firewalls are your “edge” control: traffic is filtered before it reaches your VM. In practice, that means mistakes on the host are less likely to become an internet exposure.

Baseline rules (recommended for Basic Setup)

  1. Create a Cloud Firewall in Hetzner.
  2. Attach it to your OpenClaw server.
  3. Add one inbound allow rule:
  • TCP 22 (SSH)
  • Source: your fixed IP(s) (home, office). If you truly need it, add a temporary admin IP and remove it after.

Keep everything else blocked inbound.

Notes:

  • The usual “minimal ports” stance is SSH only.
  • Don’t open the OpenClaw Gateway/dashboard to the internet by default.

(Reference: Hetzner Cloud Firewall overview)


Step 2 — Mirror the perimeter on the VM (UFW defense-in-depth)

Why both a Hetzner firewall and UFW?

  • Hetzner firewall = edge protection, safer by default.
  • UFW = host-level safety net if cloud rules drift or are misapplied.

UFW baseline (Ubuntu)

On the VPS:

sudo apt update
sudo apt install -y ufw

# Deny inbound by default; allow outbound
sudo ufw default deny incoming
sudo ufw default allow outgoing

# Allow SSH (you can also restrict to your IP here, but do that at the Hetzner layer first)
sudo ufw allow 22/tcp

# Enable
sudo ufw enable
sudo ufw status verbose
Enter fullscreen mode Exit fullscreen mode

If you want to restrict SSH at the host layer too:

# Example: allow SSH only from one IP
sudo ufw delete allow 22/tcp
sudo ufw allow from <YOUR_PUBLIC_IP> to any port 22 proto tcp
sudo ufw status numbered
Enter fullscreen mode Exit fullscreen mode

Step 3 — SSH keys only: remove password guessing from the equation

The biggest practical win for SSH is eliminating passwords.

3.1 Create an unprivileged sudo user

Avoid operating as root day-to-day.

sudo adduser claw
sudo usermod -aG sudo claw
Enter fullscreen mode Exit fullscreen mode

3.2 Install your public key

From your local machine, copy your public key (example uses ~/.ssh/id_ed25519.pub).

ssh-copy-id -i ~/.ssh/id_ed25519.pub claw@<SERVER_IP>
Enter fullscreen mode Exit fullscreen mode

Or manually:

sudo -u claw mkdir -p /home/claw/.ssh
sudo -u claw chmod 700 /home/claw/.ssh

# paste your public key into:
sudo -u claw nano /home/claw/.ssh/authorized_keys
sudo -u claw chmod 600 /home/claw/.ssh/authorized_keys
Enter fullscreen mode Exit fullscreen mode

3.3 Test in a second session before locking things down

Open a new terminal and confirm you can log in with the key:

ssh claw@<SERVER_IP>
Enter fullscreen mode Exit fullscreen mode

Only after this succeeds should you proceed.

3.4 Harden sshd_config

Edit /etc/ssh/sshd_config (exact options can vary by distro; check comments in-file):

Recommended baseline:

  • Disable password auth
  • Disable root login
  • Optionally restrict allowed users/groups

Example settings:

PasswordAuthentication no
PermitRootLogin no

# Optional tightening
AllowUsers claw
Enter fullscreen mode Exit fullscreen mode

Then reload:

sudo systemctl reload ssh
Enter fullscreen mode Exit fullscreen mode

Reference for options: man sshd_config.


Step 4 — Add fail2ban to reduce noisy internet traffic

If SSH is key-only, why fail2ban?

  • Key-only blocks password guessing, but fail2ban:
    • reduces noise/log spam
    • slows repeated authentication failures
    • provides an extra response layer for misbehaving IPs

Install and enable:

sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status
Enter fullscreen mode Exit fullscreen mode

Create a minimal jail override (Ubuntu commonly uses /etc/fail2ban/jail.d/*.conf):

sudo nano /etc/fail2ban/jail.d/sshd.local
Enter fullscreen mode Exit fullscreen mode

Example:

[sshd]
enabled = true
# Defaults are often fine for a baseline; tune if needed
# maxretry = 5
# findtime = 10m
# bantime = 1h
Enter fullscreen mode Exit fullscreen mode

Then:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd
Enter fullscreen mode Exit fullscreen mode

Important: fail2ban helps manage rate and noise; it does not replace strong authentication.


Step 5 — Patch hygiene: automatic security updates

Hardening only matters if the box stays patched. On Ubuntu, enable unattended security updates:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Enter fullscreen mode Exit fullscreen mode

Document the operational reality: some updates (kernel, key libraries) may require reboots. For a Basic Setup baseline, it’s enough to:

  • enable security updates
  • agree on a reboot habit (manual when needed, or a maintenance window)

Step 6 — OpenClaw-specific posture (tie the hardening to the product)

Once the VPS is hard to break into, you can trust the layer above it:

  • Keep the OpenClaw Gateway/dashboard private (loopback) by default.
  • Prefer private remote access (e.g., Tailscale) if you need “admin from anywhere.”
  • Treat your Telegram bot token as a secret stored server-side; combine with allowlisting/DM policy so only intended users can command the agent.

If someone asks “can we just expose the OpenClaw dashboard publicly?” — treat that as a deliberate design change that needs explicit protections (reverse proxy, TLS, authentication, IP allowlisting). It’s not the Basic Setup default.


Practical “done” checks

Run these after hardening:

# Firewall status
sudo ufw status verbose

# Confirm SSH is key-only (password auth disabled)
sudo sshd -T | egrep 'passwordauthentication|permitrootlogin'

# fail2ban status
sudo fail2ban-client status
sudo fail2ban-client status sshd

# Updates
sudo systemctl status unattended-upgrades --no-pager
Enter fullscreen mode Exit fullscreen mode

And validate from the outside:

  • SSH works from allowed IPs
  • SSH fails from non-allowed IPs (Hetzner firewall should drop)

Deliverables SetupClaw leaves behind (Basic Setup baseline)

A good handoff is a short runbook, not a pile of screenshots. For this hardening slice, the deliverables should include:

  • What inbound ports are intentionally exposed (usually only TCP 22) and why
  • Where rules live:
    • Hetzner Cloud Firewall name + rule summary
    • UFW policy summary + any IP restrictions
  • SSH access model:
    • which user(s) can log in
    • where to add/remove authorized keys
    • confirmation that password auth is disabled
  • fail2ban basics:
    • how to check status and jails
  • Break-glass note:
    • Hetzner console access
    • key rotation steps if a laptop is lost

Want this baseline implemented cleanly (and documented)?

Get OpenClaw setup on your own Hetzner VPS — see how we can help.


References

Top comments (0)