# Hetzner Server Inventory Compilation When asked to document all Hetzner servers, services, and running applications: ## 1. Query the Hetzner API for server list ```python import urllib.request, json token = open('/root/.hermes/scripts/.hetzner_token').read().strip() headers = {'Authorization': f'Bearer {token}'} req = urllib.request.Request('https://api.hetzner.cloud/v1/servers', headers=headers) data = json.loads(urllib.request.urlopen(req, timeout=10).read()) for s in data.get('servers', []): print(f'{s["name"]} — {s.get("public_net",{}).get("ipv4",{}).get("ip","?")} — {s.get("status")}') ``` ## 2. Cross-reference with existing documentation Check these sources in order: - `/root/.hermes/skills/devops/infrastructure-automation/references/server-inventory-snapshot.md` — shows app-to-server mapping - `/root/.hermes/skills/devops/infrastructure-automation/references/disaster-recovery-plan.md` — shows DR architecture - Scripts in `/root/.hermes/scripts/` — function calls, IP references, API keys (e.g. `snapshot-hetzner.py`) - Memory store (`memory` tool) and `facts_store` for past user statements ## 3. Mark verified vs assumed | Marking | Meaning | |---|---| | 🟢 Verified | Confirmed by SSH or API response | | 🟡 Assumed | From old inventory doc, needs SSH verification | | 🔴 Unknown | No data available | **SSH verification:** If you can SSH in with the wisp_rsa key, run `docker ps`, `systemctl list-units --type=service --state=running`, and `hostnamectl status` to confirm. If no SSH access exists, document it as a gap. ## 4. Document the access map Not every server has the same SSH keys deployed. Track which servers are accessible with which keys: | Server | SSH User | Key | Access | |---|---|---|---| | app1 (netcup) | root | wisp_rsa | ✅ | | app1-bu (Hetzner) | root | wisp_rsa | ✅ | | ai.itpropartner.com | ippadmin | ? | ❌ | ## 5. S3 backup Upload the finished inventory to `s3://hermes-vps-backups/standby/server-inventory.md` for DR access. ## Pitfalls - **Hetzner API hostname vs OS hostname** — `GET /v1/servers/{id}` returns the cloud provider's label, which may differ from the OS hostname. Both are valid — note which you're reporting. - **Missing SSH key for most servers** — The wisp_rsa key was only deployed on app1 (netcup) and app1-bu (standby). All other Hetzner boxes need the SSH key injected via rescue mode (see `infrastructure-automation` skill's Hetzner rescue section) or the user's own key. - **Old inventory may be stale** — apps may have been consolidated between servers since the document was written. Mark "needs SSH verification" rather than stating as fact. - **The `data.get('datacenter',{})` may return empty** — The Hetzner API response has a `datacenter` field with a `location` sub-object (`city`, `country`). Not all API shapes include these. Handle gracefully. - **Don't fabricate service details** — If you can't SSH in to verify what's running, say "from old inventory — needs verification" rather than guessing.