diff --git a/README.md b/README.md index 5707a65..2dfd539 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Zentrale Dokumentation für die Proxmox-Umgebung **jeanavril**. |------|-----------------|-------|------| | **pve1** | 192.168.10.5 | Primärer Proxmox, Fallback-OPNsense | [pve1/](pve1/) | | **pve2** | 192.168.10.4 | Produktions-Proxmox, Router, GPU-Compute | [pve2/](pve2/) | +| **Horus** | 207.180.222.207 / WG 10.1.1.1 | Contabo-VPS: WireGuard-Hub, Mailserver, DNS, SSO, Apps | [horus/](horus/) | DNS intern: `*.iot` → VLAN 40 (z. B. `homeassistant.iot` → 192.168.40.254) @@ -20,6 +21,8 @@ docu/ ├── README.md ← diese Datei ├── migration/ ← Schritt-für-Schritt Updates & Tuning ├── shared/ ← übergreifend (MQTT, Git, Netzwerk) +├── issues/ ← abgeschlossene Vorfälle / Fehldiagnosen (Lessons Learned) +├── horus/ ← Contabo-VPS: WG-Hub, Mail, DNS, SSO, Apps ├── pve1/ ← pve1 inkl. guests/ (VM/CT-Stacks) └── pve2/ ← pve2 inkl. guests/ (falls vorhanden) ``` diff --git a/horus/README.md b/horus/README.md new file mode 100644 index 0000000..25b88a1 --- /dev/null +++ b/horus/README.md @@ -0,0 +1,54 @@ +# Horus — VPS (Contabo) + +Öffentlicher VPS, **WireGuard-Hub** und Anwendungsserver. Stand: 2026-06-28 (per Dienst-Discovery erhoben). + +| | | +|---|---| +| **Hostname** | `horus.jeanavril.com` | +| **Public IP** | `207.180.222.207` | +| **WireGuard-IP** | `10.1.1.1` (Hub für alle Peers) | +| **OS** | Debian 12 (bookworm) | +| **Provider** | Contabo (Zugang via Contabo-Weboberfläche → VNC) | + +## Zugang + +- **Wenn ein WG-Tunnel läuft:** `ssh jean@192.168.10.10` (VM 101) → `ssh root@10.1.1.1` +- **Wenn alle Tunnel tot sind:** über Public-IP `ssh root@207.180.222.207` — aber **SSH:22 ist per ufw nur über `wg0` offen**. Notfall: am Contabo-VNC `ufw allow ssh`, fixen, danach `ufw delete allow ssh`. VM 101 besitzt den Horus-SSH-Key. +- **ufw:** default deny incoming. Offen: `61951/udp` (WG), alles auf `wg0`, plus die unten gelisteten Dienst-Ports. + +## WireGuard + +- **Verwaltung: `wg-quick@wg0`** (systemd, enabled). **Es läuft KEIN wireguard-ui** (kein Prozess/Container/Port 5000) — die `wg0.conf` wurde nur *historisch* damit erzeugt. +- Server-Config: `/etc/wireguard/wg0.conf` (Header sagt „don't edit manually", aber maßgeblich ist, was `wg-quick` lädt → `wg show wg0` / `wg showconf wg0` ist die Wahrheit). +- Client-Keys/Configs: `/etc/wireguard/clients//` (je `client.conf`, `privatekey`, `publickey`, `presharedkey`), Backup unter `/etc/wireguard/bak/`. +- Listen-Port: `61951/udp`. PostUp/PostDown setzen iptables FORWARD/NAT. +- **Peers sauber löschen** (ohne UI): `[Peer]`-Block aus `wg0.conf` entfernen **+** `clients//` löschen **+** `wg syncconf wg0 <(wg-quick strip wg0)` (oder `systemctl restart wg-quick@wg0`). +- Vorfall NAT/Port siehe [../issues/2026-06-28-vm101-horus-wireguard-nat.md](../issues/2026-06-28-vm101-horus-wireguard-nat.md). + +## Dienste (Docker-Compose-Stacks) + +Web-Apps liegen i.d.R. hinter **nginx-proxy-manager** (Ports 80/443). + +| Stack | Verzeichnis | Zweck | Ports (extern) | +|-------|-------------|-------|----------------| +| **mailcowdockerized** | `/opt/mailcow` | Kompletter Mailserver (postfix, dovecot, rspamd, sogo, clamd, unbound, mysql, redis …) | 25, 465, 587, 110, 143, 993, 995, 4190; Web 8443/8880 | +| **infrastructure** | `/opt/infrastructure` | nginx-proxy-manager (Reverse Proxy) + MariaDB + watchtower | 80, 443; Admin `81` nur auf `10.1.1.1` (WG) | +| **sso** | `/opt/sso` | authentik (SSO / Identity Provider) + postgres + redis | 9000, 9443 | +| **bind9** (Container) | — | Autoritativer DNS | `207.180.222.207:53` tcp/udp | +| **collab** | `/opt/collab` | HedgeDoc (kollaborative Notizen) + postgres | hinter NPM | +| **files** | `/opt/files` | Caddy File-Server + filebrowser | hinter NPM | +| **kifin** | `/opt/projects/kifin` | App „ai-finance-simulations" | hinter NPM | +| **vectorseek** | `/opt/projects/vectorseek` | App (Port 3000) | hinter NPM | +| **website** | `/opt/website` | *gestoppt* (Exited vor ~15 Monaten) | — | + +## Eigene systemd-Dienste + +| Dienst | Zweck | +|--------|-------| +| `monitor-cert-changes.service` | `/usr/local/bin/monitor_cert_changes.sh` — überwacht Zertifikatsänderungen und startet Mailcow-Dienste neu (Teil der Cert-Automation, Certs kommen per rsync von VM 101). | +| `wg-quick@wg0.service` | WireGuard-Hub | +| `chrony`, `uptimed`, `docker`, `containerd` | Standard | + +## Bekannte Probleme + +- ⚠️ **`infrastructure-watchtower-1` crash-loopt** (`Restarting`). Log: *„client version 1.25 is too old. Minimum supported API version is 1.40"* — watchtowers Docker-API-Client ist zu alt für den Docker-Daemon. **Auto-Updates der Container laufen dadurch nicht.** Fix: watchtower-Image aktualisieren (`docker compose pull && up -d` in `/opt/infrastructure`) oder entfernen. diff --git a/issues/2026-06-28-vm101-horus-wireguard-nat.md b/issues/2026-06-28-vm101-horus-wireguard-nat.md new file mode 100644 index 0000000..2597a6d --- /dev/null +++ b/issues/2026-06-28-vm101-horus-wireguard-nat.md @@ -0,0 +1,73 @@ +# VM 101 ↔ Horus WireGuard tot — Ursache war NAT, nicht die Keys + +**Datum:** 2026-06-28 +**Status:** gelöst +**Betroffen:** WireGuard-Tunnel VM 101 (`server5`, `10.1.1.5`) ↔ Horus VPS (`10.1.1.1`) + +--- + +## Symptom + +- `ping 10.1.1.1` von VM 101 → 100 % Loss, **0 Bytes empfangen** +- WireGuard-Handshake auf VM 101 kam nie zustande (latest handshake blieb stehen) +- Der **OPNsense**-Tunnel zu Horus (`10.1.1.22`) lief dagegen normal weiter + +## Falsche Spur (kostete viel Zeit) + +Das Vorgänger-Handover führte alles auf **Key-/PSK-Chaos** zurück („kimi hat die Keys verstellt"). Das war für **dieses** Problem **falsch**: + +- VM-101-Seite: PrivateKey → Pubkey `VB3Cf8kD…`, PSK `xeXr67…` — korrekt +- Horus-Seite (Peer `VB3Cf8kD…`): **identischer** PSK `xeXr67…`, korrekte AllowedIPs `10.1.1.5/32, 10.2.2.0/24` +- Probeweises Setzen anderer PSKs (OPNsense-PSK `fBnIJ…`, leer) brachte **keinen** Handshake → es war kein Crypto-Problem + +## Diagnose, die zur Wahrheit führte + +Mit Root auf Horus (Zugang siehe unten) Paketfluss direkt gemessen: + +``` +# Auf Horus, tcpdump während VM 101 sendet: +In 93.199.218.174:46165 → 207.180.222.207:61951 UDP len 148 (Handshake-Init kommt an) +Out 207.180.222.207:61951 → 93.199.218.174:46165 UDP len 92 (Handshake-Response geht raus) +# Auf VM 101 gleichzeitig: In = 0 (Antwort kommt NIE an) +``` + +→ **Hinweg VM 101 → Horus OK, Rückweg Horus → VM 101 tot.** Horus antwortete korrekt an den Quellport (`:46165`), aber das Paket erreichte VM 101 nie. + +## Echte Ursache + +VM 101 sitzt hinter OPNsense (NAT). Ihr WireGuard nutzte den **festen** Quellport `61951`, der **konstant** auf WAN-Port `46165` ge-NAT-et wurde. Durch kimis `qm stop 104` + manuelle Wiederherstellung wurde der **NAT-/State-Tisch von OPNsense durchgewirbelt** — diese eine, langlebige Zuordnung `61951↔46165` war danach **verwaist**: Hinweg funktionierte, der Rückweg lief ins Leere. + +Da **UDP** verbindungslos ist, merkte WireGuard nichts und sendete endlos weiter, ohne je eine Antwort zu sehen. (Bezeichnend: **TCP-SSH** von VM 101 zu Horus' Public-IP ging — frischer Zufalls-Port = frische, gesunde NAT-Zuordnung.) + +## Lösung + +**Frischen Quellport auf der Client-Seite erzwingen** → neue, saubere NAT-Zuordnung: + +```bash +# Auf VM 101: +sudo wg set wg0 listen-port 51871 # Live-Test → Handshake sofort da +sudo sed -i 's/^ListenPort = 61951/ListenPort = 51871/' /etc/wireguard/wg0.conf # persistent +``` + +- **Nur Client-Seite (VM 101) geändert.** Horus' Port `61951` und alle Keys blieben unverändert. +- **Kein** Eingriff an OPNsense / VM 104. +- Reboot-getestet: `systemctl restart wg-quick@wg0` → kommt auf `51871` hoch, Handshake < 3 s. + +## Verifikation + +- `ping 10.1.1.1` von VM 101 → 3/3, ~24 ms +- SSH durch den Tunnel (`ssh root@10.1.1.1`) wieder OK +- Überlebt wg-Neustart + +## Nützliche Zugangswege (für nächstes Mal) + +- **Horus Root, wenn Tunnel läuft:** `ssh jean@192.168.10.10` → `ssh root@10.1.1.1` +- **Horus Root, wenn Tunnel tot ist:** über die **Public-IP** `ssh root@207.180.222.207` — aber nur erreichbar, wenn auf Horus per ufw Port 22 offen ist (Notfall: am Contabo-VNC `ufw allow ssh`, danach wieder `ufw delete allow ssh`). VM 101 hat den Horus-SSH-Key, geht also auch von dort über die Public-IP. +- **Horus WireGuard wird per `wireguard-ui` verwaltet**, Config-Datei `/etc/wireguard/wg0.conf` (nicht manuell editieren — wird regeneriert). Live-Kernel vs. Datei können auseinanderlaufen; Wahrheit ist `wg show wg0` / `wg showconf wg0`. +- VM 101 hat **kein** wireguard-ui — nur `wg-quick@wg0`. + +## Prävention / offene Risiken + +- Der eigentliche Übeltäter — **OPNsenses fragiler NAT/CARP-Zustand nach dem VM-104-Stop** — besteht weiter. Wird dort erneut State geflusht (Reboot/Failover), kann ein WireGuard-Tunnel wieder „einschlafen". Workaround dann: Client-Port wechseln. +- Lehre: Bei „Handshake-Init kommt an, aber 0 empfangen" **zuerst den Rückweg/NAT prüfen** (tcpdump auf beiden Seiten), nicht stundenlang an PSK/Keys. +- **VM 104 / OPNsense** nie per `qm stop/start` anfassen (Auslöser dieses ganzen Vorfalls). diff --git a/issues/README.md b/issues/README.md new file mode 100644 index 0000000..4c85bc5 --- /dev/null +++ b/issues/README.md @@ -0,0 +1,25 @@ +# Issues / Vorfälle + +Tracking von Problemen, Fehldiagnosen und deren Lösungen — damit der **nächste Agent (oder ich selbst)** beim nächsten Mal nicht wieder bei null anfängt. + +## Wozu + +Das Handover beschreibt den *aktuellen Übergabestand*. Hier dagegen landen **abgeschlossene Vorfälle** mit Fokus auf: + +- Was war das **Symptom**? +- Welche **Fehldiagnose** hat Zeit gekostet (damit man sie nicht wiederholt)? +- Was war die **echte Ursache**? +- Wie wurde es **gelöst** und **verifiziert**? +- Welche **Zugangswege / Befehle** waren nützlich? + +## Konvention + +- Eine Datei pro Vorfall: `YYYY-MM-DD-kurz-titel.md` +- Status oben: `gelöst` / `offen` / `teilweise` +- Ehrlich dokumentieren, auch eigene Fehler — der Lerneffekt ist der Sinn. + +## Index + +| Datum | Vorfall | Status | +|-------|---------|--------| +| 2026-06-28 | [VM 101 ↔ Horus WireGuard tot (NAT, nicht Keys)](2026-06-28-vm101-horus-wireguard-nat.md) | gelöst | diff --git a/shared/horus-opnsense-wireguard/README.md b/shared/horus-opnsense-wireguard/README.md index 486b484..0e977de 100644 --- a/shared/horus-opnsense-wireguard/README.md +++ b/shared/horus-opnsense-wireguard/README.md @@ -10,6 +10,19 @@ Direkter WireGuard-Tunnel zwischen **OPNsense** (lokales Netz) und **Horus** (VP Configs inkl. Private Keys: **privates Repo** — siehe Dateien in diesem Ordner. +## Keys nicht verwechseln (VM ≠ OPNsense) + +Zwei getrennte Tunnel = **zwei getrennte Keypairs**. Horus kennt jeden Peer nur über den **Public Key**. + +| Tunnel | Private Key (Datei) | Public Key (muss in GUI stehen) | +|--------|-------------------|----------------------------------| +| **OPNsense** `10.1.1.22` | `opnsense-client.conf` → `AGEam06B9…` | `walbWTYXAGOD1mOxPK+NwKT6qUhLyY0qieWBeTIbdXU=` | +| **VM 101** `10.1.1.5` | `vm101-client.conf` → `SKMnLpkj…` | `VB3Cf8kDxpzO+FyMrLxPyJ0vUjm8yJ/qIKmhY2KeeyI=` | + +**Falscher Private Key auf OPNsense** → GUI zeigt evtl. trotzdem einen Public Key, Horus antwortet aber nicht zum richtigen Peer → Symptom: **Bytes gesendet, 0 empfangen, kein Handshake**. + +OPNsense-Instanz: Private Key **nur** aus `opnsense-client.conf`, **nicht** aus `vm101-client.conf`. + ## Subnetz-Aufteilung (kein Teilen zwischen Peers) | Netz | Horus-Peer | Wer routet | diff --git a/shared/horus-opnsense-wireguard/opnsense-client.conf b/shared/horus-opnsense-wireguard/opnsense-client.conf index 676457b..37b4b4d 100644 --- a/shared/horus-opnsense-wireguard/opnsense-client.conf +++ b/shared/horus-opnsense-wireguard/opnsense-client.conf @@ -1,3 +1,5 @@ +# OPNsense Local — NICHT vm101-client.conf (SKMnLpkj… = VM, Public Key VB3Cf8kD…) +# Public Key zu diesem Private Key: walbWTYXAGOD1mOxPK+NwKT6qUhLyY0qieWBeTIbdXU= [Interface] PrivateKey = AGEam06B9IKmy3wSNRUOLoeLIaGJ5q1ftasOs3qlHEI= Address = 10.1.1.22/32