Home / Docs / Hetzner Cloud

Hetzner Cloud

Connect a Hetzner Cloud project and you can spin up a server, SSH into it, watch its logs, and tear it down again without leaving the terminal — or let an AI agent do the same under guard rails. Hetzner's hourly billing and fast provisioning make it ideal for disposable demo and staging boxes, and Servonaut covers the full lifecycle: list, create, power on, shutdown, power off, reboot, delete, plus the project's SSH-key registry.

What you get

Three ways to drive the same operations: a Hetzner section in the TUI sidebar (Manager screen + SSH-key registry) for day-to-day work, a scriptable servonaut hetzner CLI for CI and cron, and 11 MCP tools so AI agents can manage your Hetzner fleet — guarded, confirmed, and audit-logged like everything else in Servonaut.

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:

#SourceNotes
1config.hetzner.api_tokenSupports $ENV_VAR and file:/path/to/token prefixes.
2$HCLOUD_TOKEN env varSame env var the official hcloud CLI / Terraform provider use.
3~/.config/hcloud/tokenDefault 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.

bash
$ mkdir -p ~/.config/hcloud $ echo "abc...your-token..." > ~/.config/hcloud/token $ chmod 600 ~/.config/hcloud/token

3. Enable the provider

The quickest path is the in-TUI wizard: open Settings → Hetzner Setup, paste or point at your token, and pick your defaults — the wizard writes the config for you.

On headless machines, or if you manage config in version control, edit the hetzner block in ~/.servonaut/config.json directly:

~/.servonaut/config.json
{
  "hetzner": {
    "enabled": true,
    "api_token": "",
    "default_username": "root",
    "default_image": "ubuntu-22.04",
    "default_server_type": "cx23",
    "default_location": "fsn1",
    "default_hetzner_ssh_key": "my-laptop",
    "default_local_ssh_key": "~/.ssh/id_ed25519",
    "require_ssh_keys_on_create": true
  }
}

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

bash
$ servonaut hetzner test-connection → Connected. 0 server(s) in project.

Using it in the TUI

With hetzner.enabled = true, a Hetzner section appears in the TUI sidebar, and your Hetzner servers join the unified instance list alongside AWS, OVHcloud, and custom servers, tagged provider: hetzner. Everything you can do to any other server works here too, using the configured default_local_ssh_key and default_username (root by default — Hetzner's stock images don't ship a non-root user):

  • From the instance list: S SSH to the selected server, C run-command overlay, B remote file browser, T SCP transfer, Y copy the IP.
  • Click a row (or press Enter) to open the per-server Server Actions dashboard — browse files inline, tail logs, run AI analysis, and press L for an opt-in live resource monitor (CPU / RAM / load / disk, polled over SSH only while the pane is open).
  • Press F2 anywhere to open the AI chat panel and ask for Hetzner operations in plain language — "shut down demo-1", "what server types are available in Falkenstein?". The assistant calls the same guarded tools described below.

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.
  • Power on / Shutdown / Power off / Reboot — buttons enable based on the selected row's state.
  • Delete — typed-name confirmation; permanent.

The create wizard walks you through four steps — region → server type → image → SSH keys — pulling current server types and EUR pricing live from the Hetzner catalog, and pre-selects your default SSH key. If the project has no SSH key registered, the wizard nudges you to add one before continuing — Servonaut refuses by default to create a server with no keys. New servers register into your fleet automatically and show up in the instance list within seconds, ready for SSH.

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.

Automating with the CLI

Every operation above is also available headlessly via servonaut hetzner — built for CI runners, cron jobs, and scripts. For day-to-day operation, the Hetzner Manager screen in the TUI is the recommended interface.

bash
$ servonaut hetzner list [--json] [--state STATE] $ servonaut hetzner create NAME [--type cx23] [--image ubuntu-22.04] [--location fsn1] [--ssh-key NAME|ID] (repeatable) [--no-wait] [--json] $ servonaut hetzner destroy NAME_OR_ID [--yes] [--json] $ servonaut hetzner ssh-keys list [--json] $ servonaut hetzner ssh-keys add NAME --public-key-file PATH (or --public-key "ssh-ed25519 AAAA…") $ servonaut hetzner server-types [--json] $ servonaut hetzner test-connection [--json]

