Files
hermes-skills/skills/devops/infrastructure-automation/references/hetzner-snapshot-automation.md
T

2.7 KiB

Hetzner Snapshot Automation

Weekly snapshots of all running servers in a Hetzner Cloud account. Part of the provider-level backup layer (layer 1 in the three-layer model).

Script

File: snapshot-hetzner.py at /root/.hermes/scripts/snapshot-hetzner.py

Reads the API token from a companion file .hetzner_token in the same directory (avoids shell escaping issues with special characters in the token).

API Token Handling

The Hetzner Cloud API token can contain special characters ($, !, etc.) that break shell-based environment variable passing. Do not use export TOKEN=... in bash — the shell will mangle it.

Pattern: Store the token in a dedicated file, have the script read it directly:

script_dir = os.path.dirname(os.path.abspath(__file__))
token_file = os.path.join(script_dir, ".hetzner_token")
with open(token_file) as f:
    TOKEN = f.read().strip()

Token file permissions: chmod 600.

Setup

  1. Generate a Hetzner Cloud API token (Read & Write) from the Hetzner console
  2. Write it to /root/.hermes/scripts/.hetzner_token (one line, no trailing newline via Python write)
  3. chmod 600 /root/.hermes/scripts/.hetzner_token
  4. Test: python3 /root/.hermes/scripts/snapshot-hetzner.py
  5. Cron job handles weekly runs (Monday at 5:00 UTC = 1:00 AM ET)

What it does

  • Lists all servers in the account via GET /v1/servers
  • For each running server, POSTs a create_image action with type=snapshot
  • Snapshot description: auto-weekly-{server-name}-{date}
  • Skips stopped/offline servers

Cron schedule

0 5 * * 1  (Mondays at 5:00 UTC / 1:00 AM ET)

Via no_agent cron job, silent output (watchdog pattern).

Pitfalls

  • Token expires — Hetzner tokens can have expiry dates. If snapshots start failing with 401, regenerate the token and update the file.
  • Writing the token file via echo truncates it — Bash echo "$TOKEN" > file can silently truncate tokens containing $, !, backticks, or other shell-special characters. The file may contain fewer characters than the actual token, causing silent auth failures. Always write the token via Python:
    token = 'paste-the-full-token-here'
    with open('/path/to/.hetzner_token', 'w') as f:
        f.write(token)
    print(f'Wrote {len(token)} chars')
    
    Verify the length matches the token in the Hetzner console.
  • Snapshot names are unique — A snapshot with description auto-weekly-{name}-{date} allows easy identification in the Hetzner console. Hetzner allows up to 10 snapshots per server.
  • Billing — Hetzner charges for snapshot storage (based on disk size). CPX11 (40GB) snapshots cost ~$0.01-0.02 each. Full account backup of 9 servers = negligible monthly cost.