2.7 KiB
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
- Generate a Hetzner Cloud API token (Read & Write) from the Hetzner console
- Write it to
/root/.hermes/scripts/.hetzner_token(one line, no trailing newline via Python write) chmod 600 /root/.hermes/scripts/.hetzner_token- Test:
python3 /root/.hermes/scripts/snapshot-hetzner.py - 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_imageaction withtype=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" > filecan 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:Verify the length matches the token in the Hetzner console.token = 'paste-the-full-token-here' with open('/path/to/.hetzner_token', 'w') as f: f.write(token) print(f'Wrote {len(token)} chars') - 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.