TP10 Doku konsolidiert: kanonischer Runbook + kompakter Kontext-Digest

- tp10-vpn-migration.md zur Single Source of Truth umgeschrieben: widerspruechliche
  alte Transfernetz-Tabelle/MyFRITZ-Endpoint entfernt, aktueller Stand (Proxy-ARP
  LAN-IP, DDNS bf4.emsenhuber.net, dual-range DW, geparkter ap1-Hub, vertagt+
  gebuendelt mit Bridge-Cutover, v6-Variante) konsolidiert.
- teilprojekte.md TP10-Eintrag von verbose Saga auf kompakten Status + Verweis gekuerzt.
- tp10-context-digest.md neu: ultrakompakter Handoff (lokal via Ollama nemotron-3-nano:4b
  destilliert, fakten-gegengeprueft) fuer kleines Kontextfenster.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-24 14:08:01 +02:00
parent 03f328f043
commit dd4c6ad77c
3 changed files with 85 additions and 110 deletions

View File

@@ -1,91 +1,68 @@
# TP10 — Multi-Site-VPN-Migration (2× AVM-S2S → 2× WireGuard, Hub auf ap1)
# TP10 — Multi-Site-VPN (2× AVM-S2S → 2× WireGuard, Hub auf ap1)
> Stand 2026-06-16 · Research: `docs/research/vpn-comparison.md` · Plan: `~/.claude/plans/pure-wibbling-graham.md`
> gated: permanenter FB-Bridge-Mode (AP4.1) hängt an diesem TP.
> **Reihenfolge fix: VPNs migrieren → Liwest-Anruf (Bridge) → FB wird Modem.**
> **Single Source of Truth** für TP10. Research: `docs/research/vpn-comparison.md` · IPv6: Memory `project-ipv6-state`.
> Plan-Scratch (historisch, teils überholt): `~/.claude/plans/pure-wibbling-graham.md`.
> ## 🅿️ STATUS 2026-06-17: VERTAGT — gebündelt mit dem FB-Bridge-Cutover
> **Entscheidung:** TP10 nicht mehr als Parallel-Migration vorab, sondern **zusammen mit dem permanenten Bridge-
> Cutover** (VPN-auf-FB ⊕ FB-Bridge schließen sich aus). Am Bridge-Tag hat ap1 die echte Public-IP → **kein
> FB-Port-Forward-Umweg** mehr; Spokes zeigen direkt auf ap1 (DDNS). **FM-PoC ✅** hat den Fix bewiesen (Root Cause:
> FB masqueradet, wenn die WG-Interface-`Address` eine **Transfernetz-IP** statt der **FB-LAN-IP** ist — AVM Proxy-ARP).
> **Park-Zustand ap1:** Peers `disabled`, WG-Routen entfernt (FM/DW wieder über die FB), `wg-hub` bleibt (Key erhalten),
> Firewall bleibt (TP5-Vorarbeit). Beide VPN vorerst über die FB: **FM = IPsec, DW = FB-WG.**
> **Resume:** `routeros/fritzbox-wg-lanlan-klickanleitung.md` (FB-LAN-IP als Interface-Adresse, Verify gegen `10.101.0.10`).
## 🅿️ STATUS 2026-06-17: VERTAGT — gebündelt mit dem FB-Bridge-Cutover
TP10 wird **nicht** mehr als Parallel-Migration vorab gemacht, sondern **zusammen mit dem permanenten FB-Bridge-Cutover**
— denn **VPN-auf-FB und FB-Bridge schließen sich aus** (Bridge = Modem = keine VPN-Terminierung). Bonus: am Bridge-Tag
hat **ap1 die echte Public-IP** → **kein FB-Port-Forward-Umweg** mehr, Spokes zeigen direkt auf ap1 (via DDNS).
- **Beide VPN laufen vorerst über die BF-FB:** **FM = IPsec**, **DW = FB-WG** (Status quo, produktiv).
- **DW-Config ist aber schon bei Geli vor Ort gestaged** (2026-06-17, seltener Zugriff genutzt) — wird erst aktiv,
wenn die ap1-Seite live geht (s.u. „Offen").
## 💡 Variante DW/Geli — v6-direkt statt CGNAT-Spoke (Idee 2026-06-17, für später)
Gelis CGNAT ist **nur v4**; ihre FritzBox hat **öffentliches natives v6** (`2a0e:7a02:31c:3000::/56`, rotiert ~30h →
MyFRITZ-DDNS) → ihre FB ist **über v6 von außen erreichbar**. Der **v6-Inbound-Port auf Gelis FB ist bereits offen.**
- **Sofort/PoC (ad-hoc Fernwartung, da Geli kein Zero Trust hat):** Christophs **WARP** (schon im Einsatz) gibt ihm
outbound-v6 trotz Liwest-v4-only → `Christoph(WARP-v6) → CF-Edge → Gelis v6-FB`. CGNAT-immun, reversibel.
Nur Fernwartung — **nicht** für Telefonie (Calls = Messenger-Relays).
- **Daueform (sauberer):** echtes v6 auf BF-Seite via **HE-6in4** (Liwest gibt voraussichtlich **auch mit Fiber kein v6**)
→ **direktes WireGuard ap1↔Geli-FB über v6**, kein Cloudflare im Datenpfad, kein Tunnel-in-Tunnel (WARP ist selbst WG),
**umgeht die ganze Hub-&-Spoke-CGNAT-Gymnastik** unten (Geli müsste nicht mehr outbound zum Hub initiieren — v6↔v6 ist
symmetrisch erreichbar). Siehe Memory `project-ipv6-state`.
- **Endgeräte bleiben v6-agnostisch:** v6 ist **nur der äußere Transport** zwischen FB-WAN und Christophs Endpunkt; im
Tunnel läuft Gelis LAN weiter **rein IPv4** (192.168.178.0/24). Ihre Geräte (Galaxy Note 10, Cudy-APs als Bridge, NAS …)
müssen **kein v6 können** — sie sehen nie ein v6-Paket. v6-Eigenfähigkeit eines Backend-Geräts wäre nur nötig, wollte man
es **direkt ohne Tunnel** über v6 erreichen (klobig: Freigabe pro Gerät + rotierendes Prefix) — macht man nicht.
## Root Cause des FM-PoC (bewiesen) — der zentrale Lerneffekt
FM-WG-Versuch schlug fehl: Ping auf realen FM-Host `10.101.0.10` kam aus `10.255.255.2` zurück ⇒ **die FB masqueradet
den Tunnel.** **Ursache:** WG-Interface-`Address` war eine **Transfernetz-IP** → FRITZ!OS = Einzelgerät-Modus = NAT.
**AVM nutzt Proxy-ARP statt Transfernetz** → die FB-WG-`Address` **muss die eigene LAN-IP sein**. Damit: kein NAT,
echte LAN-IPs, LAN-LAN sauber. (Gleiche Ursache wie der alte „NetBIOS routet nicht"-Fehlschlag.)
## Zielbild
- **ap1 (hAP ax², 7.23.1) = WireGuard-Hub** (nativ). FM & DW = FritzBox-Spokes (hub-&-spoke, keine Zusatz-HW).
- Ablösung der **2 produktiven AVM-LAN-LAN-Tunnel** auf der BF-FB → **2× WireGuard auf ap1**:
- **FM** `10.101.0.0/24` (GW .254) — war **IPsec**.
- **DW/Geli** `192.168.178.0/24` (GW .1, **CGNAT**, Antennengemeinschaft Geroldsgrün) — war **WireGuard**.
## ✅ As-built auf ap1 (Phase A erledigt, 2026-06-16)
## Eckdaten
| Objekt | Wert |
|---|---|
| Interface `wg-hub` | Listen **UDP 51821**, MTU 1412, **keine IF-IP**, running |
| Hub-Public-Key | `P/bztIk13cAmLHbN6oHGGnWAKLZsqR5TXAbFP+NGGBk=` |
| Endpoint (für Spokes) | **`xvbeo64jqlqd9gfo.myfritz.net:51821`** (MyFRITZ-FQDN) |
| Peer FM (`peer1`) | pub `dzRY0lnnUygijChWe5wXZmXPeNcbdALpqBptA3fyiVE=`, allowed `10.255.255.2/32,10.101.0.0/24`, Endpoint leer |
| Peer DW (`peer2`) | pub `FqYZLztQ/qME5VDie5QLGH++5299WJiE1dPpQnPbzUw=`, allowed `10.255.255.3/32,192.168.178.0/24`, Endpoint leer |
| Route | `10.101.0.0/24` → wg-hub · `192.168.178.0/24` → wg-hub (beide active) |
| Firewall | input accept udp/51821 · forward accept in/out wg-hub (TP5-Vorarbeit) |
| NAT | **keine Änderung nötig** — masquerade ist out-interface bridge/ether1; Tunnel-Egress = wg-hub → nie NATed |
| Hub `wg-hub` (ap1) | UDP **51821**, MTU 1412, **keine IF-IP**, Key `P/bztIk13cAmLHbN6oHGGnWAKLZsqR5TXAbFP+NGGBk=` |
| **Endpoint (Spokes)** | **`bf4.emsenhuber.net:51821`** — DDNS via Cloudflare (Zone `emsenhuber.net`, **proxied=false**, TTL 120) → `86.56.201.104`. Überlebt IP-Wechsel **und** FB-Bridge. NICHT MyFRITZ (stirbt im Bridge). |
| BF-Seite (AllowedIPs der Spokes) | `10.40.0.0/16` |
| FM | LAN `10.101.0.0/24` (GW .254), war IPsec. FB-WG-`Address` = **`10.101.0.254/24`** (LAN-IP!) |
| DW/Geli | LAN heute `192.168.178.0/24` (GW .1), **CGNAT v4**, Antennengem. Geroldsgrün. Künftig **`10.95.10.0/24`**. FB-WG-`Address` = **`192.168.178.1/24, 10.95.10.1/24`** (Dual, renumber-fest) |
| Keepalive | Spoke-Seite `PersistentKeepalive=25` (CGNAT-Dial-out) |
**Port 51821 (statt 51820):** Die BF-FB hält ihren eigenen WG-Server auf 51820 für den **noch laufenden DW-Tunnel**.
51821 für den Hub vermeidet die Kollision während der Parallelphase.
**Spoke-Configs (Private-Keys, gitignored):** `routeros/.secrets/wg-fm.conf`, `routeros/.secrets/wg-dw.conf`.
**ap1-Park-Zustand:** Peers **disabled**, WG-Routen **entfernt** (FM/DW laufen über FB-Default), `wg-hub` bleibt
(Key erhalten), Firewall-Regeln bleiben (TP5-Vorarbeit). NAT braucht nichts (Egress wg-hub ≠ masq-Interface bridge/ether1).
**Spoke-Configs (Private-Keys, NICHT im Git):** `routeros/.secrets/wg-fm.conf`, `routeros/.secrets/wg-dw.conf`.
## ⏳ Offen — ap1-Seite aktivieren (sobald BF erreichbar; aktuell locked out)
- `peer2` (DW) enable/neu: `public-key=FqYZLztQ/qME5VDie5QLGH++5299WJiE1dPpQnPbzUw=` (unser Key; falls Gelis FB
**eigene** Keys erzeugt → deren Public-Key eintragen), **allowed-address = `192.168.178.0/24, 10.95.10.0/24`**, Endpoint leer.
- Routen `192.168.178.0/24 → wg-hub` **und** `10.95.10.0/24 → wg-hub`.
- `peer1` (FM) bleibt **disabled** (FM auf IPsec, vertagt bis Bridge-Tag).
- Verify: `list_wireguard_peers` Handshake; `/ping 10.101.0.10 src-address=10.40.20.1` bzw. ein Geli-Host → **Quelle muss
die echte LAN-IP sein**, nicht `10.255.255.x`. **NetBIOS-Lehre:** per IP/DNS testen (SMB 445), nie Broadcast/Netzwerkumgebung.
## ✅ Vorbedingung (User erledigt)
- **FB-Portfreigabe** UDP **51821** → `10.40.41.1` (ap1) gesetzt.
## DW-Gotchas
- **2 WG zum selben Zielnetz**: Gelis FB lehnt zwei WG-Verbindungen mit überlappenden AllowedIPs (`10.40.0.0/16`) ab
→ **direkter Swap** (alten Geli↔BF-FB-WG entfernen, neuen Geli↔ap1 anlegen), kein Parallelbetrieb. On-site oder via
temporärem Admin-Tunnel zu anderem Zielnetz.
- **Fernzugang zu Gelis FB**: MyFRITZ-v4 tot (CGNAT). Sobald Geli↔ap1 steht → FB unter `192.168.178.1` über den Tunnel
erreichbar (Endpoint später proaktiv pflegen, solange Tunnel läuft).
## Phase B — Cutover (pro Spoke, Parallelphase) — OFFEN
> Pro Standort: neuen WG-Tunnel hochziehen, **verifizieren**, erst dann den alten AVM-Tunnel abschalten.
## 💡 DW-Variante: v6-direkt statt CGNAT-Spoke (für später)
Gelis CGNAT ist **nur v4**; ihre FB hat **öffentliches natives IPv6** (`2a0e:7a02:31c:3000::/56`, rotiert ~30h → MyFRITZ),
**v6-Inbound-Port offen** → von außen über v6 erreichbar.
- **PoC/Fernwartung jetzt:** Christophs **WARP** gibt outbound-v6 (Liwest v4-only) → `Christoph(WARP-v6) → CF-Edge →
Gelis v6-FB`. CGNAT-immun, reversibel. Nur Fernwartung (Calls laufen eh über Messenger-Relays).
- **Daueform:** echtes v6 auf BF via **HE-6in4** → **direktes WG ap1↔Geli-FB über v6**, kein CF im Datenpfad, **umgeht die
ganze Hub-&-Spoke-CGNAT-Gymnastik** (v6↔v6 symmetrisch erreichbar). Inner-Tunnel bleibt IPv4 (Gelis Geräte v6-agnostisch).
### B1 — FM zuerst (alter IPsec-Tunnel bleibt parallel an)
1. `routeros/.secrets/wg-fm.conf` in die **FM-FritzBox** importieren:
`Internet → Freigaben → VPN (WireGuard) → Verbindung hinzufügen → eigene Konfiguration importieren`.
- ⚠️ Falls FRITZ!OS keinen Import mit vorgegebenem Key erlaubt: FB-WG-Verbindung manuell anlegen, FB-**Public-Key**
ablesen und melden → wird in `peer1` auf ap1 eingetragen (`manage_wireguard_peer` set public-key).
2. **Handshake prüfen:** `list_wireguard_peers` → `peer1` last-handshake aktuell, rx/tx > 0.
3. **L3-Verify (NetBIOS-Lehre, s.u.):** Ping ap1 → ein Host in `10.101.0.0/24`; Gegenrichtung FM → BF-Host (NAS);
**SMB per IP (TCP 445)** testen, **nicht** Netzwerkumgebung/Broadcast.
4. Grün → **IPsec-Tunnel** für FM auf der BF-FB deaktivieren → erneut prüfen.
## Cutover-Sequenz (am Bridge-Tag, ein Rutsch)
1. ap1-Seite live (peers/routes, s.o.), Spoke-Configs an FM+DW (FM-`.conf` neu mit LAN-IP-Address).
2. Verify je Spoke (echte LAN-IP-Quelle, SMB/445 per IP).
3. Alte AVM-Tunnel abbauen (FM-IPsec; DW-FB-WG/Server 51820).
4. **Liwest-Anruf** → FB Bridge/Modem, ap1 = Edge mit Public-IP (DDNS zeigt weiter dorthin) → Portfreigabe entfällt.
5. TP5-Firewall auf ap1 finalisieren (WG-Regeln behalten).
6. Entblockt: NAS/Controller-IP-Migration (IP-Plan Phase 3), Double-NAT weg.
**Follow-up:** DDNS-Auto-Updater für `bf4` auf NAS/pve (statt manuell bei IP-Wechsel).
### B2 — DW/Geli danach (alter FB-WG-Tunnel auf 51820 bleibt parallel an)
5. `routeros/.secrets/wg-dw.conf` in die **DW-FritzBox** importieren (CGNAT → wählt ausgehend, Keepalive 25).
6. Handshake + L3-Verify (Ping/SMB per IP in `192.168.178.0/24` ↔ BF).
7. Grün → alten **DW-WG-Server/Tunnel** auf der BF-FB abbauen.
## NetBIOS / Namensauflösung (FM — bekannter Stolperstein)
Früherer FM-WG-Versuch scheiterte an „NetBIOS nicht geroutet". NetBIOS-Namensauflösung läuft über **Broadcasts
(UDP 137/138)**, die über einen *gerouteten* Tunnel grundsätzlich nicht traversieren — kein Routing-Bug.
→ **L3 zuerst per IP beweisen** (Ping + SMB/445); Namensauflösung per **IP oder DNS** lösen (statische Einträge),
nicht über Broadcast-Browsing. Unser Design führt beide Richtungen in AllowedIPs/Routes → unicast muss laufen.
## Phase C — Abschluss (nach beidseitig grün, ≥1 Tag stabil)
8. TP5-Firewall auf ap1 finalisieren (WG-Regeln behalten).
9. **DDNS-Übergabe:** MyFRITZ läuft über die FB, entfällt evtl. im Bridge-Mode → ap1 braucht eigenes DDNS
(`/ip cloud` mynetname / DynDNS); Spoke-Endpoints dann auf ap1-FQDN umstellen.
⚠️ Prüfen, ob `/ip cloud` trotz device-mode=home läuft (scheduler/fetch geblockt).
10. **Liwest-Anruf** für FB-Bridge-Mode → FB wird Modem, ether1 = WAN, Portfreigabe entfällt.
11. Entblockt: NAS/Controller-IP-Migration (IP-Plan Phase 3) + Wegfall Double-NAT.
## Rückbau (falls nötig)
- ap1-Seite vollständig reversibel: Peers/Routen/Firewall via `manage_*` `action=remove`, `wg-hub` löschen.
- Alte AVM-Tunnel erst nach Verifikation abschalten → jederzeit reaktivierbar.
## Reversibilität
ap1-Seite vollständig per `manage_*`/`action=remove` rückbaubar. Alte AVM-Tunnel erst nach Verify abschalten →
jederzeit reaktivierbar. FB-Bridge bis Liwest-Anruf reversibel (`routeros/wan-cutover-runbook.md`).