# BF-Netzwerk — Teilprojekte (kanonische Steuerung, Stand 2026-06-10) > **Zweck:** Das große Netz-Projekt in **einzeln durchziehbare Teilprojekte (TP)** zerlegt — jedes mit klarem Scope, > aktuellen Entscheidungen, Abhängigkeiten und Status. Jedes TP ist so geschnitten, dass es eine frische Session > **mit sauberem Kontext** straight abarbeiten kann. Architektur/Historie: `~/.claude/plans/ich-will-das-delegieren-atomic-sunrise.md`. > > 📚 **Diese Datei führt den Ist-Stand, den kritischen Pfad und die OFFENEN Teilprojekte.** > Abgeschlossene TPs stehen im **[Archiv](teilprojekte-archiv.md)** — im Volltext, unverändert, mit > Inhaltsverzeichnis. **Für den Einstieg reicht diese Datei**; ins Archiv sieht man, wenn man wissen > will, *warum* etwas so entschieden wurde. *(Aufgeteilt am 2026-08-23, Doku-Session Punkt F: 2217 > Zeilen waren zu 49 % Historie erledigter TPs.)* ## Kanonisches VLAN-Modell (gültig — überschreibt ältere Tabellen) | VLAN | Name | Subnetz (Ziel) | Zweck | |---|---|---|---| | 10 | MAIN | 10.40.10.0/24 | Trusted (Handy/Laptop/Apple Watch) | | 20 | INFRA | 10.40.20.0/24 | NAS/VMs/Docker/HA | | 30 | IOT | 10.40.30.0/24 | Smart-Home (HA-managed), Waage, Fitness-Tracker | | **40** | **MEDIA** | 10.40.40.0/24 | **Sonos, AppleTV, TV, VuPlus, Cast-Ziele** (getauscht ggü. früher) | | **50** | **UNTRUSTED** | 10.40.50.0/24 | **Spielekonsole, eBook-Reader, Low-Trust-Internet** | | 90 | GUEST | 10.40.90.0/24 | nur Internet | | 99 | MGMT | 10.40.99.0/24 | Switch/AP/Hypervisor-Mgmt | | 100 | WAN | (Arris-Transfer) | zum Arris-Kabelmodem (Liwest, Bridge-Mode, Public-IP an `crs326-core`) | IP-Blöcke: `.1–10` Router/Gateways · `.11–20` Switches/APs. **GW je VLAN = `.1` (crs326-core).** Mgmt (VLAN99, Ist 2026-08-16): core `.99.1` · branch `.99.2` · ap1 `.99.11` · ap2 `.99.12`. *(Historisch, überholt: „ap1=.1, ap2=.2 · ALLNET=.11, Omada=.12" — aus der Zeit vor dem Core-Cutover.)* ## Ist-Stand (Kurz) **Stand 2026-08-18 — live gegen die Geräte geprüft (MikroMCP/REST), nicht aus der Doku abgeschrieben.** **Die Compliance-Zeile unten ist am 2026-08-23 gegen die Nautobot-API nachgezogen.** *(Die Fassung vom 2026-08-16 stand bis zum 18. hier und war an vier Stellen überholt — Standalone-APs, RouterOS-Versionen, „plain 1.1.1.1", 68/68. Wer diesen Block liest, liest ihn als Erstes: er wird ab jetzt bei jeder Änderung mitgezogen, nicht nur die TP-Abschnitte.)* - **Alle vier MikroTik laufen auf RouterOS 7.24** (stable, 2026-08-17 von Christoph selbst gehoben, TP27), **RouterBOOT ebenfalls 7.24** auf allen vieren (`current-firmware` = `upgrade-firmware`, geprüft 08-18). - **L3 + WAN-Edge = `crs326-core`** (CRS326-24G-2S+, Technik UG): Routing, DHCP (7 Server, 54 Reservierungen), DNS, NAT, **NTP-Server für den Standort** und der WG-Hub (TP10, Peers `fm`/`dw`) laufen hier. Mgmt-SVI **`10.40.99.1`** (vlan99), Gateway `.1` je VLAN. **WAN = `vlan100`** — DHCP-Client hält die öffentliche Liwest-IP **`90.146.33.177/24`** direkt vom Arris (Bridge-Mode) → kein Double-NAT. **DNS-Upstream = DoH zum CF-Gateway mit `verify-doh-cert=yes`** (TP23 Stufe 1 ✅ 08-18); `servers=1.1.1.1` steht nur noch als Bootstrap für den DoH-Hostnamen. - 🔥 **Die Firewall ist deny-by-default — in BEIDEN Ketten** (TP5 E3/E4 ✅ 08-18). `TP10-seal-lan` ist `disabled`; Mgmt-Input kommt nur noch aus VLAN10, von HA (`8728`), von Nautobot (`22`) und über `cf-mesh`. Ein neuer Dienst über eine VLAN-Grenze braucht ab jetzt eine explizite Regel. - **L2-Branch = `crs326-branch`** (Technik OG): reiner L2-Switch, Mgmt **`10.40.99.2`**, Uplink `ether1` → core `ether8`. - **WLAN = CAPsMAN auf dem Core** (TP28 ✅ 08-17, GC-Modell nachgezogen 08-18): ap1 **`10.40.99.11`** (an core `ether15`), ap2 **`10.40.99.12`** (an branch `ether24`), beide **reine CAPs** — `cap enabled=yes`, `discovery-interfaces=vlan99`. Die APs halten **keine eigene WLAN-Config** mehr; Kanäle, SSIDs, Security und Steering kommen vom Manager. 802.11r/k/v aktiv, `ft-over-ds=yes`. - **SSDP-Relay** (TP7.1 ✅ 08-18): LXC **108 `mcast-relay`** auf pve, zweibeinig `10.40.10.21` (VLAN10) + `10.40.40.21` (VLAN40) — dafür trägt `core ether13` beide VLANs. Die macOS-Sonos-App findet damit ihr System; mDNS macht weiterhin der Core. - **Ausgebaut / gelöscht:** ALLNET-`sw1` und Omada-`sw2` sind **physisch weg** (2026-08-08 bzw. 2026-07-23, in Nautobot *Decommissioned*); Omada-Controller + `omada-mcp` gelöscht (2026-07-16); FritzBox 6660 raus seit 2026-07-01 (Liwest-Tausch auf Arris). **VLAN1 ist leer** (`/ip arp` auf `bridge` = 0 Einträge, 08-18) — TP19 ist geschlossen; `cudy1` hängt stromlos an core `ether11`, physischer Ausbau ist hands-on. - **Kontrolle / Governance:** MikroMCP für Reads/Debug (alle 4 Geräte in der Registry), **Config-Änderungen ausschließlich über Nautobot Golden Config** (TP21/TP22 — Deploy-Pipeline scharf, **104/104 Compliance-Checks grün, 0 Drifts** bei **26 Rules × 4 Geräten** — live gegen die API geprüft am **2026-08-23**; zuletzt dazugekommen: **`wifi-access-list`** (08-22), **`queue`** (08-23, TP6) und **`ip-firewall-mangle`** (08-23, TP6.1), s. TP22-Nachtrag im Archiv). *(Hier stand bis zum 08-23 „100/100 bei 25 Rules" — eine Zählung, die TP6.1 am selben Tag überholt hat. Die Merkregel gilt: der Ist-Stand-Block wird bei jeder Änderung mitgezogen, nicht nur der TP.)*
📜 Historische Fassung (Stand bis 2026-08-08, Topologie vor dem Core-Cutover — bewusst erhalten, nicht als Ist lesen) > ALLNET-Core `.11` (FW2.2.1, VLANs 10/20/30/40/50/90/99/100; GE1/GE2/GE8 Trunk; **TP1 ✅ 2026-06-15**). Omada-Switch `.12` (adopted, **TP2 ✅ 2026-06-15**; Trunk-ALL auf P1+P2, Access-Profile auf P3-P8; Profile noch PVID=1 bis Omada-PVID-Fix). > Omada-Controller **`.175`** (DS923/macvlan, mbentley 6.2, 🟢 live). omada-mcp **`.176`** (pve-LXC, StreamableHTTP, 🟢 live, 84 read-Tools; Controller-API v2 intern via christoph@emsenhuber.com). > 2× hAP ax² (7.23.1): ap1 `.1` (ALLNET P1) — **TP4 ✅ 2026-07-01: Router + WAN-Edge** (VLAN-Subinterfaces, DHCP, DNS, NAT, Public-Edge). ap2 `.2` (Omada P2 — Trunk). > **Edge-Cutover ✅ 2026-07-01:** FB6660 physisch entfernt (Liwest-Kabelmodemtausch, kein Zurück), Arris-Kabelmodem im Bridge-Mode; WAN = `sw1 gi16 Access VLAN100 → gi15 Trunk → ap1 ether2 → vlan100 auf bridge` (**NICHT** ether1); ap1 hält Public-IP direkt (Liwest, kein CGNAT), Double-NAT weg. Telefonie war auf der FB und wird nicht weitergeführt. Vorarbeit: TP10-Kern durch (2026-06-27, WG-Hub live) → Bridge-Gate vorher gelöst. Runbook: `routeros/wan-cutover-runbook.md`. > Kontrolle: MikroMCP (MikroTik) live · ALLNET = Klickanleitungen · Omada → Controller + omada-mcp 🟢.
**Nächster Schritt (Stand 2026-08-23): Christoph entscheidet — der kritische Pfad ist LEER.** > 🎯 **Das Projekt ist in seinem Kern fertig.** deny-by-default steht (TP5), Golden Config steht und > meldet **104/104 compliant bei 0 Drifts** (live geprüft 2026-08-23), WLAN steht über CAPsMAN auf dem > Core (TP28), VLAN1 ist leer (TP19) — und **TP6 ist beantwortet statt offengelassen**: CAKE gebaut, > gemessen, wieder ausgebaut. **Nichts blockiert mehr etwas.** > 🟢 **Was zuletzt wirklich etwas gebracht hat, war TP6.1** (2026-08-23): nicht Shapen, sondern > **Klassentrennung** — NAS-Bulk `priority=8` gegen interaktiv `priority=1` drückt dieselbe Strecke > unter derselben Sättigung von **40,8 auf 11,0 ms (−73 %)**. Die zuerst notierte DOCSIS-Erklärung aus > TP6 ist damit **widerlegt**; der Fehler lag in der Messmethode (Last und Messung vom selben Host). > 📋 **Offen und ohne Blockadewirkung:** **TP25** (Fund F = 5:05-Takt bei IoT, plus die Entscheidung > „5 GHz auf 20 MHz") · **TP16** (CF-Tunnel-HA degradiert, vier tote Alt-Tunnel) · **TP16.2/16.3** · > **TP23 Stufe 2** · **TP24** (DC-USV) · **TP13/TP14.4** (beide mit fertigem Runbook) · > 🔑 **Rotation des MikroTik-Admin-Passworts** (User: „machen wir, aber erst später"). > Zugeschnittene Sitzungsvorschläge: [`handoff-20260822-naechste-schritte.md`](handoff-20260822-naechste-schritte.md). > ✅ **`crs326-core` ist transaktionsfrei** (seit 2026-08-22, geprüft): ein gemeldeter Drift ist ab > jetzt **echt**, nicht beabsichtigt — `python3 nautobot/gc-transaktion.py status`.
📜 Vorherige Fassungen dieses Absatzes (2026-07-22 → 2026-08-21, bewusst erhalten) > *Fassung 2026-08-21 abends (erledigt — TP25s Dead Spot ist am 08-22 repariert, TP6 am 08-23 geschlossen):* > **Nächster Schritt: TP25 — Steering-Test in den Schlafräumen.** > 📋 **Einstieg: [`handoff-tp25-session-20260821.md`](handoff-tp25-session-20260821.md)** — dort steht > der verifizierte Ist-Stand, die Messfallen und der nächste Test. > ✅ **`crs326-core` ist transaktionsfrei (2026-08-22).** `TEST-ether3-trunk-ap1-sideboard` und > `TEST-infra-ssid-matter-pairing` sind beide zurückgerollt und geschlossen; ap1 hängt wieder auf > `ether15`, `ether3` ist wieder untagged VLAN40. Ein gemeldeter Drift ist ab jetzt **echt**, nicht > beabsichtigt — `python3 nautobot/gc-transaktion.py status`. > 🆕 **TP29** (Anwesenheitserkennung fürs Energiesparen) ist als Idee angelegt, nicht auf dem Pfad. > 📌 **Die TP6-Prämisse ist am 2026-08-20/21 gemessen** (Runbook §5): formal Fall B (+28…+47 ms unter > Dauer-Upload), aber im Videocall **nicht wahrnehmbar** — kein einziger Problem-Klick über sechs > Lastphasen. Laut war stattdessen der Funk: **Sticky Client + Band-Ping-Pong, zwölf Wechsel in neun > Minuten**, je Wechsel bis zu 4 s ohne Durchsatz → > [`tp25-wlan-roaming-messung-20260820.md`](tp25-wlan-roaming-messung-20260820.md). Deshalb steht jetzt > **TP25 vor TP6**; TP6 bleibt offen und begründet, aber nachrangig. > > *Vorherige Fassung (Stand 2026-08-18, erledigt):* TP6 wird hier seit Monaten als „DAS Ziel" geführt, aber `docs/call-quality-diagnosis.md` hat den Bufferbloat 2026-06-16 bereits gemessen (**A/A+**, „CAKE wäre marginal, nicht deployt"). Die Messung stammt aus der FritzBox-Ära, der Edge ist seither getauscht — also **einmal gegen den heutigen Edge nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Nacht auf den 18. abgeschlossen worden (Etappe 3 + 4: deny-by-default in `forward` **und** `input`, MGMT isoliert, `seal-lan` abgeschaltet), TP23 Stufe 1 (DoH auf dem Core) ebenfalls. Nebenher offen, blockiert nichts: **TP25** (Signal-Boden + Re-Walk), **TP28-Rest** (die fünf `wifi-*`-Features vom AP-Scope auf den Core umhängen — die einzigen verbliebenen Compliance-Drifts), **TP7.1** (SSDP-Relay für die macOS-Sonos-App), **TP16.3**, **TP24**. > *Vorherige Fassung (Stand 2026-08-14, überholt): „TP5 — Deny-by-default am Ende von `forward`." Alles Davorliegende ist durch:* CRS326-Bring-up + L3-Umzug ap1→`crs326-core` (TP15/TP21.1 ✅ 2026-08-08), WLAN-Neuprovisionierung ohne CAPsMAN (TP3 ✅ 2026-08-08), Nautobot-Plattform + Fleet-Adoption + Deploy-Pipeline (TP21/TP22 ✅ 2026-08-13). Danach **TP6 (CAKE) = das Projektziel**. Kleine Follow-ups nebenher: DoH-Cloudflare auf core, DC-USV (**TP24**, seit 2026-08-16 eigener TP). ⚪ **Omada-PVID-Fix ist obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit der TP15-Korrektur keine Rolle mehr im Netz, nie mehr aufgreifen). > *Vorherige Fassung (Stand 2026-07-22, erledigt): „TP15 CRS326-Bring-up als neuer L3-Core, danach WLAN-Neuprovisionierung ohne CAPsMAN; TP5 folgt nach TP21/CRS326-Adoption."*
> 🎯 **Ziel: sauberes System „from scratch", keine Leichen/Altlasten.** Migrations-Session-Endstand = **VLAN1 + altes cudy-WLAN komplett weg** (VLAN1 nur noch Mgmt, `defconf`-Client-DHCP zurückgezogen, cudy-Uplinks aufs Ziel-Client-VLAN getaggt oder cudy abgebaut). **Unterpunkte/Aufräum-Liste bei Migration:** (a) die Interim-Härtung ap2 `wifi1/wifi2 frame-types=admit-only-vlan-tagged` (TP3.1, 2026-07-06) bleibt gültig — verschwindet automatisch mit VLAN1; (b) ~~`st-main rrm/wnm` = reines Roaming-Provisorium~~ → **kein Provisorium mehr (2026-08-13, TP3.3): Steering ist fester Bestandteil des Golden-Config-Templates + ComplianceFeature `wifi-steering`** — es war die Neuprovisionierung, die es stillschweigend verloren hatte; (c) ~~**cudy1 = verbleibender aktiver VLAN1-Leak**~~ → **ERLEDIGT (User-bestätigt + verifiziert 2026-08-14): cudy1 ist offline.** `core ether11` trägt **kein Link** (kein `R`-Flag), Nautobot-Status *Offline* (TP22 Schritt 5). Damit existiert kein aktiver VLAN1-Leak mehr; der Dual-DHCP-Race aus `project_vlan1_dhcp_incident` ist Historie. Der formale Teardown (Gerät ausbauen, Doku/Inventar) bleibt TP19. > ⚠️ **HW-Constraint hAP ax²:** 1 GB RAM, aber nur **128 MB Flash + KEIN USB** → **Container auf dem Router NICHT praktikabel**. > Folge: **native RouterOS-Features bevorzugen** (z.B. Built-in-mDNS statt Container); Container (mDNS-Reflector, BIND9-DNS, Omada-Controller) laufen auf **NAS/pve**, nicht am hAP. > 🔒 **Governance-Entscheid (User, 2026-07-16, ausgeweitet 2026-07-16): Config ausschließlich über Nautobot — keine Direkt-Changes mehr an einzelnen im Netz verstreuten Geräten.** Ursprünglich als ap1/ap2-Config-Freeze bis TP21 formuliert, noch am selben Tag verallgemeinert: **jede** Netz-Gerätekonfiguration (Router, APs, künftig auch die CRS326-Switches) läuft ab jetzt exklusiv über Nautobot Golden Config (TP21), sobald das steht — keine ad-hoc MikroMCP-Writes/UI-Klicks mehr an Einzelgeräten. **TP19.1 war die letzte Ausnahme** (ap1-DNS-Fix + ap2/sw1/sw2-Mgmt-VLAN-Umzug, s.u.) — davon ist nur der risikolose ap1-Teil noch direkt gemacht worden, ap2 wurde bewusst auf „nach Nautobot" vertagt. **Macht Nautobot + alle Prerequisites (TP18→TP20→TP20.1→TP21, jetzt auch Komodo) zum aktuell kritischen Pfad**, vor TP5/TP6. Betrifft nicht Software-Migrationen auf NAS/pve (anderes Substrat) und die Frage, ob sw1/sw2 vor der CRS326-Ablösung noch angefasst werden (offen, s. TP15/TP19.1). > ✅ **Genehmigte Ausnahme (User, 2026-07-17): der zentrale CF-Tunnel-Zugang auf ap1 (TP16/TP16.1).** Alle für den zentralen Cloudflare-Zugang **auf ap1** notwendigen (Vor-)Arbeiten dürfen direkt via MikroMCP/CF-API gemacht werden, ohne auf Nautobot GC zu warten — konkret die nativen WireGuard-Mesh-Zeilen aus TP16.1 (und analoge cloudflared/WG-Anpassungen am ap1-Edge). Begründung: Remote-Erreichbarkeit ist die Voraussetzung, um überhaupt sicher am Netz zu arbeiten (Henne-Ei zu Nautobot). **Scope-Grenze:** Die Ausnahme gilt **nur für ap1**. Sobald der zentrale Zugang später auf die **CRS326** wandert (TP15), gilt die Ausnahme dafür **vorerst NICHT** — CRS326-Config läuft dann regulär über Nautobot GC (oder braucht eine eigene, dann neu zu erteilende Ausnahme). Nachtrag der ap1-Ausnahmezeilen in die GC als Follow-up, sobald Nautobot steht. > ✅ **Genehmigte Ausnahme #4 (User, 2026-08-16): die WireGuard-Zeilen des Cloudflare-Mesh-Bring-ups auf `crs326-core` (TP16.1).** Dürfen direkt via MikroMCP/REST gesetzt werden. **Begründung ist strukturell, nicht bequem:** TP22-Regel 1 schließt jede Sektion mit `<>` generell vom GC-Push aus, und `/interface wireguard` ist genau so eine — ein privater Schlüssel ist über Golden Config **nicht deploybar**. Damit ist die frühere TP16.1-Zusage „CRS326-Zeilen laufen regulär über GC" gegenstandslos. **Auflage:** vorher `/system backup`, danach Ist-Stand als intended config zurück nach Nautobot. **Scope-Grenze:** nur der Mesh-Bring-up auf `crs326-core` — nicht spätere WG-Änderungen, nicht andere Geräte, und sie verlängert sich nicht automatisch. Langfristige Auflösung = das Secret-Handling-Design in TP16.1 (Privkey ist Geräte-Identität, nicht Config). > ✅ **Genehmigte Ausnahme #2 (User, 2026-07-22): der CRS326-Bring-up (TP15).** Die **Grundkonfiguration** beider CRS326 — Management-IP, Bridge, VLAN-Filtering, Trunks/Access-Ports — darf **direkt** via MikroMCP/Winbox gemacht werden. **Begründung = Henne-Ei:** Golden Config kann nicht auf ein Gerät pushen, das im Werkszustand keine erreichbare IP hat, und die GC-Templates existieren noch nicht (TP21 „offen: Templates/intended config"). **Auflage:** der so entstandene Ist-Stand wird anschließend als **intended config nach Nautobot zurückgeschrieben**, danach übernimmt GC — die Ausnahme deckt das Bootstrapping, nicht den Dauerbetrieb. **Scope-Grenze:** gilt für die beiden CRS326 im Bring-up. Sie hebt die Regel für ap1/ap2 **nicht** auf (deren Neuprovisionierung läuft weiterhin über GC) und verlängert sich nicht automatisch auf spätere CRS326-Änderungen. Damit ist die frühere Formulierung in TP16.1 („CRS326-Config läuft regulär über Nautobot GC oder braucht eine eigene, dann neu zu erteilende Ausnahme") **erfüllt** — dies ist diese Ausnahme. --- ## Offene Teilprojekte > **Alles hier hat noch offene Arbeit.** Abgeschlossenes steht im > **[Archiv](teilprojekte-archiv.md)** (Volltext, mit Inhaltsverzeichnis) — die Zuordnung ist > mechanisch: *ein TP wandert erst dann ins Archiv, wenn nichts mehr daran zu tun ist.* Wo nur ein > Sub-TP offen war, steht dieses hier und das erledigte Eltern-TP im Archiv (so bei > **TP17.2** ↔ TP17 und **TP20.1** ↔ TP20). ### TP5.1 — DNS-Visibility & Flow-Observability für Low-Trust-Geräte (Airfryer-Fall) ▸ vorgemerkt - **Kontext (2026-07-08/09):** Airfryer „airschreier" (Philips/Versuni, ESP, `10.40.30.180`) bekam per DHCP-Option 6 `dns 1.1.1.1` als Override, weil das OTA-Update über den ap1-DoH-Gateway-Pfad nicht durchging (DoH-Latenz beim primitiven ESP-Stack — **kein** Content-Block, via Gateway-Logs bewiesen, s. `memory/ref_esp_ota_doh_not_block`). Nebenwirkung: public **1.1.1.1 = anonymer Consumer-Resolver ≠ accountgebundener Gateway-DoH** (`px35ynlol3.cloudflare-gateway.com`) → **DNS-Sicht auf das Gerät weg**, Gerät umgeht zudem die Filterung. - **(a) DNS-Redirect statt Geräte-Override** (der dauerhafte Fix): dst-nat „UDP/53 (+TCP/53) von Low-Trust-Src → auf einen *plain* Resolver umbiegen" gibt **Logging zurück UND** funktionierendes OTA (kein langsamer DoH-Pfad fürs Gerät). Redirect-Ziel-Optionen: (i) ap1-Resolver mit *nicht*-DoH-Upstream für dieses Src-Set, (ii) direkt public 1.1.1.1 (dann nur Flow-Logging), (iii) eigener plain-Resolver. Sauberer als „Gerät verschwindet auf 1.1.1.1". Verortung: Teil des UNTRUSTED-Internet-only-Pinnings (TP5-„Offen"); Entscheidung v50-DNS-Policy (gefiltert vs. plain) hängt dran. - **(b) Live-Torch als Ad-hoc-Observability:** DNS ist bei direktem 1.1.1.1 blind, **Flows nicht** (NATen über ap1). `torch` auf `vlan30`/`vlan50` gefiltert auf die Geräte-IP zeigt Ziel-IPs live (Versuni → AWS `eu-west-1` IoT erkennbar). Voraussetzung: Gerät aktiv. Merkregel: Airfryer nur online wenn er kocht → Capture ans Einschalten koppeln. - **Abh.:** UNTRUSTED-Move des Airfryers (Kandidat, s. VLAN50) + TP5-Deny-by-default. Kein Blocker. ### TP8 — Identity & Access-Control ▸ research-gated - **RADIUS = FreeRADIUS auf der NAS** (✏️ User-Manager v5 kann **KEIN LDAP** → openldap nur via FreeRADIUS anbindbar). - **EAP-TLS (Zert) je Gerät + dynamische VLAN-Zuweisung** (RADIUS-Attribut `Tunnel-Private-Group-ID`). **Einfachste Heim-Alternative:** pro VLAN eine SSID mit **WPA3-PSK** (kein RADIUS) — Abwägung Komfort vs. Admin-Aufwand. - Abh.: TP3. (Research erledigt, s. TP-R.) ### TP11 — Monitoring & Mgmt-Control-Plane ▸ research-gated - MikroMCP + omada-mcp + **SNMP/icinga-mikrotik**, RoMON, NTP, **E-Mail-Alerts**, Netwatch. → Teil von `docs/research/routeros-capabilities.md`. - **CF-Tunnel #1033 Track A ✅ live (2026-06-30):** Round-Robin-1033er über 3 asymmetrische Connectors behoben durch Reduktion auf pve-only Connector (NAS + macmini scheiterten an pve-lokalen/stalen Origins). SSoT: `docs/cf-tunnel-mapping.md`. **Track B/C läuft über TP14** (Ingress bereits v116 .41→.20 für NAS; pve-Connector→VLAN20 via TP14 Session B = #1033-Zielbild). ### TP12 — IPv6 (intern + extern, 3 Standorte) ▸ research-gated - Konzept für FM/BF/DW. → TP-R. #### TP12.1 — IPv6 im LAN (ULA) + v6-Firewall ▸ 🟠 **KONKRET GEWORDEN (2026-08-22), Treiber: Matter/Thread** > **Anlass:** der runde IKEA-Fühler **TIMMERFLOTTE** (Matter over Thread) ließ sich nicht anlernen — > „pairing failed" in der Companion-App. Ursache ist **nicht** die Firewall, sondern dass zwischen > VLAN10 und VLAN20 **überhaupt kein IPv6 geroutet wird**. Damit ist TP12 vom Konzept-TP zu einem > Punkt mit einem konkreten, wiederkehrenden Schaden geworden. - **Befund am `crs326-core` (live gelesen 2026-08-22):** - IPv6-Adressen: **ausschließlich Link-Local** (`fe80::…`) auf jedem Interface. Keine ULA, keine GUA. - IPv6-Routing-Tabelle: nur `::1/128` und `fe80::/64` je Interface. **Keine Route** auf den Thread-OMR-Prefix `fd92:505a:c64e:1::/64` und keine auf `fd03:cace:953f:e13d::/64` (den On-Link-Prefix, den der OTBR auf VLAN20 wirbt). - `/ipv6 nd`: Default-Eintrag, `advertise-dns=no` — es gibt aber ohnehin keine Prefixe zu werben. - 🔴🔴 **Der eigentliche Kostenpunkt ist nicht IPv6, sondern die Firewall:** `/ipv6 firewall filter` ist **komplett leer**. Heute harmlos, weil ohne Adressen nichts geroutet wird. In der Sekunde, in der Adressen vergeben werden, steht **IOT→MAIN offen, GUEST→INFRA offen — an TP5 vorbei**. Das gesamte TP5-Regelwerk muss **vorher** in v6 nachgebaut sein, sonst reißt dieser TP genau die Segmentierung auf, die TP5 am 2026-08-18 geschlossen hat. **Das ist die Arbeit, nicht die Adressvergabe.** - 🔎 **Warum Matter das braucht:** Commissioning läuft in zwei Etappen. Etappe 1 (BLE zum Gerät) ist netzunabhängig. In Etappe 2 muss der Commissioner — das iPhone — das Gerät auf dem **operativen Thread-Netz** wiederfinden (DNS-SD `_matter._tcp`, dann CASE). Dafür braucht das Telefon eine IPv6-Route in den OMR-Prefix hinein. iPhone hängt auf VLAN10, OTBR auf VLAN20 → Etappe 2 bricht ab. Die ~30 bereits laufenden Matter-Knoten widersprechen dem nicht: HA und OTBR sitzen auf **demselben Host** (`wpan0` ist lokal), im Betrieb quert nichts die VLAN-Grenze. Nur das *Anlernen* tut es. - ⚠️ **Zwei Fallen, die den naiven Weg verbauen:** - **(a) Der OMR-Prefix ist generiert und wandert.** Am 2026-08-22 um 17:33 (OTBR-Neustart) sind alle Knoten von `fd92:505a:c64e:1::/64` auf **Mesh-Local** `fd66:986:170:bb1a::/64` gefallen — und Mesh-Local ist per Definition *nicht* off-mesh routbar. Eine statische Route auf den OMR-Prefix ist also nur so stabil wie der nächste Neustart. Ihn im Thread-Dataset festzunageln formiert das Netz neu — mit 30+ produktiven Knoten daran kein Nebenbei-Change. - **(b) RouterOS lernt fremde RAs nicht.** Der OTBR wirbt den OMR-Prefix per RA mit Route-Information-Option auf VLAN20. Der Core müsste die annehmen — als forwardender Router für dieses Interface tut er das nicht sauber. - 📡 **Dritter Baustein: DNS-SD über die VLAN-Grenze.** `mdns-repeat-ifaces` am Core (vlan10/20/30/40/90) ist **IPv4**. Für Matter-Discovery bräuchte es zusätzlich einen v6-fähigen Reflector — der `mcast-relay`-LXC (108) kann das prinzipiell, aber als **zweite Instanz** mit Beinen in VLAN10+VLAN20 (SSDP-Instanz ist VLAN10+VLAN40, s. Gotcha in CLAUDE.md). - ✅ **Der Workaround, der das umgeht statt löst:** iPhone zum Anlernen auf **VLAN20** — dann sind Telefon und Border Router auf demselben L2-Link, der OTBR wirbt dort On-Link-Prefix *und* Route, und iOS wertet beides aus. `cfg-infra` / SSID `dirtyvader-infra` (`dp-infra`, VLAN20, `sec-infra` mit PSK) existiert am Manager **bereits**, ist nur in **keiner** `provisioning`-Zeile als Slave hinterlegt. Runbook: [`docs/matter-pairing-infra-ssid-runbook.md`](matter-pairing-infra-ssid-runbook.md). - ✅ **2026-08-22 durchgefuehrt und wieder zurueckgebaut.** `dirtyvader-infra` temporaer auf ap2 (Transaktion `TEST-infra-ssid-matter-pairing`, Scope `wifi-provisioning`), iPhone dort hinein, **TIMMERFLOTTE per Companion-App angelernt** — liefert 25,44 °C / 53,1 % rF / Batterie 100 % (Bereich Technik UG). Danach SSID deaktiviert; `cfg-infra`/`dp-infra`/`sec-infra` bleiben auf User-Wunsch **inaktiv am Manager stehen**, damit der Weg beim naechsten Thread-Geraet ein Zweizeiler ist. Beide Akten geschlossen, `crs326-core` transaktionsfrei. ⇒ **Der Workaround ist damit bewiesen** — und TP12.1 bleibt trotzdem offen: er umgeht das fehlende IPv6-Routing, er behebt es nicht. - ✅ **Der Weg, der das Problem dauerhaft erledigt:** Matter-Server-Option **`ble_proxy: true`** (ab HA 2026.06, hier 2026.8.3). Dann kommissioniert **HA selbst** über seinen Bluetooth-Stack; das Telefon ist raus und die VLAN-Grenze wird nie berührt. Braucht eine **connectable** BLE-Quelle — Shelly-Proxies sind reine Advertisement-Scanner (kein GATT), ein **ESP32 als ESPHome-BT-Proxy** (`active: true`) reicht. Der **ESPHome Device Builder ist bereits installiert**. Damit wäre TP12.1 für Matter **optional**. 🔴 **User-Entscheid 2026-08-22: ESP32 wird NICHT angeschafft.** Damit bleibt `ble_proxy` zwar an (schadet nicht, kostet nichts), ist aber **wirkungslos** — HA hat keine connectable BLE-Quelle und wird auch keine bekommen. **Konsequenz, die man beim nächsten Thread-Gerät kennen muss:** der Weg ist dann wieder die temporäre `-infra`-SSID nach dem Runbook. Die ist inzwischen ein Zweizeiler, weil `cfg-infra`/`dp-infra`/`sec-infra` am Manager stehen bleiben — aber sie ist jedes Mal ein Config-Change am Core plus eine Transaktion. Wer das dauerhaft loswerden will, muss **TP12.1 bauen** (v6-Firewall zuerst); ein dritter Weg ist damit nicht mehr vorgesehen. - 🔎 **Nebenbefund 2026-08-22, gehört zur Thread-Gesundheit, NICHT zu IPv6:** drei Matter-Knoten flappen dauerhaft — **`@1:a` („Diele OG/Treppenauge")**, **`@1:f`** und **`@1:10`**. Muster im Matter-Server-Log: `IpServiceStatus … Resolving (address is unreachable)`, dann `offline grace period expired, marking unavailable`, im Abstand von 15–30 Minuten, über Stunden. Die übrigen ~20 Knoten sind stabil, es ist also **kein** Border-Router- oder Fabric-Problem. ⚠️ **Vor einer Diagnose die Sonderlage von heute abziehen:** der OTBR ist am 2026-08-22 um 17:33 neu gestartet (Knoten fielen kurzzeitig von OMR `fd92:…` auf Mesh-Local `fd66:…` zurück), und ap1 war zwischenzeitlich vom Netz. Erst nachsehen, ob das Flappen **danach** noch besteht — sonst diagnostiziert man das Nachbeben eines Umbaus. Erste Verdachtsrichtungen, wenn es bleibt: Thread-Routing/Parent-Wechsel dieser drei Knoten, schwache Funkstrecke zum nächsten Router-Knoten, oder eine ICD-/Sleepy-End-Device-Eigenheit dieser Geräteklasse. - **Abh.:** hängt an nichts. **Blockiert nichts** — außer künftige Thread-Geräte, solange weder `ble_proxy` noch die `-infra`-SSID steht. Reihenfolge innerhalb des TP ist zwingend: **v6-Firewall nachbauen → dann erst Adressen vergeben.** Gehört unter TP12 (Gesamtkonzept 3 Standorte), ist aber allein für BF ausführbar. ### TP13 — „Botschafts-WLANs" ▸ 🔜 **AUSFÜHRBAR (Runbook 2026-08-19)** — `docs/tp13-botschafts-wlan-runbook.md` · fun/low-prio > 📌 Am 2026-08-19 überarbeitet: der Technikteil beschrieb noch Standalone-APs (SSIDs entstehen seit > TP28 am **Manager**, also ein Deploy statt zwei), und der Entwurf „nur `ssid=`, kein Security" war ein > **Denkfehler** — eine SSID ohne Security *ist* ein offenes WLAN, also genau der Fall, den der > Rechtsvorbehalt ausschließen soll. Richtig: PSK, den niemand kennt. Dazu die Datapath-Falle > (Slave-VAP ohne `vlan-id` landet ungetaggt in der Bridge — dieselbe Mechanik wie der 14-h-Ausfall). - **Idee:** eine/mehrere **Broadcast-only-SSIDs als „schwarzes Brett"** an die Funk-Nachbarschaft — der SSID-Name *ist* die Botschaft (z.B. `Kanal-11-bitte-freihalten`, `WLAN-Tuning-siehe-Portal`). Optional ein **offenes WLAN mit Captive-Portal** auf eine **statische Info-HTML** (Kanalabsprache, Auto-Kanalwechsel-Bitte). Leitgedanke: wer die SSID sieht, kann auch stören → die Infoseite erreicht genau die Zielgruppe. - ~~**Technik (jetzt einfach, da WLAN standalone seit TP3-Rebuild):** reine Namens-SSIDs = zusätzliche `/interface/wifi` Slave-VAPs auf wifi1/wifi2 mit eigener `configuration` (**nur `ssid=`, kein Security/Datapath**)~~ ⚠️ **Überholt 2026-08-19, in zwei Punkten:** - **(a) WLAN ist seit TP28 nicht mehr standalone.** SSIDs entstehen am **Manager `crs326-core`** (9 `configuration`-, 6 `datapath`-Objekte, 4 `provisioning`-Zeilen — live gelesen 08-19). Das ist für TP13 sogar einfacher: **ein** Deploy statt zwei. - **(b) 🔴 „kein Security" *ist* ein offenes WLAN** — genau das, was der Rechtsvorbehalt unten ausschließen will. Richtig ist eine SSID **mit** WPA2/WPA3-PSK, den niemand kennt: sie beacont den Namen, ist aber nicht beitretbar. - Captive-Portal-Variante (RouterOS-**Hotspot**, isoliertes VLAN, `walled-garden`) bleibt als Option bestehen — s. Rechts-Gate unten. - ~~**Umsetzungs-Skizze:** … Beacon-SSIDs in `routeros/.secrets/ap{1,2}-prov-base.rsc` ergänzen …~~ → diese Dateien sind für den WLAN-Teil **Historie** (die CAPs sind auf die `cap`-Zeile eingedampft). **Aktuelle Umsetzung: `docs/tp13-botschafts-wlan-runbook.md`** (2026-08-19). - 🔴🔴 **Die Falle, die dort ausführlich steht:** ein Slave-VAP **ohne explizite `vlan-id` am Manager** landet ungetaggt in `bridge` — weil der CAP vom Manager-Datapath **nur die `vlan-id`** übernimmt. Das ist dasselbe Leck wie TP3.1 (`cfg-main-2g` ohne datapath) und dieselbe Mechanik wie der 14-h-Ausfall vom 08-18. Die Botschafts-SSID braucht deshalb einen Datapath mit **totem** `vlan-id` — PSK **und** toter Datapath, nicht eines von beidem. - ✅ **VAP-Budget geprüft (live 08-19), unkritisch:** `max-interfaces=16` je Radio, belegt sind 4 (5 GHz) bzw. 5 (2,4 GHz). **Die Grenze ist Airtime, nicht die Zahl** — jeder VAP beacont eigenständig. Empfehlung: **genau eine SSID, auf 2,4 GHz** (mehr Reichweite = mehr Nachbarn, und 5 GHz bleibt für Nutzverkehr frei). - ⚠️ **Recht vor Scharfschalten prüfen (User privat, AT):** offenes WLAN + Portal berührt Impressumspflicht/Störerhaftung — **reine Namens-SSIDs ohne offenen Zugang sind unkritisch** (kein Fremd-Datenverkehr); im Zweifel nur die Beacon-Variante. - **Abh.:** ~~TP3-Rebuild ✅ (Standalone-APs — SSID-Änderung = 1 Deploy/GC-Job)~~ → **TP28 ✅** (CAPsMAN auf dem Core) + **TP22 ✅** (GC-Deploy-Pipeline). SSID-Änderung = **ein** Deploy auf den Core; Direkt-Edit am Gerät ist durch den Governance-Entscheid ausgeschlossen. ### TP14.4 — Session D: CF-Access-Profil für Claude ▸ 🔜 **AUSFÜHRBAR (Runbook 2026-08-19)** — `docs/tp14.4-cf-access-token-runbook.md` · nicht cutoff-kritisch > 📌 Ist-Stand geprüft: in `mcp/cloudflare/.env` stehen **weder** `CF_ACCESS_CLIENT_ID` **noch** `_SECRET` — > es ist also nichts halb erledigt. ⚠️ Das Secret existiert **nur im Moment der Rotation**. > Abnahme braucht **beide** Fälle (mit Headern antwortet / ohne Header 403), sonst ginge ein > bypass-Hostname wie `vw` fälschlich als Erfolg durch. Kein CF-Write erfolgt. - CF-Token „claude code mcp" hat jetzt `Access: Service Tokens: Write`+`Read` → `claude-mcp` rotieren (`POST …/access/service_tokens/{id}/rotate`) → `CF_ACCESS_CLIENT_ID`/`_SECRET` in `mcp/cloudflare/.env` (chmod600). Memory `ref-cf-access-claude-profile`. - 📋 **Runbook: `docs/tp14.4-cf-access-token-runbook.md`** (2026-08-19). **Ist-Stand verifiziert:** `mcp/cloudflare/.env` enthält bisher weder `CF_ACCESS_CLIENT_ID` noch `_SECRET` — es ist nichts halb erledigt. 🔴 **Das Secret wird nur bei der Rotation ausgegeben**, wer es nicht sofort schreibt, muss erneut rotieren. Abnahme = ein Aufruf **mit** den Headern (antwortet) **und** einer **ohne** (403) — der Erfolgsfall allein beweist nichts, der Hostname könnte auf `bypass` stehen. ### TP16 — CF-Tunnel: Round-Robin killen + reziprokes HA ▸ ✅ KERN UMGESETZT (2026-07-10) — ⚠️ **HA aktuell degradiert (Live-Befund 2026-08-16)** — `docs/cf-tunnel-mapping.md §10`, #1033 - 🟠 **BEFUND 2026-08-16 (beim Doku-Aufräumen live über die CF-API erhoben, kein Eingriff): das reziproke HA läuft nur noch auf einem von drei Tunneln.** - `bf-mm` = **2 Connectoren** (je 4 conns) ✅ · `bf-nas` = **1 Connector** (3 conns) 🟠 · `bf-pve` = **1 Connector** (4 conns) 🟠. - **Bedeutung:** die Dienste hinter `bf-nas` (gitea, grafana, pve-mcp, **vw**, ds-bf, nautobot) und `bf-pve` (pve, ccu, iobroker, z2m25, portainer, **hass**, ha-mcp) hängen jeweils an **einem einzigen** cloudflared-Prozess. Fällt dessen Host aus, sind sie weg — genau der Zustand, den TP16 beseitigt hat. **Kein `530`/Round-Robin-Problem** (das bleibt strukturell gelöst), sondern **Redundanzverlust**. - **Bekanntes Muster:** identisch zum Incident vom 2026-07-16 (macmini-Connectoren flappten unter QUIC → Fix `TUNNEL_TRANSPORT_PROTOCOL=http2`). Diesmal sind die *macmini*-Connectoren oben (bf-mm hat 2), es fehlt je **ein** Gegenstück auf NAS/pve. **Nächster Schritt (eigene Session):** auf NAS und pve nachsehen, welcher der beiden cloudflared-Container nicht läuft, und ob es der `http2`-Konventionsfall ist. - 🧹 **Nebenbefund beim selben Sweep — Alt-Tunnel mit VLAN1-Origins (alle `down`, 0 Connectoren, daher aktuell harmlos):** `openclaw` (→ `10.40.41.147/.148/.139`), `coolify` (→ `10.40.41.133`), `johnny2`, `TeilzeitCharlie`. ⚠️ **`openclaw` beansprucht `n8n.emsenhuber.net`, das produktiv auf `bf-mm` läuft** — käme der Tunnel je wieder hoch, entstünde exakt das alte Round-Robin-Muster auf diesem Hostname. **Empfehlung: die vier toten Tunnel löschen** (user-gated, Löschen ist nicht umkehrbar) — gehört fachlich zu **TP19** (VLAN1-Retirement: `.41.133` war eines der „unidentifizierten VLAN1-Geräte" aus TP19 B1.2 — hiermit als coolify-Origin identifiziert). > **✅ Umgesetzt (2026-07-10, eigene Session):** reziprokes **3-Tunnel-HA** live (bf-nas `70d6a4cf` / bf-pve `f7fdf3a6` / bf-mm `7a322261`), 6 Connectoren (2/Host, je Fremdhost), 19 FQDNs Loop-Smoke **0×530**, HA per Host-Ausfall-Sim bewiesen. Round-Robin-#1033 **strukturell weg**. As-Built = `docs/cf-tunnel-mapping.md §10`. **Schritt 5 Access-Strang: ~~`vw` bypass→geschützt via WARP~~ — 🔴 GESTRICHEN (User-Constraint 2026-08-14, s. TP16.2). Verbleibend offen: `hass`/`ha-mcp` 400/403; `gateway-dw` (WG→404) klären.** - **Symptom (User):** FQDNs über CF werden **sporadisch / „sehr unsicher"** aufgelöst = #1033-Muster zurück („jeden 3. Schuss eine Niete"). User hat alle 3 cloudflared-Images + Container aktualisiert/neu gestartet. - **✅ Root-Cause endgültig (User-Diagnose bestätigt): macvlan/ipvlan-Host-Isolation.** Ein cloudflared-Connector ist **blind für macvlan/ipvlan-Container auf seinem EIGENEN Host** (Linux-Kernel-Regel), erreicht aber Fremdhost-L2 + co-lokierte Bridge-Container. Mehrere Connectoren auf EINEM Tunnel = geteilter Ingress + CF-**Round-Robin** → jede Origin, die auf dem Host *eines* Connectors liegt, fällt bei ~**1/N** aus. **Strukturell**, nicht durch „Origins fixen" heilbar. Bsp: `omada .20.175`/`pve-mcp .20.173`/`gitea .20.157`/`grafana .20.109` = NAS-macvlan → vom NAS-Connector NICHT erreichbar. - **Invariante:** innerhalb EINES Tunnels ist **kein Route→Connector-Pinning** möglich (alle Connectoren teilen Ingress, CF round-robined). „Ausgewählte Routen für ausgewählte Connectoren" = **getrennte Tunnel**. - **Ziel-Design (HA): reziproke Per-Host-Tunnel** — jeder Host-Dienst wird von den Connectoren der ANDEREN Hosts bedient (nie vom eigenen): | Tunnel (= Dienste eines Hosts) | Connectoren auf | HA | |---|---|---| | pve-Dienste | NAS + macmini | 1 abdrehbar | | NAS-Dienste (omada/pve-mcp/gitea/grafana/…) | pve + macmini | 1 abdrehbar | | macmini-Dienste (`.20.167`) | pve + NAS | 1 abdrehbar | 3 Tunnel, jeder Host fährt 2 cloudflared → Host-Ausfall ⇒ jeder Tunnel ≥1 Connector = **voll HA**. Voraussetzung: jede Origin L2-erreichbar. - **Ist-Inventory (live 2026-07-10, s. `cf-tunnel-mapping.md §9`):** Ingress v119, 24 Hostnames, 2 live Connectoren. **DOWN/stale:** `pbs .20.135`, `nginx-bf .41.123` (noch VLAN1!), `hermes`+`hermes-geli .20.167`. **Zu klären (Host/Netz):** `vw .20.127`/`ccu .20.232`/`iobroker .20.107`/`z2m25 .20.106` — ggf. `vw`/`ccu` auf VLAN20-macvlan heben. `gateway-dw` (192.168.178.1) = WG-Sonderfall. - **CF-Access-Strang (verzahnt, s. TP11 Track-B):** `hass`-**400 in der HA-iPhone-App = CF-Access davor** (Companion-App kann Access-Login nicht) → Fix **ohne Passthrough**: iPhone in **WARP** enrollen (Device-Identity erfüllt Access; „Warp Login App" existiert bereits `allow:christoph`). ~~⚠️ **`vw` = aktuell `bypass` (öffentlich!)** → von bypass auf geschützt heben.~~ 🔴 **Überholt (2026-08-14): `vw` BLEIBT bypass — harter User-Constraint, Härtung stattdessen über TP16.2.** „Passthrough-Hosts sind die kritischen" (User). - **Umsetzungs-Reihenfolge (für die eigene Session):** (1) **Reachability-Matrix je Host** (pve/NAS/macmini → jede Origin, read-only) BEVOR gruppiert wird; (2) **Interim-Sofortfix:** bf-Tunnel auf **pve-only** (pve erreicht alles außer gateway-dw) → 0×1033, reversibel; (3) reziprokes 3-Tunnel-HA bauen (CNAMEs re-pointen, 6 Connectoren, Token je Tunnel; NAS/macmini-Alt-Token entfernen); (4) tote Origins bereinigen; (5) Access-Strang (WARP + vw); (6) Loop-Gegentest. - Abh.: TP14.1/14.2 ✅. Verwandt: **TP11** (CF-Tunnel-Track-B/C + Access), #1033. SSoT: `docs/cf-tunnel-mapping.md`. Memory `project_cf_tunnel_1033`. - ✅ **Incident 2026-07-16 (User unterwegs, WARP „spinnt", keine BF-IPs mehr) ▸ Public-FQDN-Teil gefixt:** macmini-Connectoren (`cloudflared-bfnas`/`-bfpve`) flappten live unter QUIC/UDP (Docker-Desktop-Bridge-NAT) → `bf-nas`/`bf-pve` von 2 auf 1 Connector degradiert (HA faktisch weg, nicht down). Fix: beide auf `TUNNEL_TRANSPORT_PROTOCOL=http2` umgestellt (rollend, 0 Downtime), wieder voll HA. Konvention: macmini-Connectoren künftig immer `http2`. **ICMP-Befund (getrennt, strukturell):** TCP über die WARP-Route ging überall, ICMP nicht (fm 36 %/bf 100 %/dw 100 % Loss) — cloudflared ist QUIC-Proxy, kein WireGuard. **Kurz als „bf-pve-Route wegen USV" notiert (Commit `1c1a676`) → REVIDIERT** (Begründung invertiert: bf-pve-Connectoren laufen auf NAS+macmini, nicht pve). Details: `docs/cf-tunnel-mapping.md §13`. **→ Richtungswechsel für Private Access = TP16.1.** ### TP16.2 — Härtung der öffentlich erreichbaren Dienste (bypass-Strang) ▸ 📋 KONZEPT (2026-08-14), Umsetzung offen - 🔴 **HARTER CONSTRAINT (User 2026-08-14): `vw` wird NICHT WARP-/Access-geschützt.** Gilt dauerhaft, nicht „vorerst". **Begründung (technisch belastbar, nicht Bequemlichkeit):** die Bitwarden-Clients (Browser-Extension, Mobile, Desktop) können den **interaktiven Access-Login nicht durchführen** — dasselbe Muster, das die HA-Companion-App auf `400` laufen lässt. Ein Passwortmanager hinter einem Client, den man im Notfall (fremdes Gerät, Neuinstallation, Handyverlust) nicht installieren kann, ist ein **Aussperr-Risiko gegen den eigenen Schlüsselbund** — und damit gefährlicher als das, wovor die Maßnahme schützen soll. **Die frühere TP16-Schritt-5-Absicht „vw von bypass auf geschützt heben" ist damit gestrichen.** - **Ziel stattdessen: Schutz erhöhen, ohne Clients zu brechen** — gilt für **alle** bypass-Dienste (`vw`, `hass`, `gitea`). - ✅ **Schicht 0 — bereits vorhanden, nicht unterschätzen:** keine offenen Ports, **alles ausschließlich über CF-Tunnel** (3-Tunnel-HA, TP16), TLS terminiert an der Edge, DDoS-Schutz. Der Origin ist nicht direkt erreichbar. Das ist bereits mehr als bei den meisten Selfhostern. - ✅ **Schicht 1 — chirurgisch: Access nur auf die Pfade, die kein Client anfasst.** CF Access wertet **die spezifischere Application zuerst** → man kann eine **zweite Access-App auf `vw.emsenhuber.net/admin*`** legen (echte Policy) und den Host im Übrigen auf bypass lassen. **Das Admin-Panel wird ausschließlich per Browser bedient — dort funktioniert der Access-Login einwandfrei**, während `/api`, `/identity` und `/notifications` (die Client-Pfade) unberührt bleiben. Kein Client bricht, das wertvollste Ziel ist weg. - Alternativ noch härter: **Admin-Panel ganz aus** (`ADMIN_TOKEN` leer lassen) und nur bei Bedarf temporär aktivieren. - Analog für **`gitea`**: `/admin*` + Registrierung path-scoped schützen (Git-über-HTTPS mit Token bleibt offen). - ✅ **Schicht 2 — App-eigene Bremsen (kostenlos, sofort):** Vaultwarden hat Rate-Limits **per Default an** (`LOGIN_RATELIMIT_SECONDS=60`, `LOGIN_RATELIMIT_MAX_BURST=10`, dazu `ADMIN_RATELIMIT_*`) → Werte prüfen/verschärfen; `SIGNUPS_ALLOWED=false`, `INVITATIONS_ALLOWED=false`, `SHOW_PASSWORD_HINT=false`, **2FA erzwingen**. HA hat `ip_ban_enabled` + `login_attempts_threshold`. Gitea: Registrierung aus. - ✅ **Schicht 3 — Edge-Regeln (CF), wirkt für alle Dienste gemeinsam:** WAF-Custom-Rules + **Rate Limiting gezielt auf die Login-Endpunkte** (`/identity/connect/token` bei vw, `/auth/login` bei HA, `/user/login` bei Gitea); optional Geo-/ASN-Filter. ⚠️ **Free-Plan-Kontingente vorher im Dashboard prüfen** (nicht belegt). - ✅ **Schicht 4 — ein Mechanismus für alle: CrowdSec (oder fail2ban) mit Cloudflare-Bouncer.** Bans landen dann **an der Edge** statt erst am Origin. Vaultwarden hat ein offizielles Fail2Ban-Setup-Wiki (Log-Muster für Login **und** Admin-Panel). - 🔴 **Voraussetzung für Schicht 2–4, und der eigentliche Knackpunkt: die echte Client-IP muss am Origin ankommen.** Hinter dem CF-Tunnel sieht die Anwendung sonst **nur die IP des cloudflared-Containers** → jede IP-Sperre bannt den Tunnel statt den Angreifer = **Selbstaussperrung aller Nutzer**, und Rate-Limits greifen ins Leere. **Genau dieser Defekt ist bereits offen dokumentiert:** HAs `trusted_proxies` fehlen `.20.10`/`.20.167` (TP16, `hass`-400-Strang). ➡️ **`X-Forwarded-For`/`CF-Connecting-IP` sauber durchreichen ist Schritt 1 dieses TPs**, alles andere baut darauf auf. - **Reihenfolge:** (1) Client-IP-Weitergabe fixen (inkl. HA `trusted_proxies`) → (2) `/admin`-Pfade path-scoped schützen → (3) App-Limits + 2FA → (4) Edge-Rules → (5) CrowdSec/fail2ban mit CF-Bouncer. - **Abh.:** TP16 ✅ (Tunnel-HA). Verwandt: **TP20.1** (vw wandert auf Platform-Postgres — DB-HA ≠ Access, getrennt halten), **TP23** (dessen WARP-Managed-Network-Idee ist durch diesen Constraint **entlastet**: `vw` verlangt keine Device-Identity, also kollidiert „WARP zuhause aus" nicht mehr mit dem Access-Strang). ### TP16.3 — cloudflared-Reduktion: was der Mesh als Datenpfad kann (und was nicht) ▸ 🔜 **AUSFÜHRBAR (Runbook 2026-08-19)** — `docs/tp16.3-nautobot-mesh-only-runbook.md` > 📌 Der Schnitt (`nautobot` aus dem `bf-nas`-Ingress) ist ausformuliert inkl. Vorbedingungen, PUT-Ablauf > und Rollback. Zwei Punkte stehen dort explizit, weil sie den TP sonst kippen: **Mesh-Hostname-Routes > sind Egress und veröffentlichen nichts** (wer das verwechselt, baut den Public-Strang ab), und > **Nautobot ist nicht nur Web-UI, sondern die Deploy-Pipeline** → zur Abnahme gehört ein Job-Lauf, > nicht nur ein Browser-Aufruf. > **Christophs Frage (2026-08-17):** „recherchiere, ob unser neuer wg-tunnel/cf mesh als datenpfad für die > server/services genutzt werden kann. die containerpflicht als offizieller weg ist für mich unlogisch." - ✅ **Die Container-„Pflicht" gibt es für den privaten Zugang tatsächlich nicht — und wir nutzen sie schon nicht mehr.** CF-Docs (Mesh↔Tunnel-Vergleichstabelle) sind eindeutig: **Mesh** = bidirektional, L3/L4, **TCP+UDP+ICMP**, jeder Teilnehmer bekommt eine Mesh-IP, Connector = `warp-cli` **oder ein nativer WireGuard-Peer** (unser Fall). **Tunnel** = *inbound zum Origin*, Veröffentlichen von Hostnames, Connector = `cloudflared`, Protokolle HTTP/S·TCP·SSH·RDP·SMB **über WebSocket geproxied**. Für „Server hinter dem Node erreichbar machen, die keinen Client laufen lassen können" nennen die Docs ausdrücklich **CIDR-Routes auf dem Mesh-Node** als den Weg — wörtlich für „servers, databases, printers, IoT devices". - 🎯 **Das ist bei uns seit TP16.1 bereits scharf:** die vnet-Route `10.40.0.0/16` zeigt auf `bf-core-mesh` (§4.4, Weg A). **Der gesamte private Datenpfad läuft schon über natives WireGuard auf dem Core, ohne jeden Container.** Und er ist im TP5-Log-Lauf **belegt**, nicht vermutet: 137 Zeilen `in:cf-mesh`, Quelle `100.96.0.1` → Nautobot `.20.30:8080` (62×), NAS `.20.10:6690` (46×), macmini `:22`, NAS `:5000/:5001/:443/:22`, pve `.20.100:8006`, pve-mcp `.20.173:3000`, branch/ap1/ap2 `:22`. **Christophs Instinkt war richtig.** - 🔴 **Wo die Container-Pflicht echt ist — und warum sie nicht willkürlich ist:** für einen **öffentlichen Hostname**, den jemand **ohne** WARP im Browser aufruft, braucht es einen Reverse-Proxy an der Edge. Das ist `cloudflared`. **Achtung Verwechslungsfalle:** Mesh kennt seit 2026-07-02 ebenfalls **Hostname-Routes**, und die können auch *public* hostnames — aber das ist **Egress**: „route that hostname's traffic through the node and egress via the node's public IP". Es **veröffentlicht nichts**. Wer das verwechselt, baut den Public-Strang ab und ist überrascht. - ✅ **Der reale Gewinn ist trotzdem groß, weil die meisten Dienste keinen öffentlichen Hostname brauchen.** Kriterium: **hat der Dienst einen Client, der keinen interaktiven Access-Login kann?** (dieselbe Logik wie der TP16.2-Constraint bei `vw`) | Muss öffentlich bleiben (cloudflared) | Grund | Kann auf Mesh-only | |---|---|---| | `vw` | Bitwarden-Clients, harter TP16.2-Constraint | `pve`, `nautobot`, `portainer`, `grafana` | | `hass` | Companion-App (400-Muster) | `pve-mcp`, `ha-mcp`, `gitea-mcp`, `ds-bf` | | `n8n` | eingehende Webhooks von Dritten | `ccu`, `iobroker`, `z2m25` | | `gitea` | Git-Clients / CI von außen — **zu prüfen** | | → Für die rechte Spalte ist der Mesh **funktional gleichwertig und operativ einfacher** (keine Ingress-Zeile, kein Connector-Paar, keine HA-Frage). Sie erreicht man ohnehin schon per privater IP. - 📌 **Zwei Nebeneffekte, die den Fall stärken:** (1) die **TP16-HA-Degradierung** (`bf-nas`/`bf-pve` je nur ein Connector) verliert an Gewicht, sobald nur noch die vier Public-Dienste an cloudflared hängen — weniger Dienste pro SPOF; (2) **ICMP + beliebiges UDP** gehen über den Mesh und über cloudflared grundsätzlich nicht (der QUIC-Proxy war genau die Lücke aus TP16.1). - ⚠️ **Grenzen, ehrlich benannt:** (a) der Mesh-Weg setzt **WARP auf dem Client** voraus — für Christophs eigene Geräte gegeben, für Gäste/Fremdgeräte nicht; (b) **IPv6-CIDR-Routes brauchen MASQUE** und funktionieren mit einem WireGuard-Device-Profil **nicht** — deckt sich mit dem v4-only-Entscheid aus TP16.1, wäre aber ein Blocker, falls TP12 später v6 über den Mesh wollte; (c) es bleibt eine **Cloudflare-Abhängigkeit** — der Mesh ersetzt cloudflared, nicht Cloudflare. - **Vorgeschlagener Umsetzungsschnitt (klein anfangen, reversibel):** einen Dienst der rechten Spalte als Probe aus dem CF-Ingress nehmen (Kandidat: `nautobot` — nur Christoph nutzt es, im Mesh-Log mit 62 Treffern der am häufigsten per Mesh angefasste Dienst, und ein Fehlschlag kostet nichts Produktives), eine Woche fahren, dann entscheiden. **Rollback = eine Ingress-Zeile zurück.** - 📋 **Runbook: `docs/tp16.3-nautobot-mesh-only-runbook.md`** (2026-08-19) — der Schnitt oben, ausführbar ausformuliert: Vorbedingungen (Mesh-Route, Zugriff über `10.40.20.30:8080` **mit WARP von außerhalb**), Ingress-`PUT` über `CF_API_TOKEN` (**nicht** über den CF-MCP, der ist read-only), Rollback aus der gesicherten Config. - 🔴 **Der Abnahmepunkt, den man übersieht:** Nautobot ist nicht nur Web-UI, sondern die **Deploy-Pipeline**. Nach dem Schnitt gehört ein Job-Lauf zur Abnahme, nicht nur ein Browser-Aufruf — der Netmiko-Deploy kommt von `10.40.20.31` (`nautobot-worker`), nicht von `.20.30`. - ⚠️ Beim Kürzen des `ingress`-Arrays muss die **Catch-all-Regel die letzte bleiben**, sonst greift der Ingress für alle übrigen Hostnames nicht mehr. - **Abh.:** TP16.1 ✅ (Mesh live), TP16 (Public-Strang + dessen HA-Degradierung), **TP16.2** (der `vw`-Constraint liefert das Entscheidungskriterium). ⚠️ **Berührt TP5:** der Mesh-Verkehr braucht bei deny-by-default eine explizite `forward`-Zeile — s. TP5 Etappe 2. ### TP17.2 — einheitliches Geräte-Passwort (Shelly `SetAuth`) ▸ ⏸️ ZURÜCKGESTELLT (Kosmetik, User 2026-07-13) - **Was:** je Gerät `Shelly.SetAuth` (User `admin`, realm-individueller `ha1` = sha256("admin::"), einheitliches Klartext-PW) via `mcp/shelly/migrate.py auth --go`. `SHELLY_DEVICE_PW` liegt in `mcp/shelly/.env` (gesetzt, len 13). Runner + Digest-Auth-Fallback in `_rpc` fertig. - **Warum zurückgestellt:** rein kosmetisch/Härtung; **bricht die HA-Shelly-Integration**, bis pro Config-Entry (22×) das Credential neu eingetragen ist → disruptiv, kein Mehrwert im abgeschotteten IOT-VLAN. **Erst nach** dem Netz-Teardown (TP19) neu bewerten. ### TP18 — Souveräner Objektspeicher (Garage, Multi-Site, S3-Cold-Tier) ▸ 🔜 KONZEPT (2026-07-12) - **Auslöser:** 9-TB-Syno-Backup-Volume **zu 2/3 voll**; reine Daten ~3 TB, Tendenz steigend, „schlagartiger" Bedarf nicht ausgeschlossen. „Wenn skalieren, dann jetzt Syno-Nachfolger mitdenken." - **Kriterien (User-priorisiert):** (1) **keine Fremd-Abhängigkeit / kein Cloud-Lock-in** (Cloud-Opex abschreckend); (2) **Multi-Site BF/FM/DW**; (3) **HA** (Standort-Verlust überlebbar); (4) **billig/teuer trennen** — Variante **„kalt = Objektspeicher, heiß = lokal"** genügt (kein Hot/Cold *innerhalb* des Stores nötig); (5) **horizontal + vertikal skalierbar**; (6) **S3-API als Branchenstandard**, den jedes Backup-Tool spricht. - **Entscheid Engine = Garage** (Deuxfleurs, Rust): einziger Kandidat, der **geo-verteilt über offenes Internet/WAN latenztolerant** ist (CRDT-Metadaten, eventually consistent) → passt aufs 3-Keller-Modell BF/FM/DW. **Ceph verworfen** (will Sub-ms-LAN, Single-Cluster-über-WAN = Anti-Pattern; zu schwer, ~1 GB RAM/TB). **MinIO** (AGPL + Console/Feature-Abbau 2025) und **SeaweedFS** (kann Hot/Cold + Erasure-Coding, aber komplexer, Multi-Site async) = **Fallback**, falls später feingranulares Tiering / EC-Effizienz bei zweistelligen TB dominant wird. - **Entscheid Disk-Layout = JBOD, KEIN RAID.** Redundanz gehört in **eine** Schicht: Garage RF=3 über 3 Sites *ist* die Redundanz. RAID 1 darunter = Doppelt-Bezahlen (3 Sites × 2 Mirror = **6× roh für 1× nutzbar**, absurd). RAID 0 verworfen (1 Platte tot = ganzer Node-Rebuild über WAN). **JBOD = jede Platte eigenes Garage-Data-Dir** (v1 Multi-HDD): Failure-Domain = 1 Platte, Rebuild nur deren Anteil, kein Kapazitätsverlust. **Merksatz: distributed store = „just a bunch of disks", Redundanz ausschließlich über die Sites.** - **Was man dafür bezahlt:** Plattentod triggert **Re-Replikation über WAN** (durch Upload-BW gedeckelt). Bei ~3 TB/Site tolerabel; wenn Bedarf „schlagartig" auf zweistellige TB springt → mehr/kleinere Platten (Blast-Radius) oder 4. Node, ggf. Wechsel auf SeaweedFS-EC. - **Dimensionierung (Planungsanker 10 TB nutzbar; heute 3 TB unique / 6 TB Backup-used):** RF=3 → **30 TB roh gesamt = 1 volle Kopie ~10 TB/Site** (provisionieren ~16 TB roh/Site: 2 Platten = halber Blast-Radius + Headroom). Linear skalierend. - **Kostenmodell** *(Annahmen: HDD neu CMR ~€18/TB · recert ~€10/TB · Strom €0,25/kWh · Lean-Node Mini-PC/pve 12 W + 2 HDD ~20–28 W)*: - **Capex kumulativ (3 Sites):** Platten €540 (recert) – €900 (neu) + Nodes €400 (BF=pve €0; FM/DW je Mini-PC ~€200) = **~€600–1.300**. Vergleich: *ein* resilienter Syno-Nachfolger für 10 TB = €1.000–1.600 capex **ohne** Geo-HA → Garage-3-Node gleich teuer/billiger **mit** HA. - **Opex kumulativ:** ~€135–185/J Strom — aber **getrennt gerechnet:** FM/DW laufen über **fremde Zähler**, auf Christophs Zähler landet nur der **BF-Node ≈ €50–60/J** (Gegenleistung: er hostet deren Kopie, reziprok wie TP16). - **JBOD-vs-RAID1-Ersparnis:** Strom bloß **€9–22/J** (Christophs Zähler) → *kein* Entscheidungsgrund; der Hebel ist **Capex ~€900** (nicht gekaufte Spiegelplatten) + architektonische Korrektheit. (Reicht nicht für ein BW-Upgrade €120–240/J, taugt aber als Seed für HW-Rückstellungen.) - **Konzeptioneller Bruch (Syno-Nachfolger):** Kein *großes resilientes NAS* mehr nötig — die kollektive 3-Site-Redundanz *ist* die Garantie. **Syno-Rolle splittet:** Hot/SMB/VM-Disks bleiben lokal (Syno **oder** ZFS auf pve, klein/schnell); **Backup/Cold wandert in Garage über BF/FM/DW** → das 9-TB-Volume wird **aufgelöst** statt ersetzt (aus 1 SPOF werden 3 geo-redundante Kopien). Backup-Tool (restic/Kopia) sprechen S3 nativ. - **Impacts auf Bestand (Kurz):** (a) **Storage-Redundanz-Philosophie kippt** — weg von SHR/RAID pro NAS, hin zu 3× JBOD; (b) **Backup-Kette** Hyper-Backup/SMB → S3-Bucket umstellen; (c) **Container-Host-System** (TP14) kriegt Garage als LXC/Container je Site, aber auf **rohen Platten**, nicht auf bestehenden SHR-Volumes; (d) **Upload-BW** wird Durchsatz-/Rebuild-Limit; (e) **HW-Planung** verzahnt mit TP15 (Node-HW, pve-Standort) und **TP24** (Stromversorgung je Site), FM/DW brauchen je 1 Node. - **Startpfad (inkrementell/reversibel):** ① BF zuerst — Garage-Container auf pve, 2 HDDs JBOD, Backups lokal auf Bucket (sofort Nutzen, noch keine Redundanz). ② FM/DW nachziehen (Mini-PC + 2 Platten), RF→3, ab jetzt geo-redundant+HA. ③ Syno entlasten (Backup-Last abgeben). - **Offen (Modell scharfstellen):** realer Strompreis; ob **FM/DW eigene Nodes stellen** oder Christoph HW hinstellt; Backup-Tool-Wahl (restic vs Kopia); ob heißes Zeug künftig auf ZFS/pve statt Syno. - Abh.: **TP10** (WG-Multi-Site = Transport, Upload-BW-Constraint), **TP14** (Container-Hosts), **TP15** (Node-HW) / **TP24** (Stromversorgung), Muster von **TP16** (reziprokes Per-Host-HA). Kein Blocker für laufende TPs. SSoT dieser Session. ### TP20.1 — Vaultwarden → Platform-Postgres + Cross-Site-HA ▸ 🔜 KONZEPT (2026-07-14, ausgelagert aus TP20) - **Ziel:** `vw` (`.20.127`, heute MariaDB) auf den Precious-Tier holen **und** das eigentliche User-Ziel erfüllen: **DB-Replikation über 2 Sites** (Standort-Verlust überlebbar). - **Phase 1 — Migration (single-site):** vw **MariaDB→Postgres** (Export → Import in Tier-1-DB `vaultwarden` → `DATABASE_URL` umstellen → verifizieren). Danach ist vw precious + im pgBackRest/PITR-Schirm von TP20. *(Alternative verworfen: vw auf MariaDB lassen + MariaDB-Repl — zugunsten EINER Replikations-/Backup-Mechanik im Precious-Tier.)* - **Phase 2 — Cross-Site-Standby:** `db-platform-standby`-LXC am 2. Standort → `pg_basebackup`/Streaming-Replication über **WG (TP10)** → **manuelles Promote-Runbook**. Repliziert den ganzen Tier-1-Cluster (vw = HA-Ziel, Nautobot bekommt Gratis-DR-Kopie). **Patroni + 3. Witness** nur, falls später Auto-Failover statt manuellem Promote gewünscht. - **Verwandt/Abgrenzung:** vw ist auch in **TP16** offen (CF-Access: `bypass`→WARP-geschützt) — **DB-HA ≠ Access**, getrennt behandeln. Reziprokes 2-Site-Muster analog **TP16**/**TP18**. - Abh.: **TP20** (Tier-1 Postgres muss stehen), **TP10** (WG-Transport für Phase-2), **TP18** (Backup-Schirm). Kein Blocker für TP21. ### TP23 — DNS-Policy & Self-Service-Ausnahmen ▸ ⏳ **STUFE 1 DURCH, STUFE 2 VORBEREITET (2026-08-18)** - ✅ **Stufe 1 — DoH auf dem Core scharf** (`routeros/tp23-stufe1-doh-core.rsc`), schliesst zugleich **TP21.1 TODO 1**. `use-doh-server=https://px35ynlol3.cloudflare-gateway.com/dns-query`, **`verify-doh-cert=yes`**. `servers=1.1.1.1` bleibt als Bootstrap fuer den DoH-Hostnamen stehen. - 🔑 **Die alte Begruendung „core hat kein CA-Bundle, verify also unmoeglich" war zu pessimistisch.** Es braucht kein Bundle, sondern **genau einen Root**: die Kette ist `Leaf → GTS WE1 → GTS Root R4`, importiert wurde nur **R4** (~1 KB, gueltig bis 2036) — bei **2,8 MB freiem Flash** ist das der Unterschied zwischen geht und geht nicht. Fingerprint lokal und am Geraet gegengeprueft (`349dfa40…3c7d`). - 📌 Der Zertifikatsimport steht bewusst **nicht** im GC-Template: er braucht die Datei am Geraet und ist einmaliger Bootstrap, kein Sollzustand. Im Template steht nur die `/ip dns set`-Zeile. - ⚠️ **Der Deploy meldete FAILURE, obwohl alles sass.** `/certificate import` gibt `failed: 0` aus, und der Job scannt den Geraete-Output stumpf nach dem Wort. Wieder ein Beleg fuer die TP22-Regel: **Job-Status ist kein Wirksamkeitsnachweis**, nur die Gegenpruefung am Geraet zaehlt. - ⏳ **Stufe 2 — AdGuard eingerichtet, aber bewusst NICHT scharf geschaltet** (User-Vorgabe 2026-08-18). `adguard_bf1` (`10.40.20.16`) macht bereits DoH zum selben CF-Gateway. Ergaenzt wurden: conditional upstreams **`[/bf.lan/]10.40.20.1`** und **`[/40.10.in-addr.arpa/]10.40.20.1`** (ohne die zweite Zeile wuerden interne Reverse-Lookups zu Cloudflare abfliessen), sechs **CIDR-Client-Gruppen** (ein VLAN = eine Gruppe) und die permanente Ausnahmegruppe **`dns-bypass-exempt`** (aktuell `10.40.10.183`). Abnahme per `dig`: `core.bf.lan` → `10.40.99.1`, `nas.bf.lan` → `10.40.20.10`, extern ueber DoH. Backup `AdGuardHome.yaml.bak-tp23-20260817`. - **Kein DHCP-Scope wurde angefasst** — alle sieben liefern weiter `10.40.X.1` aus. Das Scharfschalten ist damit spaeter ein reiner DHCP-Change; die passende Firewall-Zeile (`TP5-E2: LAN->AGH dns (Vorrat)`) steht bereits, damit dabei die scharfe Firewall nicht angefasst werden muss. - ⚠️ **AGH schreibt die YAML beim Start neu** (eigene Schluesselreihenfolge, Kommentare weg, `time_zone: Local` → `UTC`). Wer die Datei patcht, muss danach am **laufenden** Stand pruefen, nicht am eigenen Entwurf. - 🔜 **Offen bleiben Stufe 3–6** (zweite AGH-Instanz, per-Lease Option 6, HA-Buttons, und zuletzt die Bypass-Sperre). **Ausdruecklich keine HA/zweite Instanz** (User 2026-08-18). - **Auslöser:** sobald gefiltertes DNS scharf ist, gehen einzelne Seiten/Dienste kaputt. Es braucht **Ausnahmen ohne Admin-Eingriff** — per User/Client/Gruppe/global, temporär oder permanent, mit Oberfläche. **Bedarf ist belegt, nicht vermutet:** der bisherige Workaround war „Client von Hand auf `1.1.1.1` stellen", regelmäßig (User 2026-08-14). - 🔴 **Zentrale Reihenfolge-Regel: genau dieser Workaround IST der DNS-Bypass, den TP5 schließen will → erst der Ersatz, dann die Sperre.** Ohne funktionierende Ausnahme-Oberfläche verliert u.a. der Entwicklungsrechner samt Agenten-Toolchain seinen Ausweg — und DNS-Blocks äußern sich dort nicht als klare Meldung, sondern als diffus kaputte Build-Umgebung. - **Zwei Befunde, die die Architektur bestimmen:** 1. **DoH ist nicht das Problem.** Clients sprechen plain mit dem lokalen Resolver, der macht DoH nach oben — die empfohlene Auflösung des DoH/Split-Horizon-Konflikts, `bf.lan` bleibt heil. Was Seiten blockiert, ist die **Policy**. ➡️ **Nie einen „DoH aus"-Schalter bauen**, sondern Policy-Ausnahmen. 2. **Identität existiert nur dort, wo die Client-IP sichtbar ist.** Router-DoH aggregiert alle Clients hinter *einer* Quelle — CF sieht nur den Core. Per-User-Identität *bei CF* verlangt einen **Agent** (WARP; bei NextDNS/ControlD deren CLI) → auf Shelly/Sonos/TV unmöglich. **RouterOS kann keine per-Client-Ausnahme** (keine DNS-Views; `/ip dns static` wirkt domain-weit — verifiziert). ➡️ Ein lokaler Resolver mit Client-Policy ist unvermeidbar. - ✅ **Architektur-Entscheid: Filter zentral bei CF, Identität + Ausnahmen lokal.** Die **Filterliste bleibt vollständig bei Cloudflare** (Core via DoH, unterwegs via WARP); lokal wird **nie eine Filterliste vorgehalten, nur die Diffs**. Vorteile: kein RAM-Thema auf dem Core (eine Adlist kostet ~1,9 KB/Domain, 50k ≈ 95 MB — Konkurrenz mit Conntrack/DHCP/WG), **eine** Policy-Quelle statt zweier, gleiche Regelbasis zuhause wie unterwegs. - ✅ **Resolver-Wahl: AdGuard Home** (läuft bereits, `10.40.20.16`). Vergleich gegen die realen Anforderungen: - **Pi-hole disqualifiziert:** **spricht kein DoH** → bräuchte cloudflared/unbound als Sidecar (vierte QUIC-Komponente neben den drei TP16-Connectoren). Dazu belegtes Bruchrisiko **v5→v6** (FTL/API/Web neu, Docker-Env-Variablen tot). - **AGHs „keine Gruppen"-Schwäche verschwindet hier**, weil Clients als **CIDR** eintragbar sind → `10.40.30.0/24` = die IoT-Gruppe. **Die VLAN-Segmentierung ist bereits die Policy-Grenze.** Dazu natives DoH, per-Device-ID auch bei wechselnder IP, „Unblock for this client", API + HA-Integration. - **Technitium** = ernsthafte Alternative (autoritativer DNS + DHCP + Apps, `networkGroupMap`); seine IP/Subnet-Bindung trifft uns kaum, weil die IPs per Reservierung faktisch statisch sind. **Neubewertung legitim** (die TP4-Ablehnung galt einer anderen Frage) — sinnvoller Anlass wäre, DNS **und** DHCP zusammenzuführen. Eigener TP, nicht dieser. - **Verworfen:** eigene Self-Service-UI bauen · per-Device-DoH via NextDNS/ControlD (Agent-Zwang, bricht `bf.lan`) · Umbrella ($30–45/User/Jahr) · Cloudflare verlassen (wirft TP16/TP16.1 weg) · Adlist auf dem Core. - **Zuweisung ist nativ möglich:** `/ip/dhcp-server/lease` hat die Property **`dhcp-option`** (verifiziert) → **Option 6 pro Lease**, bei 54 Reservierungen ein Konfigurationsschritt. *(Nebenfund: Leases haben `address-lists` → automatische Aufnahme in eine Firewall-Liste, direkt nützlich für die TP5-JIT-Gruppe.)* - ✅ **WARP im LAN abschalten — Mechanismus: Cloudflare „Managed Networks".** Der Client sucht bei jedem Netzwechsel einen **selbst gehosteten TLS-Endpunkt**, prüft dessen SHA-256-Fingerprint und zieht ein Device-Profil, das WARP **deaktiviert**. Beacon auf **NAS/pve**, nicht auf den Core (`certs=0`). Beseitigt die ICMP-Falle vom 2026-08-13 (`ref_warp_local_icmp_trap`) an der Wurzel. - ✅ **Kollision aufgelöst (2026-08-14):** die frühere Sorge war, dass TP16-Schritt 5 `vw` auf WARP-geschützt hebt und damit „WARP zuhause aus" bricht. **Der User-Constraint aus TP16.2 streicht genau das** — `vw` bleibt bypass und verlangt nie Device-Identity. **Damit steht der Managed-Networks-Weg frei.** Rest-Risiko nur für Dienste, die künftig doch Device-Identity verlangen sollten → dann Access-Policy zusätzlich auf die Heim-IP (`bf4-home-ip` existiert bereits). - ✅ **Kein Verlust beim Fremdnetz-Zugriff:** FM/DW laufen über den WG-Hub (TP10), nicht über WARP. Managed Networks schaltet nur *im* Heimnetz ab. - ⚠️ Free-Plan-Verfügbarkeit des Features **nicht belegt** → im Dashboard gegenprüfen. Holzhammer-Alternative (WARP-Endpunkte per Firewall sperren) **nicht empfohlen**: bricht still, Client probiert Transport-Fallbacks, trifft auch Gäste. - **Umsetzung in Stufen — Sperre zuletzt:** 1. **DoH auf dem Core scharf** → schließt TP21.1-TODO 1 (heute plain `1.1.1.1`); CA-Bundle nötig. 2. **WARP-Managed-Network** (Beacon auf NAS/pve) → WARP zuhause aus. 3. AGH in den Pfad, **zweite Instanz** + Config-Sync, beide per DHCP als DNS 1 + 2. 4. **Client-Gruppen per CIDR** (ein VLAN = eine Gruppe); per-Lease Option 6 nur für Abweichler. 5. HA-Buttons für temporäre Freigaben + JIT (AGH-API, RouterOS-REST, CF-API), RouterOS-`scheduler` als Backstop, damit Ablauf auch ohne HA greift. 6. 🔴 **Erst jetzt (in TP5): DNS-Bypass sperren** — Vorbedingung: Freigabe über HA funktioniert **nachweislich**, und die permanente Ausnahmegruppe **`dns-bypass-exempt`** (Entwicklungsrechner + Build-/Agent-Tooling) steht. Dann: nur Resolver dürfen 53/853 nach außen (schließt Geräte, die eigene Resolver hardcoden — Smart-TV mit `8.8.8.8` ist der Klassiker). - **Grenzen, offen benannt:** **ein Resolver im Datenpfad** ist unvermeidbar (zwei Instanzen federn ab, ⚠️ **AGH hat kein natives HA → Config-Sync ist Betriebsaufwand**, sonst gilt nach Failover eine andere Policy) · **keine Blockseite bei HTTPS** (gilt für jede DNS-Filterlösung, auch Umbrella) · **CF-Log-Retention 24 h** im Free-Plan — laut User ausreichend, weil Ausnahmen JIT entstehen und ältere Fälle reproduziert werden. - ⚠️ **802.1X löst die IoT-Identität NICHT:** Consumer-IoT (Shelly, Sonos) hat keinen 802.1X-Supplicant; der Standardweg ist **MAB** = wieder MAC-basiert → **kein Identitätsgewinn gegenüber der DHCP-Reservierung**. **TP8 bleibt richtig, aber als Sicherheitsthema** (dynamische VLAN-Zuweisung, kein MAC-Spoofing bei Managed-Geräten), nicht als DNS-Identitätsquelle. - **Abh.:** **TP21.1 TODO 1** (DoH auf core), **TP5** (Firewall/Bypass-Sperre — Reihenfolge s.o.), **TP16 Schritt 5** (Access-Kollision), **TP16.1** (falls WARP zuhause bleiben soll), **TP8** (nur Sicherheit). **Kein Blocker für TP5 → TP6**, aber TP5 darf die Bypass-Sperre nicht vorziehen. ### TP24 — Unterbrechungsfreie Stromversorgung (DC-USV, 48V-Bus) ▸ 🔜 KONZEPT — **aus TP15 herausgelöst (User-Entscheid 2026-08-16)** — `docs/hw-refresh-requirements.md §9` - **Warum ein eigener TP:** Die USV hing bisher als Unterpunkt in TP15 (HW-Refresh Switching/Router) mit. TP15s Kernauftrag — CRS326-Beschaffung, Bring-up, Core-Tausch — ist seit 2026-08-08 **durch**; die Stromversorgung ist als einziger Rest übrig geblieben und hat mit Switching sachlich nichts zu tun. Sie ist ein **eigenständiges Infrastruktur-Thema mit eigener Einkaufs-, Verkabelungs- und Entscheidungslogik** (Elektrik, Batterie, Standort) und blockiert nichts auf dem kritischen Pfad. Darum eigener TP. - **Was es ist (Begriffsklärung):** eine **Pufferbatterie für die Netz-/Infrastruktur-Hardware** — **keine** klassische AC-USV mit 230-V-Steckdosen. Ein 48-V-Gleichspannungsbus versorgt die Geräte **direkt an ihrem DC-Eingang**; die Batterie hängt am selben Bus und übernimmt bei Netzausfall ohne Umschaltlücke. Der Umweg AC→DC→AC→DC (und damit dessen Dauerverlust) entfällt. - **Zielbild (Aufbau, unverändert gültig aus der TP15-Recherche):** | Teil | Typ | Preis | Wirkungsgrad | |---|---|---|---| | Netzteil | MeanWell **LRS-150-48** (150 W, 48 V) | ~€30 | ~88 % | | DC-USV-Modul | MeanWell **DDR-120-48** (120 W) | ~€80 | ~95 % (pass-through) | | Batterie | **LiFePO4 12,8 V / 20 Ah** (256 Wh) | ~€50 | — | | DC-DC 12 V | MeanWell SD-100A-12 (100 W, für NAS/pve) | ~€30 | ~85 % | | **Summe** | | **~€190** | | `230 V AC → LRS-150-48 → 48-V-Bus →` Switches direkt · `→ DC-DC 12 V →` DS923/pve · `→ DDR-120-48 →` LiFePO4. - **Warum 48 V:** PoE-Technik arbeitet nativ mit 44–57 V (kein Wandler nötig), höhere Spannung = kleinere Ströme = weniger Leitungsverlust, und 48 V ist der Telecom-/USV-Standard. - **Laufzeit (256 Wh):** ~2,5 h bei 100 W reiner DC-Last · **~5,5 h wenn nur Switch + PoE (45 W)** · ~2 h wenn ein Inverter für den Mac mini mithängt. - **Effizienz-Argument (der eigentliche Grund für DC statt AC):** eine AC-USV verheizt bei 100 W Dauerlast ~25–40 W (≈ €66–105/Jahr), die DC-Variante ~5–12 W (≈ €13–32/Jahr) — bei praktisch gleicher Anschaffung (~€190 vs. €150–250). Der Mehrpreis amortisiert sich über den Dauerbetrieb. - ✅ **DC-Eingang vorhanden (geprüft):** `crs326-core` + `crs326-branch` (12–57 V, DC-Jack) · ap1/ap2 hAP ax² (12–57 V, alternativ PoE-in). ⚠️ **Adapter/Sonderfall:** DS923+ (externes 12 V/7 A, 4-Pin Mini-Fit JR) · pve/N100 (12 V Hohlstecker) · **Mac mini hat gar keinen DC-Eingang** (eingebautes Netzteil → nur über Inverter). - **Offene Entscheidungen (aus TP15 mitgenommen, unverändert offen):** 1. **Mac mini auf USV?** Braucht einen Inverter (~15–20 % Verlust + Komplexität). Vorfrage: läuft er überhaupt 24/7? Wenn nein, reicht ein Graceful-Shutdown-Script auf USV-Warnung. 2. **Standort/Verkabelung:** Der Bus soll laut Skizze im **Arbeitszimmer/Technik OG** sitzen — der L3-Core steht aber in **Technik UG**. Entweder zweiter Zweig nach unten oder Bus dorthin, wo der Core steht. **Diese Frage ist durch den Core-Umzug neu zu stellen** (die Skizze stammt aus der Zeit, als oben der Verteiler geplant war). 3. **Arris-Kabelmodem:** vorentschieden auf **Grid** (muss ohnehin am Netz bleiben, DC-Zweig nach unten wäre Aufwand für ~1–2 W). 4. **Batteriegröße:** 20 Ah als Startwert; 50 Ah wenn die gepufferte Last über Switch+AP hinaus wächst. 5. **Monitoring/Shutdown:** wie meldet die USV einen Netzausfall an NAS/pve (Signalkontakt vs. nichts)? Ohne das gibt es kein sauberes Herunterfahren, nur Durchhalten bis die Batterie leer ist. - **Nutzen konkret:** bei Stromausfall bleiben Core-Switch, Branch-Switch und beide APs online → **Netz, WLAN und der WG-Hub überleben** (der WAN-Uplink nur, solange auch der Arris Strom hat, s. Entscheidung 3). Für NAS/pve zählt vor allem das **kontrollierte Herunterfahren** statt des harten Abschaltens. - **Abh.:** keine harten. **TP15 ✅** (die zu versorgende Hardware steht und hat DC-Eingänge). Verwandt: **TP18** (Garage-Nodes brauchen je Site eine Stromversorgung), **TP11** (USV-Zustand ins Monitoring). **Kein Blocker für TP5/TP6.** - **Historie:** war bis 2026-08-16 Unterpunkt von TP15 („🔋 DC-USV: MeanWell LRS-150-48 + DDR-120-48 + LiFePO4 20Ah (~€190), 48V-Bus; CRS326 DC-input passt"). Vollständige Recherche inkl. Schaltbild, Effizienzvergleich und Gerätetabelle: `docs/hw-refresh-requirements.md §9` (+ §10 D/E/F für die offenen Fragen). ### TP25 — WLAN-Stabilisierung ▸ 🟢 **KERN ERLEDIGT (2026-08-22): Dead Spot Terrasse repariert** (43 % → 9 % Verlust, 20,4 s → 1,0 s). Offen nur noch **Fund F** (5:05-Takt IoT) und die Entscheidung **5 GHz auf 20 MHz**. Nicht mehr kritischer Pfad — Sammel-TP für Christophs Beobachtungen 1–6 > 📚 **Kondensiert am 2026-08-23 (Doku-Session, Punkt F).** Dieser Abschnitt war mit 394 Zeilen > 18 % der Datei. Die **Langfassung steht vollständig und unverändert** im Archiv: > [`teilprojekte-archiv.md` → TP25 (Langfassung)](teilprojekte-archiv.md#tp25-lang) — Messchronik (A)–(G), > Funde A–E im Volltext, die beantworteten Fragen (Beobachtung 5, ch149-Herkunft, `2ghz-g`, > Deckenmontage), Umsetzungsreihenfolge mit allen Deploy-Gotchas. Hier steht: **Stand, Offenes, > Merkregeln.** Wer an TP25 weiterarbeitet, kommt mit diesem Abschnitt aus; wer wissen will > *warum* etwas so entschieden wurde, liest die Langfassung. **Stand 2026-08-22, 23:30 — die Terrasse ist repariert.** Erster Lauf mit beiden Ping-Strecken ([`tp25-runde-20260822-2330-auswertung.md`](tp25-runde-20260822-2330-auswertung.md)): **43 % Verlust / 20,4 s längste Lücke (08-21) → 9 % / 1,0 s** bei gleichem Gerät und gleicher Rolle. Wirksam war das **Anheben von ap2 auf 2,5 m**; 1,0 s liegt unter der Hörbarkeitsschwelle im Call. Der Dead Spot, der TP25 seit dem 08-20 getragen hat, ist damit weg. 🔎 **Kernbefund, der bleibt: das Netz ist gut, die Redundanz ist es nicht.** Die frei roamende Referenz hat in **17 von 21** Raumabschnitten 0 % Verlust; der Gegen-AP liefert Schlafzimmer −84,6/38 %, Bad −82,3/24 %, Küche −82,0/23 %, Terrasse −78,7/19 %. **Fällt ein AP aus, ist die halbe Wohnung „verbunden, aber tot".** ⇒ Ein **dritter AP ist nach Christophs eigener Randbedingung derzeit NICHT begründet** — er kaufte Redundanz, keine Abdeckung. Das ist eine andere Frage und Christophs. **Offen — nur noch zwei Punkte:** 1. 🟡 **Fund F — IoT-Clients trennen exakt alle ~5:05 bei gutem Signal** (−59 dBm, vier Messpaare, auf 3 s reproduzierbar → **ein Timer, kein Funk**). Muss **am Manager** nachgemessen werden, die AP-Tabellen sind unter CAPsMAN leer. Kandidaten und der Test, der sie trennt: (a) periodischer VAP-Re-Apply (Fund D war die Ursache → prüfen, ob es nach dem Fix weg ist); (b) DHCP-`lease-time` der beiden MACs (`38:A5:C9:C0:73:1E`, `38:A5:C9:BC:33:31`) gegen die Periode legen; (c) das Gerät selbst mit 5-min-Duty-Cycle → dann bleibt es unverändert. 🚫 **Nicht die alte Power-Save-Merkregel wiederbeleben** — die ist am 2026-08-13 als Fehldiagnose zurückgezogen (`ref_wifi_powersave_multicast`). 2. ⚖️ **Entscheidung 5 GHz auf 20 MHz** (statt heute 20/40): **+3 dB Link-Budget**, für einen 1,2-Mbit-Call an Durchsatz irrelevant. Ein-Wort-Change im Template. Steht seit dem Terrassen-Fix ohne Dringlichkeit da — **Christophs Entscheidung**, keine Empfehlung mehr. ⚠️ **2,4 GHz NICHT vorschnell drosseln** — dort hängen ~20 IoT-Geräte. **Fund E (`signal-range`-Boden am Manager) — abgestuft, NICHT umsetzen.** Der Sticky-Client vom 08-20 reproduzierte sich am 08-22 nicht (Treppe: sauberer Wechsel ap2→ap1, 0 % über 57 s). Und auf der Terrasse würde ein Boden **schaden**, weil es dort keinen besseren AP gibt, auf den gesteuert werden könnte. ⇒ **Erst wieder aufgreifen, wenn ein Sticky-Fall erneut gemessen ist.** *(Der Defekt ist nicht gegenstandslos, nur unbelegt: Fund B/C wurden am 08-20 mit ap1 auf `ether15` gemessen — also in genau der Stellung, in der ap1 heute wieder hängt. Er ist platzierungsunabhängig.)* **✅ Erledigte Funde — Ergebnis und Merkregel (Volltext im Archiv):** | Fund | Ergebnis | Merkregel, die bleibt | |---|---|---| | **A** 2,4 GHz fuhr 40 MHz statt der profilierten 20 | ✅ 08-17: Inline-`channel.*` auf `wifi1/wifi2` geleert → `2412`/`2462` @ 20 MHz | **Inline-Overrides gewinnen gegen das verlinkte Profil** — die SoT war die ganze Zeit richtig, das Gerät hat sie nicht befolgt | | **B** ap2 sendete 5 GHz mit **9 statt 18 dBm** | ✅ 08-17: `5220/ax/Ce/I`, **18 dBm** | Der Fix ist gemessen, **der Mechanismus nicht** — beide ersten Erklärungen (ETSI-Band C, „80 MHz kostet generell") sind widerlegt. Resthypothese + diskriminierender Test (`ap2 auf 5180/Ceee`) stehen im Archiv und gehören **vor** einen Hardwarekauf | | **C** 80 MHz kostete Randabdeckung | ✅ 08-17: `ch-5g` auf `20/40mhz`; ap1 `5180/Ce`, ap2 `5220/Ce`, überlappungsfrei | Unter ETSI gibt es im Indoor-Band **nur einen** 80-MHz-Block — zwei APs können dort nicht beide 80 MHz fahren. Genau deshalb war ap2 je auf 5745 gelandet | | **D** `w2-iot` trug einen Channel-Override auf einem **Slave**-VAP | ✅ 08-17: Overrides auf beiden APs entfernt, `w2-iot` seither `BR` | `band` ist eine Eigenschaft des **Radios**, nicht eines Slave-VAPs. War der Mechanismus hinter „alle SSIDs da, `-iot` beharrlich nicht" | | **Drift-Lücke** — genau diese Overrides lagen außerhalb jeder ComplianceRule | ✅ 08-18 mit dem TP28-GC-Umbau: `wifi-*`-Features hängen am Core, drei neue Rules; ein CAP hat keine Inline-Overrides mehr | **„Compliant" heißt nur: die abgedeckten Sektionen sind sauber.** Fund A und D blieben seit 08-08 unentdeckt, während die Flotte durchgehend compliant meldete | 🔴 **Deploy-Gotchas aus derselben Arbeit (kosten sonst zwei Deploys, Volltext im Archiv):** `/interface/wifi/set !channel` **löscht die Inline-Sub-Properties NICHT** — es wirft nicht, es tut nichts; richtig ist einzeln `!channel.width !channel.band !channel.skip-dfs-channels`. Und bei Kanalarbeit **Breite VOR Frequenz** ändern, sonst erzeugt man auf dem Weg eine Co-Channel-Kollision. ⚠️ `steering=`/Channel-Änderungen **re-applien alle VAPs und werfen jeden Client kurz raus** — nicht während eines Calls deployen, `/system backup` je AP vorher. 🔬 **Messwerkzeug — drei Regeln, jede aus einem Fehlbefund geboren:** - 🔴 **Die `cap-wifiN`-Nummern sind NICHT stabil.** Der Manager vergibt sie in der Reihenfolge, in der sich die CAPs anmelden — nach dem ap1-Rückbau sind `cap-wifi1/2` = **ap2** und `cap-wifi3/4` = **ap1**, umgekehrt zur früher fest verdrahteten Tabelle. ⇒ **Die Zuordnung gehört zum Messlauf**, nicht zur Auswertungszeit: [`tp25-walk-messung.sh`](tp25-walk-messung.sh) friert sie als `ap-map.txt` ein, die Auswertung lässt die Namen sonst roh — **unbeschriftet ist ehrlicher als falsch beschriftet.** **Läufe vor dem 2026-08-22 sind nicht rekonstruierbar**; wer ihre AP-Namen zitiert, prüft sie an der Physik (der AP im Raum liefert dort das stärkste Signal). - 🔴 **Ein vom Pin abgewiesener Verbindungsversuch ist in Ping-Daten nicht von einem Funkloch zu unterscheiden** — und der Manager protokolliert ihn auf `info`-Ebene **gar nicht**. Android quittiert die Abweisung mit „Verbindung fehlgeschlagen" und **wählt das Netz ab**; danach misst der Rest des Rundgangs Stille. Die Klick-Konsole schlägt deshalb Alarm, sobald das gepinnte Gerät nirgends hängt, und schreibt nach 45 s `UNERREICHBAR=apX` — denn „der Gegen-AP trägt hier nicht" **ist das Messergebnis**. - 📐 **Eine Runde, zwei Messpunkte** (Christophs Aufbau 2026-08-22): das frei roamende iPhone zeigt, was ein normaler Client wählt — interessant ist der **andere**. Das S22 wird per `access-list` auf den Gegen-AP gezwungen ([`tp25-pin-s22.sh`](tp25-pin-s22.sh)). Gute Referenz + schlechte Sonde = die Abdeckung steht, die Rückfallebene nicht. Memory `ref_gegen_ap_messung`. - ▶️ **Start ohne Werkzeugkette: `bash docs/tp25-runde.sh [name]`** — legt den Lauf unter `docs/messdaten/tp25-runde-/` an, friert die AP-Karte ein, startet Konsole (Port 3031) und Messung, sagt die **vom Interface gelesene** Adresse fürs Telefon an und löst beim Beenden den Pin. Auswertung: `tp25-gehweg-auswertung.py --dir …`. - ℹ️ **Und das alles passiert TROTZ aktivem 802.11k/v und FT** (`st-main` mit `rrm=yes`/`wnm=yes`, `ft-over-ds=yes`, live geprüft). Die Merkregel `ref_ft_is_not_roaming` („11k/v fehlen") ist **historisch**. Bei −48…−55 dBm kostet eine Übergabe 0–2,6 s, meist unter einer halben Sekunde — **nicht die Übergabe ist teuer, sondern die schwache Zone.** **User-Randbedingung (2026-08-17, wörtlich): „ich weigere mich einen anderen access point zu kaufen solange ich nicht das gefühl habe, wir haben alles aus dem ap rausgeholt."** Das ist die **Abnahmebedingung dieses TPs** — keine Hardware-Empfehlung, bevor die Parameter stimmen. Der Boden ist gelegt (beide APs 18 dBm, überlappungsfrei, 20 MHz auf 2,4 GHz, ap2 auf 2,5 m); was übrig bleibt, ist die Redundanzfrage oben. - **Warum eigener TP:** Christoph hat am 2026-08-16/17 sechs konkrete Beobachtungen gemeldet und ausdrücklich **einen** TP dafür verlangt; sie hängen alle an derselben Ursache-Klasse (Funkparameter, die nicht nach Manual gesetzt sind). **TP25 übernimmt den offenen Rest von TP3.3** (Re-Walk, Dead-Spot-Kartierung — mit der Raumkarte vom 08-22 faktisch geleistet). TP3.2/TP3.3 stehen als Historie. - **Stand bei Sitzungsende 2026-08-22:** Pin gelöst, Automatik aus, `crs326-core` unverändert und **transaktionsfrei** — die `access-list` steht unter keiner ComplianceRule, es gab nichts zu committen. *(Seit 2026-08-23 gibt es die Rule `wifi-access-list`, s. TP22-Nachtrag — Fund E wäre ab jetzt transaktionsfähig.)* - 📋 **Übergabe:** [`handoff-tp25-session-20260821.md`](handoff-tp25-session-20260821.md) · Messungen: [`tp25-wlan-roaming-messung-20260820.md`](tp25-wlan-roaming-messung-20260820.md), [`tp25-runde-20260822-2330-auswertung.md`](tp25-runde-20260822-2330-auswertung.md) - **Abh.:** TP22 ✅ (GC-Deploy-Pipeline). Verwandt **TP3.2** (`docs/wifi-p750w-coverage-and-map.md`), **TP29** (nutzt dieselbe Datenquelle als Sensor). **Kein Blocker für irgendetwas.** ### TP29 — Anwesenheitserkennung fürs Energiesparen ▸ 💡 **IDEE, noch nicht auf dem kritischen Pfad** (angelegt 2026-08-21) > **User-Formulierung (2026-08-21):** „Personen im Haus orten mit BT (Shellys), WiFi und Radar. So > kommen wir dem Ziel der Energieersparnis ohne Komfortverlust groß näher." - **Ziel:** raumgenaue Anwesenheit als Eingangssignal für Heizung und Licht — sparen, **ohne** den typischen Komfortverlust („erst kalt, dann warm, wenn jemand da ist"). - 🔎 **Der Entwurfsgedanke sind die komplementären Schwächen der drei Quellen** — keine trägt allein: | Quelle | erkennt | erkennt **nicht** | |---|---|---| | **BLE über die Shellys** | grobe Zonen, billig, überall vorhanden | Menschen ohne getragenes Gerät; Raumgrenzen unscharf | | **WLAN** (Registration-Table am Manager: Gerät, AP, Signal) | wer mit Telefon da ist, inkl. AP-Zuordnung | Menschen ohne Telefon; Raum nur so genau wie die AP-Abdeckung | | **mmWave-Radar** | auch die **stillsitzende Person ohne Gerät** | braucht einen Sensor **je Raum** | - ✅ **Was schon steht:** Shellys vollständig auf VLAN30 (TP17 ✅), HA produktiv — und mit [`docs/tp6-monitor-core.sh`](tp6-monitor-core.sh) existiert seit TP25 bereits ein Sammler, der die WLAN-Präsenzdaten am Manager mitschreibt (Gerät → AP → Signal, im Sekundentakt). - ❓ **Offene Fragen für die erste Session:** Datenpfad ins HA (MQTT oder REST?) · Firewall-Regeln für neue Sensorik (**TP5 ist deny-by-default**, jeder neue Dienst über eine VLAN-Grenze braucht eine Regel) · Aufbewahrung und Privatsphäre der Ortsdaten · ob Radar-Sensoren auf `dirtyvader-iot` laufen oder eigene Segmentierung brauchen. - **Abgrenzung:** TP25 **misst** den Funk, TP29 **nutzt** ihn als Sensor — dieselbe Datenquelle, anderes Ziel. Die Raumkarten aus TP25 sind für TP29 direkt verwertbar: sie sagen, wie genau die WLAN-Quelle einen Raum überhaupt auflösen kann. - **Abh.:** keine harten. Profitiert von TP25 (Abdeckung/AP-Zuordnung) und TP11 (Monitoring), wenn es dahin kommt. **Kein Blocker für irgendetwas.** --- ## Abgeschlossene Teilprojekte ▸ [`teilprojekte-archiv.md`](teilprojekte-archiv.md) **34 abgeschlossene TPs** liegen dort im Volltext, unverändert und mit eigenem Inhaltsverzeichnis. 📊 **Für einen Statusbaum reicht diese Datei:** die Tabelle unten nennt **jedes** archivierte TP, und die Zeile „✅ Durch (Fundament)" weiter unten führt sie noch einmal mit Abschlussdatum. Das Archiv muss dafür **nicht** geöffnet werden — es trägt die Begründungen, nicht den Status. Kurzorientierung, wo was zu finden ist: | Thema | TPs im Archiv | |---|---| | **Fundament / Fabric** | [TP1](teilprojekte-archiv.md#tp1) ALLNET-Core *(Gerät ausgebaut)* · [TP2](teilprojekte-archiv.md#tp2)/[TP2.1](teilprojekte-archiv.md#tp2-1) Omada *(ausgebaut)* · [TP15](teilprojekte-archiv.md#tp15) HW-Refresh CRS326 · [TP21.1](teilprojekte-archiv.md#tp21-1) Core-Cutover-Recovery · [TP4](teilprojekte-archiv.md#tp4) Router-Cutover *(Rolle seit 08-08 auf dem Core)* | | **WLAN** | [TP3](teilprojekte-archiv.md#tp3) *(historisch)* · [TP3.1](teilprojekte-archiv.md#tp3-1) · [TP3.2](teilprojekte-archiv.md#tp3-2) · [TP3.3](teilprojekte-archiv.md#tp3-3) *(in TP25 aufgegangen)* · [TP28](teilprojekte-archiv.md#tp28) CAPsMAN auf dem Core · [TP25-Langfassung](teilprojekte-archiv.md#tp25-lang) | | **Firewall / QoS** | [TP5](teilprojekte-archiv.md#tp5) deny-by-default · [TP26](teilprojekte-archiv.md#tp26) `ip-firewall-filter` unter Drift-Kontrolle · [TP6](teilprojekte-archiv.md#tp6) CAKE *(geschlossen statt gebaut)* · [TP6.1](teilprojekte-archiv.md#tp6-1) Upload-Priorisierung | | **Discovery / Media** | [TP7](teilprojekte-archiv.md#tp7) mDNS · [TP7.1](teilprojekte-archiv.md#tp7-1) SSDP-Relay · [TP7.2](teilprojekte-archiv.md#tp7-2) HA↔Sonos | | **Hosts / Migration** | [TP14](teilprojekte-archiv.md#tp14) (+[.1](teilprojekte-archiv.md#tp14-1)/[.2](teilprojekte-archiv.md#tp14-2)/[.2a](teilprojekte-archiv.md#tp14-2a)/[.3](teilprojekte-archiv.md#tp14-3)/[.5](teilprojekte-archiv.md#tp14-5)) VLAN20-Cutover · [TP17](teilprojekte-archiv.md#tp17) Shelly→VLAN30 · [TP19](teilprojekte-archiv.md#tp19) VLAN1-Retirement | | **Control-Plane** | [TP20](teilprojekte-archiv.md#tp20) Platform-Postgres · [TP21](teilprojekte-archiv.md#tp21) Nautobot GC · [TP22](teilprojekte-archiv.md#tp22) Adoption + Compliance-Push · [TP27](teilprojekte-archiv.md#tp27) RouterBOOT 7.24 · [TP-R](teilprojekte-archiv.md#tp-r) Capabilities-Sweep | | **Zugang** | [TP10](teilprojekte-archiv.md#tp10) Multi-Site-VPN *(offen nur der DDNS-Updater, s. Follow-ups)* · [TP16.1](teilprojekte-archiv.md#tp16-1) natives CF-Mesh | | **Verworfen** | [TP9](teilprojekte-archiv.md#tp9) Gateway-HA (User-Entscheid 2026-08-08) | ## Reihenfolge / Abhängigkeiten ### 🎯 Kritischer Pfad (Stand 2026-08-23) — **LEER** ``` TP5 E1 ✅ ─► E2 ✅ ─► E2-Nachtrag ✅ ─► E3 Drop ✅ ─► E4 input+MGMT ✅ ─► E5 MAIN→IOT ✅ ─► TP6 ✅ GESCHLOSSEN 🎯 DER KRITISCHE PFAD IST LEER (2026-08-23). Das Projekt ist in seinem Kern fertig: deny-by-default steht, Golden Config steht, WLAN steht, VLAN1 ist weg, und TP6 ist beantwortet statt offengelassen. Was jetzt kommt, entscheidet Christoph — nichts blockiert mehr etwas. ``` > ➡️ **Update 2026-08-22 (Sitzungsende):** TP25 hat den Pfad seit dem 08-20 blockiert und ist im > Kern **erledigt** — die Terrasse ist repariert, der Dead Spot weg, Fund E abgestuft. Damit ist > **TP6 wieder der einzige Punkt auf dem kritischen Pfad**, und seine Prämisse ist inzwischen > gemessen (`tp6-praemisse-messrunbook.md` §5): **formal Fall B** (+28…47 ms in der Senderichtung), > **aber durch sechs Lastphasen mit laufendem Videocall kein einziger Problem-Klick.** Die > nächste Sitzung entscheidet daher **bauen oder begründet schließen** — sie misst nicht neu. > Übergabe mit den Sitzungszuschnitten: [`handoff-20260822-naechste-schritte.md`](handoff-20260822-naechste-schritte.md). > 🟢 **Update 2026-08-23 (Endstand): TP6 ist beantwortet — und der kritische Pfad damit leer.** > Gebaut wurde, wie entschieden. Der erste Anlauf (`/queue tree parent=vlan100`) war wirkungslos, > **aber nicht aus dem zuerst notierten Grund**: nicht der Switch-Chip, sondern die > MikroTik-dokumentierte Regel, dass Interface-HTB bei hw-offloadetem out-interface nicht greift. > Ueber `parent=global` + Mangle-Mark **funktioniert CAKE einwandfrei** (zaehlt 6 MB, drosselt > 9,3 → 7,78 Mbit). Und genau deshalb ist das Ergebnis belastbar: **die Latenz unter Last bessert > sich trotzdem nicht — bei keiner Bandbreite, auch nicht bei 52 % der Linerate** (42,4 / 43,3 / > 44,0 / 44,6 ms). Der Puffer sitzt im **DOCSIS-Uplink**, nicht im Router. ⇒ **TP6 schliessen: > nicht mangels Nutzen, sondern weil das Werkzeug nicht an die Ursache reicht.** Details im > TP6-Abschnitt oben, Merkregeln in `ref_queue_htb_platzierung_docsis`. > 🔴 **Korrektur wenige Stunden spaeter (2026-08-23, TP6.1): die DOCSIS-Erklaerung oben ist FALSCH.** > Der Puffer sitzt nicht unabaenderlich im Uplink — er loest sich auf, sobald der Verkehr in > **getrennte Klassen** faellt: NAS-Bulk `priority=8` gegen interaktiv `priority=1` bringt dieselbe > Strecke unter derselben Saettigung von **40,8 auf 11,0 ms (−73 %)**. Der Fehler steckte in der > **Messmethode** — Last und Messung liefen vom selben Host, ein Shaper kann eine Queue nicht > priorisieren, in der nur eine Klasse liegt. ⇒ **TP6 bleibt geschlossen** (CAKE war das falsche > Werkzeug), **aber nicht aus dem dort notierten Grund.** Der Rest steht in **TP6.1** > ([Archiv](teilprojekte-archiv.md#tp6-1)) und in `ref_queue_htb_platzierung_docsis`. 📜 *Die folgende Fassung stammt vom 2026-08-18 und ist **erledigt** — die Praemisse ist am 08-20/21 gemessen, TP6 am 08-23 geschlossen. Bewusst erhalten, weil sie zeigt, warum nicht gebaut, sondern zuerst gemessen wurde:* **TP5 ist am 2026-08-18 abgeschlossen.** Damit steht rechnerisch nur noch **TP6** auf dem kritischen Pfad — 🟠 **aber dessen Prämisse ist offen**: eine Messung von 2026-06-16 (`docs/call-quality-diagnosis.md`) bescheinigt dem Netz bereits **A/A+** und hält CAKE für „marginal". Der nächste Schritt ist deshalb ein **Bufferbloat-Test gegen den heutigen Edge**, nicht der Bau einer Queue. Fällt er gut aus, ist der kritische Pfad **leer** und das Projekt in seinem Kern fertig — dann entscheidet Christoph, was das neue Ziel ist. Alles andere läuft nebenher und blockiert nichts. 1. ✅ **TP5 Etappe 1–4 — komplett durch** (2026-08-16 bis 2026-08-18). Details im TP5-Abschnitt oben. Die Wartezeit-Position, die hier bis 2026-08-17 als eigener Schritt stand, ist eingeloest: statt eines mehrtaegigen Fensters wurde der Nachtrag aus einem **dreieinhalbstuendigen** Fenster abgeleitet und der Drop mit Auto-Revert plus weiterlaufender Log-Regel abgesichert. Die Vorbedingung D2 (iPhone `.30.201`) ist **gegenstandslos**: das Geraet hing dort bewusst zum Anlernen eines IoT-Geraets (User 2026-08-17). Wer im IOT-SSID sitzt, ist im selben VLAN wie das Geraet und beruehrt die `forward`-Kette gar nicht; fuer Ad-hoc-Zugriffe aus MAIN gibt es jetzt die selbstverfallende Gruppe `jit-admin`. 2. ✅ **TP6 — QoS/CAKE ▸ GESCHLOSSEN 2026-08-23.** Gebaut, gemessen, wieder ausgebaut. CAKE ist auf diesem Geraet baubar (Global-HTB + Mangle) und wirkt technisch — verbessert die Latenz unter Last aber bei **keiner** Bandbreite, auch nicht bei 52 % der Linerate. Der Puffer sitzt im DOCSIS-Uplink, nicht im Router *(⚠️ **widerlegt von TP6.1 am selben Tag** — s. Korrektur oben)*. Queue und Template-Block sind entfernt, die ComplianceRule `queue` bleibt und bewacht den Abschnitt als leer. **Damit ist der kritische Pfad leer.** 💡 Aus dem Abschluss ist **TP6.1** entstanden (Saettigung vermeiden statt Bufferbloat bekaempfen) — Christophs Gedanke, den NAS-Sync zurueckzuhalten. ~~Steht als Vorschlag, nicht auf dem Pfad.~~ **✅ Am selben Tag gebaut und gemessen: 40,8 → 11,0 ms.** ~~Das eigentliche Projektziel; **keine offenen Blocker mehr**.~~ **Korrigiert 2026-08-19:** kein *Blocker*, aber eine offene **Prämisse** — der Satz oben und dieser Punkt widersprachen sich seit dem 18. Richtig ist: der nächste Schritt ist eine **Messung**, kein Bau. Runbook liegt bereit: `docs/tp6-praemisse-messrunbook.md`. Fällt sie A/A+ aus, wird TP6 **geschlossen statt gebaut** — dann ist der kritische Pfad leer und das Projekt in seinem Kern fertig. **Eine harte Reihenfolge-Regel dazwischen:** TP5 darf die **DNS-Bypass-Sperre erst schließen, wenn TP23s Ausnahme-Oberfläche steht** — der bisherige Workaround „Client von Hand auf `1.1.1.1`" *ist* genau dieser Bypass. Alles andere aus TP5 ist davon unabhängig und kann vorher laufen. ⚠️ **Und eine zweite, aus TP16.1/TP16.3:** der Drop braucht `cf-mesh` explizit — steht seit Etappe 2 als `TP5-E2: mesh->LAN` / `LAN->mesh` drin. Ohne diese zwei Zeilen sperrt Etappe 3 den Fernzugang aus, also genau den Weg, über den man den Fehler zurücknehmen wollte. ### Follow-ups nebenher (blockieren nichts) - **TP25 — WLAN-Stabilisierung (NEU 2026-08-17):** Audit durch, **6 Funde** (2,4 GHz fährt 40 MHz statt der profilierten 20; ap2 sendet auf 5 GHz mit **9 statt 18 dBm**, weil ch149 unter ETSI leistungsbegrenzt ist; 80 MHz kostet Randabdeckung; unzulässiger Channel-Override auf `w2-iot`; keine `access-list`; 5-Minuten-Takt bei IoT-Trennungen offen). Umsetzung in 6 Schritten, alles via GC. **Übernimmt den offenen Rest von TP3.3.** - **TP16.3 — cloudflared-Reduktion (NEU 2026-08-17):** Recherche durch. Der Mesh **ist** schon der private Datenpfad (im TP5-Log mit 137 Zeilen belegt); Container braucht nur noch der **öffentliche** Ingress. Vorschlag: `nautobot` als Probe aus dem CF-Ingress nehmen. - ~~**DoH-Cloudflare auf `crs326-core`**~~ ✅ **erledigt 2026-08-18** (TP23 Stufe 1 = TP21.1 TODO 1). - ~~**TP6.1 — Saettigung vermeiden**~~ ✅ **LIVE 2026-08-23: 40,8 → 11,0 ms unter Last** (−73 %). NAS-Sync weicht bei Last zurueck, ComplianceRule `ip-firewall-mangle` angelegt, 104/104. - **TP24 — DC-USV** (seit 2026-08-16 eigener TP, aus TP15 herausgelöst). - ~~**TP19 — VLAN1-Client-Retirement / cudy-Teardown**~~ ✅ **geschlossen 2026-08-18** (VLAN1-ARP = 0). Die zwei Reste sind dorthin verschoben, wo sie hingehören: tote CF-Tunnel → TP16, HA-Portainer `setup_retry` → TP11. - ~~**TP3.3 — WLAN-Coverage-Kur**~~ → **in TP25 aufgegangen** (2026-08-17). 802.11k/v ist repariert (08-13); Re-Walk + Dead-Spot-Kartierung laufen als Schritt 5 von TP25 — und zwar erst **nach** den Funkparameter-Fixes, weil vorher gemessene Werte wertlos sind. - **TP10 —** DDNS-Auto-Updater für `bf4.emsenhuber.net` (auf dem Core möglich, `device-mode` erlaubt scheduler). - 🔑 **Admin-Passwort der vier MikroTik rotieren (offen seit 2026-08-22, User: „machen wir, aber erst später").** Anlass: das Core-Passwort ist bei einer Debug-Ausgabe im Klartext in ein Sitzungstranskript geraten. Ursache war `sshpass -p`, das es in die **Kommandozeile** schreibt — sichtbar in `ps` und in jedem argv-Trace. `docs/tp6-marker/server.py` ist auf `sshpass -e` umgestellt (Passwort nur in der Umgebung des Kindprozesses); **`docs/tp6-monitor-core.sh` und `docs/tp25-pin-s22.sh` haben dieselbe Schwäche noch** und gehören vor der Rotation nachgezogen — sonst ist die Rotation nach dem nächsten Messlauf wieder wertlos. Weg: `manage_user set-password` (⚠️ `/user set*` ist per Deny-Policy blockiert), danach `~/.secrets/credentials.env` (`ROUTER_*_PASS`/`CRS326_*_PASS`) und `~/.claude.json` nachziehen. Es ist **ein** Passwort für alle vier Geräte — die „Überlebensversicherung" aus CLAUDE.md. - **TP14.4 —** CF-Access-Service-Token rotieren. - ~~**Doku-Aufräumen** (`docs/doku-cleanup-session.md`)~~ ✅ **abgeschlossen 2026-08-23.** Punkte A–D (08-16), E (08-18/19) und **F — der Split** (08-23) sind durch: abgeschlossene TPs liegen jetzt in [`teilprojekte-archiv.md`](teilprojekte-archiv.md), TP25 ist von 394 auf ~100 Zeilen kondensiert, diese Datei ist von **2217 auf ~760 Zeilen**. Die Regel dahinter bleibt gültig: ⚠️ **während einer Doku-Session `teilprojekte.md` nicht parallel bearbeiten** (in der Nacht auf den 18. viermal committet, das kollidiert sonst) — und **ein TP wandert erst dann ins Archiv, wenn nichts mehr daran zu tun ist.** ### Nachgelagert / research-getrieben **TP8** (Identity/802.1X) · **TP11** (Monitoring) · **TP12** (IPv6) · **TP13** (Botschafts-WLANs) · **TP16.2** (Härtung bypass-Dienste) · **TP18** (Garage-Objektspeicher) · **TP20.1** (Vaultwarden → Platform-PG) · **TP23** (DNS-Policy, s. Regel oben). *(**TP16.1** stand hier bis 2026-08-17 fälschlich als offen — es ist seit demselben Tag ✅ abgeschlossen und steht unten unter „Durch" (Volltext im [Archiv](teilprojekte-archiv.md#tp16-1)). Nachfolger ist **TP16.3**, das oben unter Follow-ups läuft.)* ### ✅ Durch (Fundament — nicht mehr planen, nur nachschlagen) > 📚 **Alle folgenden TPs stehen seit 2026-08-23 im [Archiv](teilprojekte-archiv.md)** — im Volltext, > mit Inhaltsverzeichnis. Diese Zeile bleibt als *Landkarte*: sie sagt, was fertig ist; das Archiv > sagt, wie es dazu kam. TP1 · TP2 · TP2.1 · TP3 (Rebuild 2026-08-08) · TP3.1 · TP4 (Rolle seit 08-08 auf dem Core) · TP7 · TP7.2 · TP10 (Kern) · TP14 (+14.1/14.2/14.2a/14.3/14.5) · TP15 · TP16 (Kern) · TP17 · TP19.1 · TP20 · TP21 · TP21.1 · TP22 · TP-R · **TP3.2** (08-17) · **TP5** (08-18) · **TP7.1** (08-18) · **TP19** (08-18) · **TP23 Stufe 1** (08-18) · **TP6** (08-23, geschlossen statt gebaut) · **TP6.1** (08-23, Upload-Prio live) · **TP26** (08-17) · **TP27** (08-17/18) · **TP28** (08-17, GC-Modell 08-18). **Verworfen:** TP9 (Gateway-HA, User-Entscheid 2026-08-08). **Obsolet:** Omada-PVID-Fix (User-Entscheid 2026-07-22 — „nie wieder aufgreifen").
📜 Historische Fassung dieses Abschnitts (bis 2026-08-14 fortgeschrieben, hier bewusst erhalten) > 🎯 **AKTUELLER KRITISCHER PFAD (Stand 2026-07-16, überschreibt die Reihenfolge unten): TP20 (Platform-Postgres) → TP21 (Nautobot) — Ziel: fertig vor CRS326-Produktivsetzung, spätestens Montag 2026-07-20.** TP18 (Garage-S3) und die Komodo-Abhängigkeit wurden am selben Tag als Blocker entfernt/entkoppelt (s. TP20), um diese Deadline zu halten — beide werden später nachgezogen, nicht mehr vorher abgewartet. **➡️ Stand-Update 2026-08-08:** TP20/TP21-Plattform steht, Core-Cutover (TP21.1) + WLAN-Rebuild (TP3) + VLAN20-Migration (TP14) sind durch. Neuer Rest-Pfad: **TP22 (Device-Adoption + Compliance-Push) → TP5 (Deny-by-default) → TP6 (CAKE, das Ziel).** Kleine Follow-ups davor: DoH-Cloudflare auf core, USV (**TP24**). **➡️ Stand-Update 2026-08-13 (Abschluss): TP22 ist DURCH** (alle 5 Schritte; Fleet adoptiert, Deploy-Pipeline scharf, Datenmodell as-built, Secret-Handling entschieden) → **kritischer Pfad jetzt: TP5 (Deny-by-default) → TP6 (CAKE)**. Kleine Follow-ups davor: DoH-Cloudflare auf core, DC-USV (**TP24**), **Doku-Aufräumen (`docs/doku-cleanup-session.md`, vorbereitet 2026-08-14 — dieses Dokument beschreibt an mehreren Stellen noch die Topologie vor dem Core-Cutover)**. ➡️ **Neu 2026-08-14: TP23 (DNS-Policy & Self-Service) hängt an TP5** — und zwar in *beide* Richtungen: TP23 braucht TP5s Firewall, **TP5 darf aber die DNS-Bypass-Sperre erst schließen, wenn TP23s Ausnahme-Oberfläche steht** (der bisherige Workaround „Client auf 1.1.1.1" *ist* dieser Bypass). Ebenfalls in TP5 gezogen: **TP7.1** (SSDP-Reflector für die macOS-Sonos-App). ~~Kabel `core ether4`→`ether2` (Sideboard/TV)~~ **entfällt (2026-08-14):** gelöst wurde am **Port**, nicht am Kabel (User-Vorgabe „Patchfeld-Nummerierung wird nicht wegen einer Config geändert") — `ether4` steht seit 08-13 auf untagged VLAN40, End-to-End-Beweis am 08-14 erbracht, s. **TP21.1 Punkt 4**. Historisch: **TP22 war das nächste Arbeitspaket** — TP17 (Shelly-Migration) ist parallel dazu vollständig abgeschlossen (alle Shellys auf VLAN30, User-bestätigt). Grund für den Nautobot-First-Ansatz: Governance-Entscheid „Config exklusiv über Nautobot" (s. oben) macht Nautobot zur Voraussetzung für praktisch jede weitere Router-/Switch-Änderung. Die Punkte 3-4 unten (Omada-PVID-Fix etc.) sind **obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit TP15-Korrektur keine Rolle mehr, nie wieder aufgreifen) — ganze Liste braucht mal eine Aufräum-Session, hier nur der aktuelle Fokus vorangestellt. > ✅ **TP16 (CF-Tunnel Round-Robin/macvlan-Host-Isolation → reziprokes 3-Tunnel-HA)** KERN UMGESETZT 2026-07-10 (#1033 strukturell weg). Offen nur Access-Strang (WARP/`vw`) = user-gated. As-Built `docs/cf-tunnel-mapping.md §10`. 1. ~~**TP1 (GE8) → TP2 (Omada Controller).**~~ ✅ erledigt 2026-06-15. 2. ~~**TP4 (Router-Cutover L3-Infra + WAN-Edge).**~~ ✅ erledigt 2026-06-15 (L3) + 2026-07-01 (Edge-Cutover, FB physisch weg). 3. **Jetzt: Omada-PVID-Fix** — Omada Access-Profile korrigieren (PVID 10/20, untagNetworkIds bereinigen, sicher P3/P5/P6 zuerst), dann IP-Migration NAS/macmini/pve auf VLAN-Subnetze + DNS-Einträge updaten. **IP-Migration NAS/pve = TP14** (NAS ✅ 2026-07-10, pve 🔜 Session B). 4. **Dann:** TP5 (Deny-by-default fertigziehen — Sonos-/HA-/mDNS-Holes + WAN-Input-Seal stehen bereits; **TP5.1 = DNS-Redirect + Live-Torch für Low-Trust-Geräte/Airfryer hängt dran**) → TP6 (QoS/CAKE). ~~TP7 (mDNS)~~ ✅ 2026-07-02 (inkl. HA/vlan20), ~~TP3 (WLAN/CAPsMAN)~~ ✅ 2026-06-18, ~~TP3.1 (ap2-VLAN-Trunk)~~ ✅ 2026-07-01, ~~TP3.2 (P750W/Discovery)~~ ✅ 2026-07-02, ~~Sonos-Migration~~ ✅ 2026-07-02 (alle 10 auf VLAN 40). ⏳ **TP3.3 (WLAN-Coverage-Kur) offen** — Fortsetzung neue Session (`docs/wifi-p750w-coverage-and-map.md`). 5. ~~**TP10 (VPN)**~~ ✅ Kern durch (2026-06-27) + Edge-Cutover (2026-07-01) → DURCH. Offen nur: DDNS-Auto-Updater. 6. **Nachgelagert/Research-getrieben:** TP8 (Access), TP9 (HA), TP11 (Monitoring + CF-Tunnel-Track-B/C), TP12 (IPv6), TP13 (Spaß). 7. **Foundation (2026-07-14):** **TP15** (MikroTik-Switching / Omada-WLAN, 2× CRS326 bestellt) ∥ **TP20 (Platform-Postgres, single-site replication-ready)** → **TP21 (Nautobot Golden Config)** ∥ **TP20.1 (Vaultwarden→PG + 2-Site-HA)**. TP20 hängt an **TP18 ①** (Garage-Bucket für pgBackRest).