## Infrastructure Migration Plan (Jul 2026)

### Target Architecture

| Server | Provider | Model | Cost/mo | Role |
|--------|----------|-------|---------|------|
| **Core** | netcup RS 2000 | 8C/16G/512GB | ~$24 (paid) | Hermes, Docker (Vaultwarden, Docuseal, SearXNG, Twenty), Portal, Prometheus, Uptime-Kuma, Caddy, VPN |
| **app2** | netcup RS 4000 | 12C/32G/1TB | ~$44 | UNMS/UISP, UniFi Controller, Hudu, Traccar |
| **app3** | netcup RS 2000 | 8C/16G/512GB | ~$24 | WordPress/Apex, web apps |
| **app1-bu** | Hetzner CPX11 (2C/2G) | Staying | Paid | Warm standby for Core. Keep in place. |

### Migration rules

1. **Zero downtime for admin-ai.itpropartner.com** — LiteLLM (deepseek-chat proxy for Sho'Nuff) must stay live during migration. Set up new LiteLLM on Core first, test via alternate URL, switch DNS.
2. **Admin-ai uses PostgreSQL for model configs** — DB dump/restore, not config file.
3. **Open WebUI conversations are in SQLite** — stop container, copy `/app/backend/data/` (1.9 GB), restore on new box.
4. **Migration order:** AI stack first (most critical), then UNMS/UniFi, then web apps.
5. **app1-bu stays warm at Hetzner** — do not migrate. It's the safety net.
6. **New boxes follow Docker install standard** — `/root/docker/<service>/`, healthchecks, resource limits, internal networks, named volumes, .env chmod 600.
7. **SSH key for new boxes:** Deploy `itpp-infra` key during provisioning.
8. **New boxes provisioned via netcup SCP** (no API for provisioning — use web UI at servercontrolpanel.de).
9. **app2 needs RS 4000** — UNMS (10 containers + Java/PostgreSQL/RabbitMQ) + UniFi (Java + MongoDB + MariaDB) + Hudu (5 containers) + Traccar (Java + 26 ports) needs 12C/32G to avoid contention.
10. **Billing:** Monthly (not annual), Virginia (Manassas) location.

### admin-ai migration — critical path

admin-ai.itpropartner.com (LiteLLM on ai box at Hetzner) serves the deepseek-chat model that powers Sho'Nuff. It is the most critical service. Sequential steps:

1. Set up new LiteLLM + PostgreSQL on Core (or Monitor box)
2. Dump old PostgreSQL: `docker exec litellm_postgres pg_dump -U litellm litellm_db > litellm-dump.sql`
3. Restore on new PostgreSQL
4. Test new proxy: `curl http://new-box:4000/v1/models` — should show all models
5. Update Hermes config to point at new proxy for testing
6. Switch admin-ai DNS record to new IP
7. Keep old ai box running for 7 days as fallback

### Cron after migration

- Core retains: `hermes-live-sync`, `hermes-system-config-sync`, `hermes-docker-sync`, `ops-data-collector`, `shark-scraper`, `home-router-daily-backup` (via WG to 10.77.0.2), `vps-threshold-check`
- app2 gets: local UNMS/UniFi/etc. cron jobs, node_exporter for Prometheus scraping
- app3 gets: WordPress cron, node_exporter
- app1-bu keeps: `hermes-standby-watchdog`, `hermes-standby-sync`

### Cost comparison

| | Current (Hetzner) | Target (netcup) |
|---|---|---|
| Servers | 9 + app1-bu | Core + app2 + app3 + app1-bu |
| Monthly | ~$150-160 | ~$68 (app2 + app3) + Core (paid) |
| Savings | — | **~$82-92/mo** |

### Unchanged services

- Nginx Proxy Manager (stays on docker Hetzner box — remaining services there still need reverse proxy)
- RustDesk (stays on docker Hetzner box)
- StrongSwan Docker (stays on docker Hetzner box)
- RunCloud MariaDB instances on decommissioned Hetzner boxes — not migrated, databases stay with their apps
