Files

171 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: server-architecture-plan
description: ITPP infrastructure architecture — server roles, service placement, and the migration plan from Hetzron to netcup. Approved July 2026.
tags: [infrastructure, architecture, netcup, migration, planning, RBAC]
---
# Server Architecture Plan
## Approved Architecture (July 2026) — Rebalanced Jul 12
### Base Server Standard
All new netcup servers are **RS 4000 G12** — 12 dedicated EPYC 9645 cores, 32 GB DDR5 ECC RAM, 1 TB NVMe, ~$44/mo. Exception: Core (RS 2000) keeps Hermes + LiteLLM + Ollama fallback. core-bu (Hetzner, was app1-bu) is warm standby, pending CPX11→CPX31 upgrade.
### Server Roles — Post-Rebalance
| Box | Model | Cost | IP | Role |
|-----|-------|------|-----|------|
| **Core** | RS 2000 | ~$24/mo | 152.53.192.33 | **Hermes + MCPs only**. LiteLLM, Caddy, Portal, Super Search, Ollama moved to app1/decommissioned. See audit Jul 13. |
| **app1** | RS 4000 | ~$44/mo | 152.53.36.131 | **Service hub** — Caddy (all domains), Ops Portal, OSINT API, Super Search MCP, SearXNG, Grafana, cron, n8n + Postgres, Docker services |
| **app2** | RS 4000 | ~$44/mo | 152.53.39.202 | **Infrastructure** — UNMS/UISP, UniFi Controller, Hudu (target), Traccar (target) |
| **app3** | RS 4000 | ~$44/mo | 152.53.241.111 | **Web apps** — WordPress/Apex from wphost02/SiteGround |
| **core-bu** (was app1-bu) | CPX11→CPX31 | ~$22/mo | 5.161.114.8 | Warm standby, needs upgrade for DR capacity |
| | | **~$174/mo** | | |
### Hetzner Cleanup Plan (Jul 15, 2026 — mostly complete)
**Deleted today (Jul 15):**
- unifi (178.156.131.57) — ✅ Old UniFi controller decommissioned, backups in S3, server deleted
- hudu (178.156.130.130) — ✅ Full data migration to app2 verified (135 assets, 125 passwords, 18 layouts restored), server deleted
- unms (5.161.225.131) — ✅ UNMS running on app2, full backup to S3 (994MB + 1,107 configs), server deleted
**Previously deleted:**
- fleettracker (178.156.149.32) — ✅ Deleted Jul 14
**Remaining Hetzner servers (4):**
- core-bu (5.161.114.8) — Warm standby, keep
- ai.itpropartner.com (178.156.167.181) — LiteLLM, pending migration to app1
- wphost02 (5.161.62.38) — WordPress, pending migration to app3
- app1.itpropartner.com (87.99.144.163) — Old app1, deprecated
### Why RS 4000 as standard
- 12 dedicated EPYC cores — no shared vCPU contention
- 32 GB ECC RAM — headroom for Java apps (UniFi, Traccar) + 20+ Docker containers
- 1 TB NVMe — Ollama models alone need 50+ GB, plus UNMS/UISP data
- Fault isolation — an outage on app2 doesn't touch Core or app1
## Service Placement
### Core (RS 2000) — Existing, paid
- Hermes Agent (systemd, port 8081)
- Caddy reverse proxy (systemd, ports 80/443)
- Ops Portal backend (FastAPI, systemd, port 8090)
- Prometheus + Grafana (Docker)
- **Uptime-Kuma** (Docker, `/root/docker/uptime-kuma/`, port 3001) — migrated from docker server Jul 13 with 9 monitors + Telegram/Discord/Slack notifications
- FT360 MCP server (FastMCP, systemd, port 8903, `/root/docker/ft360-mcp/`) — 3 tools: get_devices, get_positions, get_stats. Queries Traccar H2 on app2 via SSH+SCP pattern
- Vaultwarden, DocuSeal, SearXNG, Twenty CRM (Docker under /root/docker/*/)
- Tailscale (systemd)
- **Super Search** — FastMCP server at http://127.0.0.1:8899/mcp (systemd: super-search.service). Multi-provider web search: SearXNG → Exa → OpenCorporates → CourtListener → Firecrawl, plus Trafilatura extraction + premium Exa endpoint. All 3 exposed as Hermes MCP tools: `web_search`, `web_extract`, `web_search_premium`. v1.2.0: token-bucket rate limiting, TTL caching, exponential backoff per provider. Deployed at `/root/docker/super-search/server.py` via venv.
### app1 (RS 4000) — 152.53.36.131 — Currently Live
- Ollama (`ollama/ollama:latest`) — running
- Open WebUI (`ghcr.io/open-webui/open-webui:latest`) — running on :3000
- n8n (`n8nio/n8n:latest`) — running on :5678, proxied at n8n.itpropartner.com
- n8n-postgres (`postgres:16-alpine`) — running
- **LiteLLM** — NOT yet deployed (target for admin-ai migration)
- Caddy 2.6.2 — active on 80/443, proxying n8n and Open WebUI
- 1TB disk — 3% used (943 GB free), 32 GB RAM, 12C EPYC
- All deployments per docker-service-deployment standard at /root/docker/*/
See `references/admin-ai-migration-plan.md` for the detailed cutover plan (Phase 03).
See `references/core-rebalance-plan.md` (created Jul 12, 2026) for the full service rebalance — moving Caddy, Ops Portal, Super Search, SearXNG, Grafana, cron from Core → app1; LiteLLM from Hetzner old-ai → Core; Ollama fallback from app1 → Core. 6-phase executable plan with DNS cutover and rollback.
### app2 (RS 4000) — New
- UNMS/UISP full stack (10 Docker containers: nginx, API, device-ws, PostgreSQL, SiriDB, RabbitMQ, Fluentd, Netflow)
- UCRM (customer management CRM)
- UniFi Controller (native Java app + MongoDB)
- Hudu (**full migration complete Jul 15** — 21 companies, 135 assets, 125 passwords, 18 custom layouts all verified on app2. Old server 178.156.130.130 deleted. Daily backup cron active: 3 AM ET → S3, 30-day retention)
- Traccar (Docker at `/root/docker/traccar/` — port 8082 web dashboard + 5000-5150 TCP/UDP for GPS device protocols). Cloudflare DNS: fleettracker360.com, gps.fleettracker360.com, www.fleettracker360.com → 152.53.39.202
### app3 (RS 4000) — New
- WordPress/Apex Track Experience (from wphost02 via RunCloud or standalone Nginx)
- Other WordPress sites (from wphost02 / SiteGround)
- Web apps requiring PHP/Nginx stack
### app1-bu (Hetzner CPX11) — Stays
- Warm standby for Core
- Hermes gateway dormant
- StrongSwan + L2TP
- Watchdog checks Core every 5 min, 2 min confirmation window
## Migration Status
### Ready to migrate
- **ai.itpropartner.com** (LiteLLM, Open WebUI, Ollama, Qdrant) → **app1**
- LiteLLM uses PostgreSQL DB for model configs — dump/restore
- Open WebUI data in SQLite at /app/backend/data/webui.db (~121 MB, 1.9 GB total)
- Ollama models at /root/.ollama (need to copy or re-pull)
- CRITICAL: admin-ai.itpropartner.com must have zero downtime. Set up new proxy first, test, switch DNS, decommission old.
- **n8n** (current Hetzner app1) → **app1**
- Docker compose at /opt/n8n/ — migrate volumes
- Benefits from direct Ollama access on same box
### Approved for migration (pending execution)
- UNMS/UISP → app2 (Docker stack ready, DNS pending SiteGround update)
- **UniFi Controller** → app2 (deployed Jul 12 at 152.53.39.202:8443, backup .unf file import needed)
- **Traccar GPS** → app2 (ready for fresh Docker deploy, HERE Maps API for traffic-aware ETA)
- **Hudu → app2** (🔴 PARTIAL — DNS cut over, companies migrated, but assets/passwords tables empty. Old server still up with all data. Full DB re-dump/restore needed. See `docker-service-deployment` skill for verification queries.)
- WordPress → app3
### Stays at Hetzner
- app1-bu (warm standby)
- tony-vps (Anthony's Hermes)
- Container host "docker" (178.156.168.35) — NPM, RustDesk, StrongSwan, RunCloud stack remain. Uptime-Kuma migrated to Core Jul 13. Server decommissioning deferred until RunCloud web apps migrate to app3 and RustDesk/StrongSwan decisions are made.
### API Access Status (Jul 13, 2026)
- **Hetzner API token expired** — server deletion/provisioning requires manual Hetzner Cloud Console access until token is rotated
- **SiteGround DNS** — no API; all DNS changes for itpropartner.com and related domains must be manual through SiteGround web panel
## Estimated Monthly Cost Breakdown
| Server | Provider | Model | Cost |
|--------|----------|-------|------|
| Core | netcup | RS 2000 | ~$24 |
| app1 | netcup | RS 4000 | ~$44 |
| app2 | netcup | RS 4000 | ~$44 |
| app3 | netcup | RS 4000 | ~$44 |
| app1-bu | Hetzner | CPX11 | ~$8 |
| **Total** | | | **~$164/mo** |
| Current Hetzner total | Hetzner | 10 VPS | ~$150/mo (inflated) |
## RBAC Model (for ops portal)
| Role | Scope | Who |
|------|-------|-----|
| **Admin** | Full access — servers, customers, billing, provisioning, DNS, audit logs | Germaine |
| **Tech/Support** | Tickets, server status, network health. No billing, no provisioning. | Future hire |
| **Sales/Onboarding** | Customer activations, provisioning status, order forms | Future hire |
| **Viewer** | Read-only, limited scope | Anita, auditors |
Roles built into ops portal from day one. Not retrofitted.
## Docker Standard Reference
All services at /root/docker/<name>/ with:
- One `docker-compose.yml`, one `.env` (chmod 600)
- Healthchecks on every service
- Resource limits per container
- Named volumes (not bind mounts for app data)
- Internal-only networks for service-to-service traffic
- Logging with rotation (max-size 10m, max-file 3)
- Automated S3 backup of volumes
## Pitfalls
- **admin-ai goes down = Sho'Nuff loses model access.** Fallback chain: deepseek-v4-pro (admin-ai) → deepseek/deepseek-chat (OpenRouter) → cheap API fallbacks. No Ollama. admin-ai lives on app1 for fault isolation — Core and admin-ai should not share the same box.
- **Do NOT put all AI containers in one compose file.** Each service gets its own /root/docker/<name>/ — LiteLLM, Open WebUI are separate.
- **UniFi on app2 needs MongoDB.** Must migrate the native MongoDB database along with the controller. Cannot just copy files.
- **Traccar device ports: 5000-5150 TCP+UDP** — Ensure firewall allows this range. GPS devices connect directly (non-proxied DNS at `gps.fleettracker360.com`). Web dashboard on port 8082.
- **UNMS uses fixed version tags (3.0.140, 4.5.31).** Do not use `:latest` for Ubiquiti images — they break on minor releases.
- **admin-ai placement decided Jul 13: app1, not Core.** LiteLLM migration target is app1 (152.53.36.131). Core keeps Hermes + MCPs only. See architecture audit at `/root/.hermes/references/architecture-audit-2026-07-13.md`.
- **Ollama removed Jul 13.** Too weak for real work, wasted RAM on Core. Replacement: cheap API fallbacks (deepseek-v4-flash, qwen3-flash via OpenRouter). Remove ollama.service from Core, delete llama3.3:70b (42GB disk waste).
- **Caddy + existing containers port conflict (app2)** — When Caddy shares a box with services like UNMS nginx (port 443), Caddy's auto port 80 binding also conflicts. Fix: use `auto_https disable_redirects` + explicit `domain:443` blocks in Caddyfile. Change existing containers to only bind their required ports.
- **Hudu migration: verify ALL tables, not just companies (Jul 15, 2026).** Initial pg_dump/restore only copied the `companies` table — `assets` and `asset_passwords` were empty on the target. Post-migration verification must query every major table (`companies`, `assets`, `asset_passwords`) and compare row counts between old and new before declaring done. Use `curl --resolve` to hit both old and new IPs through the domain for side-by-side API comparison. See `docker-service-deployment` skill for the full pattern.
```
{
default_bind 152.53.192.33
}
```
This tells Caddy to bind only the public IP. Tailscale keeps its Tailnet IP. Both coexist without conflict. Verify with `caddy validate --config /etc/caddy/Caddyfile` then `systemctl start caddy`.