Hetzner Cloud
Hetzner Cloud is a first-class provider in Servonaut — full lifecycle (list / create / power on / shutdown / power off / reboot / delete), project SSH-key registry, and 11 MCP tools your agent can call. Designed for disposable demo / staging fleets where hourly billing and clean teardown beat long-lived AWS-style fleets.
A Hetzner sidebar section with a Manager screen and SSH-key registry, three CLI verbs (servonaut hetzner list / create / destroy), and 11 hosted MCP tools — all backed by entitlements, audit, and the same confirmation protocol used elsewhere.
Setup
1. Get a Hetzner Cloud API token
Open the Hetzner Cloud Console, pick the project you want Servonaut to manage, and create a new API token under Security → API Tokens with Read & Write scope. Copy it once — Hetzner only shows it on creation.
2. Make the token available
Servonaut resolves the token from the first matching source:
| # | Source | Notes |
|---|---|---|
| 1 | config.hetzner.api_token | Supports $ENV_VAR and file:/path/to/token prefixes. |
| 2 | $HCLOUD_TOKEN env var | Same env var the official hcloud CLI / Terraform provider use. |
| 3 | ~/.config/hcloud/token | Default location of the hcloud CLI's token file — zero-config if you already have it. |
Recommended: drop the token at ~/.config/hcloud/token so the same file works for the hcloud CLI, Servonaut, and Terraform.
3. Enable the provider
Either run the in-TUI Settings → Hetzner Setup wizard, or edit ~/.servonaut/config.json:
The CLI commands work even with enabled: false, as long as the token chain resolves. The TUI and the chat panel honour the flag.
4. Validate
TUI integration
With hetzner.enabled = true, the unified instance list shows Hetzner servers tagged provider: hetzner.
SSH connect, run-command overlay, file browser, log viewer — all of these work transparently against Hetzner servers using
the configured default_local_ssh_key and default_username (root by default — Hetzner's stock images don't ship a non-root user).
Hetzner Manager screen
The sidebar's Hetzner → ⚙ Manage entry opens a per-provider table with a state-aware lifecycle toolbar:
- Create opens the create wizard (region → server type → image → SSH keys).
- Power on / Shutdown / Power off / Reboot — buttons enable based on the selected row's state.
- Delete — typed-name confirmation; permanent.
The create wizard pulls live pricing from the Hetzner catalog and pre-selects your default SSH key. If you have no SSH key registered, the wizard nudges you to add one before continuing — Servonaut refuses by default to create a server with no keys.
SSH key registry
Hetzner → 🔑 SSH Keys shows every Hetzner Cloud SSH key registered with the project. Add new ones from a public-key file, delete obsolete ones, copy the fingerprint. The same registry feeds the create-wizard's SSH-key picker, so what you see here is what gets injected into new servers.
CLI reference
Examples
| Exit code | Meaning |
|---|---|
0 | Success |
1 | Generic error (API failure, network) |
2 | Not configured (no token resolvable) |
3 | Typed-confirmation declined for destroy |
4 | Input validation error |
MCP tools (11)
Eleven tools, registered automatically when the Hetzner service is wired up. They appear in tools/list for any agent (Claude Code, Cursor, Windsurf, …) that connects to the Servonaut MCP server. Mutating tools require mcp.guard_level = dangerous and gate behind the hetzner_mcp_operations entitlement (free=0, Solo=50, Teams=200/seat).
| Tool | Guard | Description |
|---|---|---|
hetzner_list_servers | readonly | List servers in project |
hetzner_list_server_types | readonly | Catalog + EUR prices |
hetzner_list_ssh_keys | readonly | Registered SSH keys |
hetzner_create_ssh_key | standard | Register a new SSH public key |
hetzner_delete_ssh_key | dangerous | Remove an SSH key from the project |
hetzner_create_server | dangerous | Create a server (auto-registers in fleet). Confirmation required. |
hetzner_delete_server | dangerous | Permanently delete a server. Confirmation required. |
hetzner_power_on | dangerous | Power a stopped server back on |
hetzner_power_off | dangerous | Hard power-off (no graceful shutdown) |
hetzner_shutdown | dangerous | Graceful ACPI shutdown |
hetzner_reboot | dangerous | Soft reboot |
Auto-registration into the fleet
hetzner_create_server automatically busts the local Hetzner cache on success, so the next call to
list_instances (or any TUI refresh) sees the new server. Downstream tools — run_command,
get_logs, transfer_file, build_server_memory — work on the new server within seconds, with no manual "add server" flow.
Security & safety notes
- The API token is stored in
~/.servonaut/config.json, encrypted at rest if you opt in to a passphrase via the existing config-encryption flow (AES-256-GCM with PBKDF2-HMAC-SHA256, 600 000 iterations). - The token is stripped from any config-sync upload to servonaut.dev, so even if you opt in to cloud config sync, the token never leaves this machine.
- The local cache and audit log are written with
0o600permissions andO_NOFOLLOWto defeat symlink-redirect attacks. The cache uses an atomic temp+rename so a concurrent reader never sees a partial JSON. hetzner_create_ssh_keydoes not log the public-key text — only the key name. API errors that may include public-key fragments are truncated to 160 chars in the audit reason.hetzner_create_serverrefuses by default to create a server with no SSH keys (require_ssh_keys_on_create=true). Hetzner would otherwise spawn one with a random root password the CLI discards, leaving a billed unreachable box.
Troubleshooting
"No Hetzner Cloud API token configured"
The token chain didn't resolve. Place the token at one of:
config.hetzner.api_token(with optional$ENV_VAR/file:prefix)$HCLOUD_TOKENenvironment variable~/.config/hcloud/token(the standardhcloudCLI location)
"unsupported location for server type"
Hetzner deprecates server types per location every ~18 months. If your default_server_type is no longer available in default_location, the create call will fail.
Run servonaut hetzner server-types to see what's currently available, then either pass --type per call or update the default in ~/.servonaut/config.json.
SSH host-key prompt on first connect
Hetzner does not return the new server's host fingerprint in the create response. Servonaut's SSH wrapper uses
StrictHostKeyChecking=accept-new, so the first connect adds the host to your known_hosts automatically. No special handling required.
shutdown sent but server stays running
servonaut hetzner shutdown (and the hetzner_shutdown MCP tool) sends an ACPI signal to the guest. On a freshly-booted Hetzner cloud-init image, acpid isn't started yet during the first ~3 minutes, so the signal is dropped and the server stays in running state. The CLI/MCP call returns success because the API accepted the signal — guest cooperation is what didn't happen.
Two options:
- Wait until the server has fully booted (cloud-init finished,
systemctl is-system-runningreturnsrunning) before issuingshutdown. - Use
servonaut hetzner power off/hetzner_power_offinstead — that's a hard power-off via the Hetzner API which doesn't depend on the guest. Risks in-flight write loss, so prefershutdownon settled servers andpower offon fresh ones or when the guest is unresponsive.
Anti-scope (deliberately not supported)
The following are out of scope for the current release:
- Hetzner Robot (dedicated servers) — different API surface.
- Storage Boxes, DNS, Load Balancers, Volumes, Networks, Firewalls, Floating IPs, Placement Groups — manage these in the Hetzner Console.
- Snapshot / image management.