# Cluster Operations & Resilience

## Cluster-Zugang

Claude Code hat **direkten SSH-Root-Zugang** auf alle 5 mTLS-Cluster-Server ueber das VLAN (10.0.0.0/16):

| # | Hostname | Extern | VLAN | Standort |
|---|----------|--------|------|----------|
| 1 | Cert-Server-1-NBG | 188.245.157.241 | 10.0.0.2 | Nuernberg |
| 2 | Cert-Server-0-NBG | 116.203.243.240 | 10.0.0.3 | Nuernberg |
| 3 | Cert-Server-0-FSN | 49.12.76.141 | 10.0.0.4 | Falkenstein |
| 4 | Cert-Server-1-FSN | 91.98.147.79 | 10.0.0.5 | Falkenstein |
| 5 | Cert-Server-HEL | 46.62.131.226 | 10.0.0.6 | Helsinki |

**Referenz-Server:** 10.0.0.2 (Cert-Server-1-NBG) — hier wird konfiguriert, per rsync verteilt.

**Fixed-IP-Server** (kein SSH, nur Port 443):
- 49.12.179.109 (-b, Bund)
- 49.12.179.110 (-bw, Bundeswehr)

## Resilience-Architektur (Stand: 2026-04-16)

### DNS Load-Balancing
- Cloudflare DNS Round-Robin ueber alle 5 Server
- TTL: 60s (Kompromiss: schnelles Failover + wenig DNS-Overhead)

### Peer-Monitoring mit Quorum
- **Script:** `dns-maintenance peer-check` (in dns-maintenance.sh integriert)
- **Timer:** `dns-peer-check.timer` — alle 30s auf allen 5 Servern
- **Probe:** curl auf externe IP:443 (nicht VLAN)
- **Failcount-Schwelle:** 6 (= 3 Min konsekutiv down)
- **Quorum:** >= 3 Votes via SSH an andere Peers
- **Aktion:** Emergency-Drain der DNS-Records des toten Peers
- **Dry-Run:** Aktuell aktiv (`PEER_DRY_RUN=true`), nur Logging
- **Kill-Switch:** `/etc/dns-maintenance-no-peer-drain`
- **Cooldown:** 10 Min nach Drain
- **Selbst-Check:** Apache-Health + auto-restart bei Ausfall
- **Fixed-IP:** Monitoring (Alert only, kein Auto-Drain)

### Apache KeepAlive
- `KeepAliveTimeout 120` (Partner-Connections bleiben 2 Min offen)
- `MaxKeepAliveRequests 1500` (abgeleitet aus Peak: 1.378 req/h)
- `mpm_event` (idle Connections im Event-Thread, kein Worker-Block)

### Certbot (verteilte Erneuerung)
- Certbot 5.5.0 (snap) + dns-cloudflare auf allen 5 Servern
- Selber ACME-Account, selbe Cloudflare-Credentials
- **Timer gestaffelt** (2h Abstand): .2→00:10/20:23, .3→02:10/22:23, .4→04:10/00:23, .5→06:10/02:23, .6→08:10/04:23
- **Deploy-Hook:** Validiert Cert (openssl) + Apache-Test (curl localhost) **vor** Sync an Peers
- rsync ohne --delete (ueberschreibt nur, loescht nie)
- Let's Encrypt ist idempotent — wer zuerst erneuert gewinnt

### DNS Maintenance (Drain/Restore)
- **Script:** `/root/projects/cert-pki/scripts/dns-maintenance.sh` (symlink `/usr/local/sbin/dns-maintenance`)
- **Drain-Timeout:** 900s (15 Min)
- **Quiet-Period:** 300s (5 Min ohne Requests)
- **TTL:** 60s (beide Zonen)
- **Systemd-Integration:** ExecStart=restore (Boot), ExecStop=drain (Shutdown)
- **Rolling-Reboot:** drain-and-reboot pro Server, 2 Min Pause dazwischen

### Monitoring & Alerting
- **Wazuh Agent** (v4.14.4): Security/Compliance, Cloud-Backend
- **New Relic** (aktiv seit 2026-04-16): Infrastructure Agent v1.73.1 + Log-Forwarding (Apache2 + System-Logs), siehe [NEWRELIC.md](NEWRELIC.md)
- **Alerting:** `send_alert()` in dns-maintenance.sh, Webhook-faehig (`ALERT_WEBHOOK_URL`)
- **verify-deployment.sh:** 28-Check Audit ueber SSH auf alle 5 Server (seit 2026-04-21 P6-Konsolidierung)

### Backups
- Hetzner Cloud Backups (Server-Snapshots)

### Claude Code
- Auf allen 5 Servern als root installiert (v2.1.110)
- `.claude/` Config via lsyncd automatisch synchronisiert
- Details: [CLAUDE-INSTALL.md](CLAUDE-INSTALL.md)

## Offene Punkte
- Peer-Check Dry-Run nach 1-2 Wochen Beobachtung deaktivieren (`PEER_DRY_RUN=false`)
- ~~New Relic Agent installieren~~ (erledigt 2026-04-16, siehe [NEWRELIC.md](NEWRELIC.md)) + Alert-Policies konfigurieren
- ALERT_WEBHOOK_URL konfigurieren (Slack/PagerDuty)
- .2 noch nicht rebootet (Kernel 6.8.0-88 statt 110)
