Files
hermes-recovery/references/server-dr-plans.md
T

454 lines
13 KiB
Markdown

# IT Pro Partner — Per-Server Disaster Recovery Plan
**Author:** Sho'Nuff / Network Services Team
**Date:** July 9, 2026
**Version:** 1.0
**Supersedes:** hermes-dr-plan-v2.md (Hermes-specific); server-provisioning-standard-v1.md (base install)
---
## DR Architecture Overview
```
Internet ──► Cloudflare ──► Caddy ──► Service (HTTP/HTTPS)
SSH/WG ──► Management plane (via itpp-infra key)
S3 (Wasabi) ──► Backup plane (all servers)
```
**Shared dependencies:**
- **SSH access:** `itpp-infra` key (Hetzner vault or deployed per-server)
- **DNS:** Cloudflare (primary) / SiteGround (legacy for itpropartner.com)
- **Backup storage:** Wasabi S3 (us-east-1)
- **SMTP relay:** mail.germainebrown.com:2525 (MXroute)
- **Auth/SSO:** Cloudflare Access (DRE portal)
- **Monitoring:** Prometheus node_exporter on each server
- **VPN:** WireGuard for management access
---
## Server 1: Core (netcup RS 2000 G12)
**Hostname:** core
**IP:** 152.53.192.33
**Provider:** netcup (RS 2000 G12, 8C EPYC 9645, 16GB RAM, 512GB NVMe)
**OS:** Debian 13
**Status:** 🟢 LIVE — Primary Hermes host
### Purpose
Main operations server. Runs Hermes, Docker services, ops portal, WireGuard hub,
SMTP relay, local LLM fallback.
### Services Running
| Service | Type | Port | Notes |
|---------|------|------|-------|
| Hermes Agent | systemd | Telegram | Primary agent - deepseek-chat via admin-ai |
| Caddy | systemd | 80/443 | Reverse proxy for all domains |
| WireGuard (wg0) | systemd | 51821/udp | Tunnel to home router (10.77.0.1) |
| MySQL tunnel | autossh | 33060→wphost02:3306 | Apex database access |
| SearXNG | Docker | 8888 | Self-hosted search |
| DocuSeal | Docker | 3000 | Document signing |
| Vaultwarden | Docker | 8080/tailscale | Password manager |
| Ollama | systemd | 11434 | Local LLM fallback (llama3.2:3b) |
| Ops Portal | systemd | 8090 | FastAPI backend |
| node_exporter | systemd | 9100 | Prometheus metrics |
### Docker Containers
- searxng, docuseal, vaultwarden (compass), + others under /root/docker/
### Backup
- **Hermes state:** Every 15 min to s3://hermes-vps-backups/live/ (state.db + config)
- **Full Hermes:** Daily 5 AM to s3://hermes-vps-backups/hermes-full-backup/
- **Memory snapshots:** Every 10 min to s3://hermes-vps-backups/live/memories/
- **Docker volumes:** Manual (not automated)
### Restore Procedure
```bash
# 1. Provision RS 2000 G12 (or better) on netcup
# 2. Install Debian 13, apply base standard (see server-provisioning-standard-v1.md)
# 3. Install Hermes:
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
# 4. Restore from S3 backup:
aws s3 cp s3://hermes-vps-backups/hermes-full-backup/<latest> /root/restore.tar.gz \
--endpoint-url https://s3.us-east-1.wasabisys.com
tar -xzf /root/restore.tar.gz -C /root/.hermes/
# 5. Restore Docker stacks:
cd /root/docker/searxng && docker compose up -d
cd /root/docker/docuseal && docker compose up -d
cd /root/docker/vaultwarden && docker compose up -d
# 6. Restore Caddy config from S3:
aws s3 cp s3://hermes-vps-backups/live/config/Caddyfile /etc/caddy/ \
--endpoint-url https://s3.us-east-1.wasabisys.com
# 7. Restart services:
systemctl restart caddy
systemctl restart hermes
# 8. Verify: ops.itpropartner.com, Teleegram, WG tunnel
```
### Failover
- **app1-bu** (5.161.114.8) is warm standby. Checks Core every 5 min.
- If Core unreachable for 2 min → app1-bu syncs S3 state + starts Hermes gateway.
- Restore Core, then manually fail back.
---
## Server 2: wphost02 (Hetzner CPX21)
**Hostname:** wphost02
**IP:** 5.161.62.38
**Provider:** Hetzner (CPX21, 3C/4G/80GB)
**OS:** Debian 12 (RunCloud managed)
**Status:** 🟡 LIVE — Recently reconnected after SSH firewall fix
### Purpose
Apex Predators Track Experience WordPress site. RunCloud-managed.
WPForms registration + notification emails.
### Services Running
- nginx-rc (RunCloud) — 80/443
- MariaDB — 3306
- Postfix — 25 (relay via mail.germainebrown.com:2525)
- httpd — 81 (RunCloud internal)
- RunCloud agent — 34210
- node_exporter — 9100
### Docker Containers
**None.** RunCloud manages PHP directly.
### Backup
- **RunCloud backup:** Daily via RunCloud panel
- **MariaDB dumps:** Not automated externally
- **WordPress files:** Managed by RunCloud
### Restore Procedure
```bash
# 1. Provision CPX21 (or better) on Hetzner
# 2. Install Debian 12
# 3. Connect to RunCloud via their panel
# 4. RunCloud provisions nginx, MariaDB, PHP
# 5. Restore WordPress from RunCloud backup
# 6. Add itpp-infra SSH key in RunCloud → SSH Access
# 7. Whitelist Core IP (152.53.192.33) in RunCloud firewall
# 8. Restore Postfix relay config:
# - relayhost = mail.germainebrown.com:2525
# - SASL auth with email@redacted
# 9. Verify: apextrackexperience.com loads, forms submit
```
### Dependencies
- Core MySQL tunnel connects here (port 33060→3306)
- Apex mail watchdog monitors via SSH
---
## Server 3: ai.itpropartner.com (Hetzner CPX41)
**Hostname:** ai
**IP:** 178.156.167.181
**Provider:** Hetzner (CPX41, 4C/16G/226GB)
**OS:** Debian 12
**Status:** 🟡 LIVE — 🔴 92% disk full (18G free)
### ⚠️ CRITICAL: Disk at 92%. Needs cleanup before migration.
### Purpose
**Critical infrastructure.** Runs LiteLLM proxy that ALL Hermes instances use
for model inference (deepseek-chat, claude-opus). Also runs:
- Open WebUI — AI chat interface
- Ollama — local LLM inference
- Qdrant — vector database
- Caddy — reverse proxy
### Services Running
- LiteLLM — systemd service, port varies (API at admin-ai.itpropartner.com)
- Docker containers: openwebui, litellm, litellm_postgres, caddy, qdrant, ollama
- node_exporter — 9100
### Backup
- **LiteLLM config:** In /root/. hermes/.env and config.yaml (API key: sk-lbh...)
- **Docker volumes:** Not backed up to S3
- **Ollama models:** Would need re-pull (cache only)
### Restore Procedure
```bash
# 1. Provision CPX41 (or better) on netcup as part of migration
# 2. Install Debian 13, Docker
# 3. Deploy LiteLLM Docker stack:
# - From /opt/litellm/docker-compose.yml
# - Restore postgres data for LiteLLM routes
# 4. Deploy Ollama:
# - Pull model: ollama pull llama3.2:3b
# 5. Deploy Open WebUI:
# - From /opt/openwebui/docker-compose.yml
# 6. Deploy Caddy config for admin-ai.itpropartner.com
# 7. Update DNS: admin-ai.itpropartner.com → new IP
# 8. Update Hermes config.yaml on all profiles to point to new IP
# 9. Verify: curl https://admin-ai.itpropartner.com/v1/models
# 10. Decommission old Hetzner server
```
### 🔴 Pre-Reboot Checklist
```bash
# Before ANY reboot or migration of this server:
# 1. Verify at least ONE alternative model provider works:
curl https://admin-ai.itpropartner.com/v1/chat/completions \
-H "Authorization: Bearer sk-lbh..." \
-d '{"model":"deepseek-chat","messages":[{"role":"user","content":"ping"}]}'
# 2. Ensure local Ollama on Core is running:
curl http://127.0.0.1:11434/api/tags
# 3. Notify all Hermes users (Germaine, Anita, Tony)
```
### Dependencies
- **ALL Hermes instances** depend on this server's LiteLLM proxy
- If this goes down, Hermes falls back to local Ollama (llama3.2:3b on Core)
- **Tony's Hermes** has no fallback — would be offline
---
## Server 4: unms.forefrontwireless.com (Hetzner CPX21)
**Hostname:** unms
**IP:** 5.161.225.131
**Provider:** Hetzner (CPX21, 3C/4G/80GB)
**OS:** Debian 12
**Status:** 🟢 LIVE — 4d 11h uptime
### Purpose
UISP/UNMS (WISP management) + UCRM (customer management).
Manages tower routers and customer billing for Forefront Wireless.
### Docker Containers (9)
unms-api, unms-device-ws-1, unms-device-ws-2, unms-nginx, unms-rabbitmq,
unms-postgres, unms-siridb, unms-fluentd, ucrm
### Backup
- **Docker volumes:** postgres data, UCRM data
- **UNMS config:** Exportable from UNMS UI
### Restore
```bash
# 1. Provision CPX21 → Reinstall Debian 12 + Docker
# 2. Restore docker-compose stacks from backup
# 3. Restore Postgres volumes
# 4. Update DNS for unms.forefrontwireless.com
# 5. Re-register tower routers in UNMS
```
---
## Server 5: unifi (Hetzner CPX21)
**Hostname:** unifi
**IP:** 178.156.131.57
**Provider:** Hetzner (CPX21, 3C/4G/80GB)
**OS:** Debian 12
**Status:** 🟢 LIVE — Recently rebuilt (6h uptime)
### Purpose
UniFi Network Controller — manages Ubiquiti network equipment.
### Services
- MariaDB
- UniFi Controller software (native, not Docker)
### Backup
- UniFi backup via controller UI (automatic backups)
- MariaDB database backup
### Restore
```bash
# 1. Provision CPX21 → Install UniFi controller
# 2. Restore UniFi backup from last export
# 3. Update DNS for unifi.itpropartner.com
# 4. Adopt APs/switches back
```
---
## Server 6: hudu.itpropartner.com (Hetzner CPX21)
**Hostname:** hudu
**IP:** 178.156.130.130
**Provider:** Hetzner (CPX21, 3C/4G/80GB)
**OS:** Debian 12
**Status:** 🟢 LIVE
### Purpose
Hudu IT documentation platform — internal knowledge base.
### Docker Containers (5)
hudu2-app-1, hudu2-worker-1, hudu2-db-1, hudu2-redis-1, letsencrypt
### Backup
- **Hudu automatic:** Built-in backup to S3-compatible storage
- **Postgres DB:** Daily dump
### Restore
```bash
# 1. Provision CPX21 → Install Docker
# 2. Deploy Hudu Docker stack
# 3. Restore Postgres from backup
# 4. Update DNS
```
---
## Server 7: fleettracker360 (Hetzner CPX11)
**Hostname:** fleettrack360
**IP:** 178.156.149.32
**Provider:** Hetzner (CPX11, 2C/2G/40GB)
**OS:** Debian 12
**Status:** 🟢 LIVE
### Purpose
Fleet tracking application (BoxPilot Logistics?).
### Services
- Apache2 (80/443)
- MariaDB (3306)
### Backup
- Apache config + web root
- MariaDB database dump
---
## Server 8: docker (Hetzner CPX11)
**Hostname:** docker
**IP:** 178.156.168.35
**Provider:** Hetzner (CPX11, 2C/2G/40GB)
**OS:** Debian 12
**Status:** 🟢 LIVE — 🔴 Disk 73% used (9.9G free on 38G)
### Purpose
RunCloud staging + utility containers:
- Nginx Proxy Manager
- RustDesk server (hbbr, hbbs)
- Uptime Kuma
- StrongSwan
### Docker Containers (8)
runcloud_php56, runcloud_php81, runcloud_mariadb, nginx-proxy-manager,
hbbr, hbbs, strongswan, uptime-kuma
---
## Server 9: app1 / n8n (Hetzner CPX11)
**Hostname:** n8n
**IP:** 87.99.144.163
**Provider:** Hetzner (CPX11, 2C/2G/40GB)
**OS:** Debian 12
**Status:** 🟢 LIVE
### Purpose
n8n workflow automation.
### Docker Containers (2)
n8n, n8n-postgres
---
## Server 10: tony-vps (Hetzner CPX21)
**Hostname:** tony
**IP:** 87.99.159.142
**Provider:** Hetzner (CPX21, 3C/4G/80GB)
**OS:** Debian 12
**Status:** 🟢 LIVE
### Purpose
Tony's standalone Hermes agent. Separate from main infrastructure.
### Services
- llama-server (systemd) — Llama 3.2 1B local fallback
- hermes-heartbeat.sh (cron — every minute)
### Notes
- **Tony's independent instance** — not managed from Core
- Uses admin-ai for primary model, local Llama 1B for fallback
- No Docker containers
---
## Server 11: app1-bu (Hetzner CPX11 — Warm Standby)
**Hostname:** app1-bu.itpropartner.com
**IP:** 5.161.114.8
**Provider:** Hetzner (CPX11, 2C/2G/40GB)
**OS:** Debian 12
**Status:** 🟢 STANDBY — Warm, gateway dormant
### Purpose
**Hermes warm standby.** Clones Core's state via S3 sync.
### Services
- SSH (22)
- Tailscale
- node_exporter (9100)
- WireGuard (wg0 — tunnel to home router at 10.77.0.3)
### Failover Procedure
```bash
# Automatic (watchdog on app1-bu):
# 1. Checks Core every 5 min (ping + Hermes health)
# 2. If Core down for 2 min → sync latest S3 state
# 3. Integrity check on state.db (PRAGMA quick_check)
# 4. Start Hermes gateway → Telegram accessible
# 5. Write ACTIVE_OWNER lock to S3
# Manual activation:
ssh -i /root/.ssh/itpp-infra root@5.161.114.8
hermes gateway run --replace
# Or if Core is fenceable:
ssh root@152.53.192.33 "systemctl stop hermes && systemctl mask hermes"
```
### Restore
```bash
# 1. Power on via Hetzner API or console
# 2. Ensure S3 sync runs:
# /root/.hermes/scripts/hermes-standby-sync.sh
# 3. Check integrity:
# sqlite3 /root/.hermes/state.db "PRAGMA integrity_check;"
# 4. If good → start gateway:
# hermes gateway run
# 5. If corrupt → restore from snapshot:
# aws s3 cp s3://hermes-vps-backups/snapshots/<latest> /root/
```
---
## DR Classification Matrix
| Server | Tier | RTO Target | RPO Target | Restore Complexity |
|--------|------|-----------|-----------|-------------------|
| Core | 🔴 Critical | 5 min (failover) | 15 min | Medium (Docker + Hermes) |
| ai (admin-ai) | 🔴 Critical | 2 hours | 24 hours | High (migration) |
| wphost02 | 🟡 Important | 4 hours | 24 hours | Low (RunCloud restore) |
| unms | 🟡 Important | 4 hours | 24 hours | Medium (Docker stack) |
| hudu | 🟡 Important | 4 hours | 24 hours | Medium (Docker stack) |
| unifi | 🟡 Important | 4 hours | 24 hours | Low (native install) |
| n8n | 🟢 Standard | 8 hours | 24 hours | Low (2 containers) |
| docker | 🟢 Standard | 8 hours | 24 hours | Medium (8 containers) |
| fleettracker360 | 🟢 Standard | 8 hours | 24 hours | Low (LAMP stack) |
| tony-vps | 🟢 Standard | Coordinate | 24 hours | Low (minimal) |
| app1-bu | 🔴 Standby | 2 min | 15 min | Low (S3 sync) |
---
## Recovery Bundle Location
Each server's recovery configs are bundled at:
- `/root/.hermes/recovery-bundle-2026-07-05.md` (Core — needs refresh)
- `/root/.hermes/references/server-dr-plans.md` (this document)
- `/root/.hermes/references/server-provisioning-standard-v1.md` (base install)
**S3 backup of this document:**
`s3://hermes-vps-backups/live/config/server-dr-plans.md`