Examples

bash
# Spin up a box with the defaults, inject the "laptop" SSH key $ servonaut hetzner create demo-1 --ssh-key laptop # List, filtering on state $ servonaut hetzner list --state running # Destroy without typed confirmation (CI / scripts) $ servonaut hetzner destroy demo-1 --yes # Browse types + prices $ servonaut hetzner server-types
Exit codeMeaning
0Success
1Generic error (API failure, network)
2Not configured (no token resolvable)
3Typed-confirmation declined for destroy
4Input validation error

Pressing Ctrl+C during any command cancels it cleanly — a one-line Cancelled. and exit code 130, never a traceback — so wrapping scripts can rely on the standard SIGINT convention.

For AI agents: MCP tools (11)

Eleven Hetzner tools are available to agents the moment your Hetzner provider is configured — no extra registration step. They appear in tools/list for any MCP client (Claude Code, Cursor, Windsurf, …) connected to the Servonaut MCP server, whether it runs locally over stdio (servonaut --mcp, one-command install via servonaut --mcp-install) or reaches your machine through the hosted relay. Create and delete tools require mcp.guard_level = dangerous; power controls (power_on, power_off, shutdown, reboot) and create_ssh_key run at the standard tier so an agent can recover a stuck server without escalation. See guard levels for how the tiers work.

Hosted MCP calls count toward your plan's per-provider operations allowance — see Pricing for the current per-plan numbers. Dangerous-tier tools additionally require the dangerous-AI-tools opt-in on your servonaut.dev account; on Teams plans, a per-team approval policy can require human approval before they run.

ToolGuardDescription
hetzner_list_serversreadonlyList servers in project
hetzner_list_server_typesreadonlyCatalog + EUR prices
hetzner_list_ssh_keysreadonlyRegistered SSH keys
hetzner_create_ssh_keystandardRegister a new SSH public key
hetzner_delete_ssh_keydangerousRemove an SSH key from the project
hetzner_create_serverdangerousCreate a server (auto-registers in fleet). Confirmation required.
hetzner_delete_serverdangerousPermanently delete a server. Confirmation required.
hetzner_power_onstandardPower a stopped server back on
hetzner_power_offstandardHard power-off (no graceful shutdown)
hetzner_shutdownstandardGraceful ACPI shutdown
hetzner_rebootstandardSoft reboot

From Servonaut AI chat and the headless relay

The same tools back the built-in AI chat: press F2 in the TUI, or use servonaut ai chat --tools headlessly, and the assistant can list, power-cycle, or (with the dangerous opt-in) create and delete Hetzner servers on your behalf. When no TUI is open, a running servonaut connect listener executes these tool calls too — approval is policy-driven via relay.ai_tool_auto_approve in ~/.servonaut/config.json, which sets the maximum guard tier auto-approved (default standard, so power controls run but create/delete are denied unless you raise it and hold the dangerous-tools entitlement). Every execution is audit-logged.

Auto-registration into the fleet

Servers created through hetzner_create_server (or the wizard, or the CLI) appear in your fleet automatically — the next list_instances call or TUI refresh shows them. 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 created with owner-only file permissions and hardened against symlink and partial-write attacks.
  • hetzner_create_ssh_key does not log the public-key text — only the key name. API error messages are sanitised before they reach the audit log, so key material never appears there.
  • hetzner_create_server refuses 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_TOKEN environment variable
  • ~/.config/hcloud/token (the standard hcloud CLI location)

"unsupported location for server type"

Hetzner periodically retires server types in specific locations. 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

The TUI's Shutdown action (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 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-running returns running) before issuing shutdown.
  • Use the TUI's Power off action / the hetzner_power_off MCP tool instead — that's a hard power-off via the Hetzner API which doesn't depend on the guest. Risks in-flight write loss, so prefer Shutdown on settled servers and Power off on fresh ones or when the guest is unresponsive.

Not supported

Servonaut does not manage the following Hetzner products:

  • 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.
Documentation