Files
bf-infra/docs/teilprojekte.md
Christoph Emsenhuber c9a413858b TP31 + TP32 angelegt; Startreihenfolge auf pve repariert
TP31 -- Caddy als Reverse Proxy fuer innen UND aussen, cloudflared von
sechs Containern auf einen. Anlass war Christophs Einwand, er habe den
Core unter der Praemisse gekauft, dass auch die Public-Apps darueber
laufen. Aktenlage geprueft: eine Zusage gibt es nicht, aber TP16.1
begruendet die Auswahl mit seinem Prinzip 'Router = einziger SPOF' --
und niemand hat je geprueft, ob der oeffentliche Strang ohne sechs
Container auskommt. Keine Taeuschung, eine ungepruefte Annahme.

- dst-nat-Variante geprueft und verworfen (ginge, Free-Tarif reicht),
  weil Christophs Tunnel-Variante drei Risiken spart: keine angreifbare
  Origin-IP, keine CF-IP-Allowlist, kein DDNS als Voraussetzung
- cloudflared auf ap1/ap2: live gemessen arm64, 95 MB Flash frei,
  690 MB RAM frei. Der Core kann es nie (arm 32-bit, 2,9 MB frei)
- Kriterium fuer Infrastruktur-Container: was sich selten aendert und
  wenig schreibt. Caddy nein (Config aendert staendig), AGH nein
  (Query-Log frisst NAND)

TP32 -- VMID-Systematik (Hunderter = Klasse, gemeinsamer Raum fuer VMs
und LXCs) + letztes Oktett je /24, uebertragbar auf andere Standorte.
🔮 Dabei gefunden und SOFORT REPARIERT: die Startreihenfolge war falsch.
Proxmox startet erst Gaeste mit explizitem startup order=, dann den Rest
nach VMID -- drei Gaeste hatten einen, die DBs nicht. Home Assistant
startete damit vor MariaDB, MQTT und z2m25. Jetzt fuenf Stufen
(Core/Daten/Platform/Broker/Apps). Erkenntnis: VMID = Klassifikation,
startup order = Abhaengigkeit -- die Umnummerierung muss den Startlauf
gar nicht reparieren.

Doku-Korrekturen aus den Messungen:
- CLAUDE.md: 'Container NICHT auf dem Router' war nie nachgemessen
- tp16.1: 'Connector als Container ❌' galt dem TUN-Bedarf des
  WARP-Connectors; cloudflared braucht kein TUN
- cf-tunnel-mapping Paragraph 16: die macvlan-Blindheit war mit einem
  Shim behebbar -- der Workaround war groesser als der Fix

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 01:03:54 +02:00

1682 lines
169 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.)*
<details><summary>📜 Historische Fassung (Stand bis 2026-08-08, Topologie <b>vor</b> dem Core-Cutover — bewusst erhalten, nicht als Ist lesen)</summary>
> 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 🟱.
</details>
**NĂ€chster Schritt (Stand 2026-08-25): [TP31](#tp31) — Caddy als Reverse Proxy fĂŒr innen und außen.**
> 🆕 **Neu am 2026-08-24/25:** [TP31](#tp31) löst **TP16** und **TP16.2** ab und dampft cloudflared
> von **sechs Containern auf einen** ein; [TP32](#tp32) gibt die Nummern- und Adress-Systematik vor
> (und hat nebenbei die **falsche Startreihenfolge auf pve repariert** — HA startete vor seiner
> Datenbank). **TP16 ✅, TP25 ✅ und TP16.3 (Pilot) ✅** sind am 24./25. durchgezogen worden.
**Vorherige Fassung (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) ·
> ❌ **TP17.1 VERWORFEN 2026-08-23** (Zigbee-Weg bewiesen, Ziel damit nicht erreichbar — das GerĂ€t
> bleibt WLAN-Client; `s9` zurĂŒckgebaut) · ✅ **TP17.3 ERLEDIGT** (Ursache **`eco_mode`** bewiesen;
> `s23` + `s26` repariert; **`eco_mode` flottenweit aus**, 22/22 außer `s24`) ·
> âžĄïž **TP17.2 ist am 2026-08-24 in TP30 aufgegangen** (Shelly-GerĂ€tepasswort = Erstvergabe eines
> Credentials; TP30 ist das Sammelbecken dafĂŒr) ·
> 🔑 **Alle Passwort-/Token-Rotationen sind seit 2026-08-24 TP30** (Sammel-TP) — **bewusst
> gebĂŒndelt gegen Projektende**, User-Entscheid. Damit ist die Ă€ltere Einreihung „hinter TP17.1"
> gegenstandslos (TP17.1 ist verworfen). **Etappe 1 — die Service-Accounts — ist durch;**
> das `admin`-Passwort selbst ist **nicht rotiert** und bleibt es bis dahin bewusst.
> 📌 **Einstieg fĂŒr die nĂ€chste Session: [`handoff-20260824-session.md`](handoff-20260824-session.md)**
> — ⚠ dessen Empfehlung „Start bei der Passwort-Rotation Etappe 2" ist durch den TP30-Entscheid
> **ĂŒberholt**; der Rest der Übergabe gilt. Ältere 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`.
<details><summary>📜 Vorherige Fassungen dieses Absatzes (2026-07-22 → 2026-08-21, bewusst erhalten)</summary>
> *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."*
</details>
> 🎯 **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 `<<REDACTED>>` 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~~ *(TP17.2 ist am 2026-08-24 in **TP30** aufgegangen und kein eigenes TP mehr)*
> 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 ▾ ✅ **HA WIEDER VOLL (2026-08-24)** — Kern 2026-07-10 — `docs/cf-tunnel-mapping.md §10 + §15`, #1033
- ✅ **GEFIXT 2026-08-24 — Ursache war ein `docker stop`, kein QUIC-Flap.** Die beiden macmini-Connectoren
(`cloudflared-bfnas`, `cloudflared-bfpve`) standen auf `Exited (0)`, **beide `finishedAt` auf derselben
Sekunde `2026-07-21T13:00:53`**, bei korrekt gesetztem `restart=unless-stopped` und `http2`. Fix =
`docker start` der zwei, sonst nichts. **Abnahme: alle drei bf-Tunnel je 2 Connectoren / 8 conns,
und 36 Anfragen ĂŒber 6 FQDNs beider betroffener Tunnel mit `530er = 0`.** Details `§15`.
- 🔮 **Die Datierung im Befund unten war falsch:** degradiert **seit 2026-07-21**, nicht seit dem 08-16 —
der 08-16 war der Tag der *Entdeckung*. **Vier Wochen unbemerkt.**
- 🔮 **Die eigentliche Lehre ist die NachweislĂŒcke:** ein Tunnel mit 1 von 2 Connectoren meldet
`healthy`. Über den Tunnel-Status ist die Degradation **unsichtbar**, nur die **Connector-Anzahl**
zeigt sie. ⇒ Check nach **TP11**: `connectoren < 2` je bf-Tunnel = Alarm. **Ein HA-Design ohne
ZĂ€hler auf die Redundanz ist kein HA-Design.**
- 📜 **UrsprĂŒnglicher Befund 2026-08-16 (Historie, Ursache s.o.):**
- `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~~ 🔮 **war es NICHT** — s. Fix oben. Ursprungstext:
**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.
- ✅ **GELÖSCHT 2026-08-24 (User-Entscheid „alle vier"):** `openclaw`, `coolify`, `johnny2`,
`TeilzeitCharlie` sind ĂŒber die CF-API entfernt, alle vier mit `success: true`. **Gegenprobe: 5 Tunnel
verbleiben** (`bf-mm`/`bf-nas`/`bf-pve` je 2 Connectoren, `fm` und `terpene-db` je 1 — beide
standortfremd bzw. eigenes Projekt, kein Defekt). Damit sind auch die letzten **VLAN1-Origins**
(`10.40.41.147/.148/.139/.133`) aus der Cloudflare-Config verschwunden — der Rest von TP19.
- 📜 **UrsprĂŒnglicher Nebenbefund (Historie):** 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)
đŸ”” **BegrĂŒndung korrigiert 2026-08-24:** die Sorge „kĂ€me der Tunnel wieder hoch, entstĂŒnde das alte
Round-Robin auf diesem Hostname" ist **so nicht richtig** — **welcher Tunnel einen Hostname bedient,
entscheidet das DNS**, und live zeigt **kein einziger CNAME** auf die vier (`n8n` zeigt korrekt auf
`bf-mm`). Ein hochkommender `openclaw` wÀre inert. Der reale Pfad ist ein *aktives*
`cloudflared tunnel route dns`, das den CNAME umschreibt. ⇒ **Löschen bleibt richtig — als Hygiene
und um genau diese Falle zu entfernen, nicht als Störungsbehebung.** — 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) ▾ ⏳ **PROBE LÄUFT SEIT 2026-08-24** — `docs/tp16.3-nautobot-mesh-only-runbook.md §8`
- ▶ **Schnitt ausgefĂŒhrt 2026-08-24:** `nautobot.emsenhuber.net` ist aus dem Ingress von `bf-nas`
entfernt (**8 → 7 Regeln**, Catch-all weiterhin letzte). Rollback-Sicherung liegt unter
`docs/cf-backup/bf-nas-ingress-20260824-vor-tp16.3.json` — RĂŒckweg ist ein `PUT`, eine Minute.
**Abnahme vollstĂ€ndig:** private IP mit WARP von außerhalb des LAN 302 in 0,16 s · die ĂŒbrigen fĂŒnf
`bf-nas`-Hostnames unverĂ€ndert · und der Punkt, den man ĂŒbersieht — **Golden Config lief durch:
Backup → Intended → Compliance, 104/104, 0 Drifts.**
- 🎯 **Der Testaufbau war der einzige, der etwas beweist:** die Session lief auf einem Host im
Hotspot-Netz `172.20.10.13` mit aktivem WARP, also **nicht im BF-LAN**. Aus dem LAN heraus wÀre
der Zugriff ohnehin gegangen und hÀtte nichts gezeigt (Merkregel `feedback_adresse_lesen_nicht_ansagen`).
- 🔮 **Befund, der die Abnahmetabelle des Runbooks korrigiert: der öffentliche FQDN taugt nicht als
Test.** `nautobot.emsenhuber.net` liefert **vor und nach** dem Schnitt HTTP 302 — der kommt von
**Cloudflare Access**, nicht vom Origin (`location: emsenhuber.cloudflareaccess.com/cdn-cgi/access/
`,
JWT `auth_status: NONE` bei `is_warp: true`). Access greift **vor** dem Tunnel. ⇒ GĂŒltiger Nachweis
ist **das ZurĂŒcklesen der Ingress-Config**, nicht die Antwort des Frontends — dieselbe TP22/TP23-Regel.
- 📌 **Und die Erwartung wird damit ehrlicher:** Nautobot war nie ohne Access-Login öffentlich
erreichbar. Der Schnitt schließt **keine offene TĂŒr**, er entfernt eine **ĂŒberflĂŒssige zweite**.
- ⚠ **VorprĂŒfung, die vor jedem weiteren Schnitt zu wiederholen ist:** hĂ€ngt Werkzeug am
öffentlichen Namen? Hier nein — `gc-configplan.py` spricht `http://10.40.20.30:8080/api`, und
kein Repo-Skript nutzt den FQDN.
- ⏳ **Offen: das Betriebsfenster.** Eine Woche fahren (bis ~**2026-08-31**), dann entscheiden, ob es so
bleibt und ob `pve`/`portainer`/`grafana`/`pve-mcp`/`ha-mcp`/`gitea-mcp`/`ds-bf`/`ccu`/`iobroker`/`z2m25`
folgen.
- 📌 **Ein Argument des TP ist entfallen:** die HA-Degradierung, die §7 als Nebeneffekt anfĂŒhrte, ist am
**selben Tag repariert** (TP16 ✅). Der Fall steht damit allein auf dem eigentlichen Argument —
**weniger bewegliche Teile fĂŒr Dienste, die öffentlich nicht gebraucht werden.**
> 📌 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.1 — Shelly Gen4 raus aus dem WLAN ▾ ❌ **VERWORFEN (2026-08-23) — Weg bewiesen, Ziel damit nicht erreichbar** — 📋 `docs/tp17.1-shelly-gen4-funkmigration-runbook.md`
> ❌ **User-Entscheid 2026-08-23 nach dem Pilot: stoppen und zurĂŒckbauen.** Auslöser war Christophs
> strukturelle Frage: *„zigbee sollte die antwort auf die vielen radios auf -iot geben. nutzt aber
> wenig wenn man das wifi nicht abdrehen kann bzw. es nicht mehr aktivieren kann ohne reset."*
>
> **Der Pilot hat den Weg technisch vollstĂ€ndig bewiesen** — `s9` lief auf `PowerStripZB`, trat ZHA
> bei, ein Zigbee-Befehl schaltete das physische Relais, kein Broadcast-Sturm. **Und er hat gezeigt,
> dass das Ziel so nicht erreichbar ist:**
> - Das GerĂ€t **bleibt WLAN-Client** — Zigbee kommt *zusĂ€tzlich*, nicht *statt*.
> - Der Funkgewinn ist **gemessen klein**: die 12 Gen4 sind 12 von 26 IoT-Clients, bewegen aber je nur
> ~150–200 KB rx / 0,6–3 MB tx in sechs Stunden. Leerlaufende Stationen.
> - Der Preis wÀre **dauerhaft**: die Zigbee-Firmware hat **keinen AP** (`WiFi.GetConfig` kennt nur
> `sta`/`sta1`/`roam`), Shelly macht **kein Zigbee-OTA**, und `Shelly.InstallAlt` braucht IP.
> WLAN aus hieße: nie wieder Firmware-Update, kein RĂŒckweg — bei 10 Unterputz-Modulen.
>
> ✅ **RĂŒckbau durchgefĂŒhrt 2026-08-23:** ZHA-Knoten sauber entfernt (Leave **vor** dem Flash, damit
> kein Geisterrouter im 52-GerĂ€te-Mesh bleibt), `s9` zurĂŒck auf `PowerStrip`, Config aus dem Backup
> wiederhergestellt. Compliance des Zigbee-Netzes unauffÀllig: alle vier roten EZSP-ZÀhler blieben
> **0**, Retry-Quote fiel im Delta auf 8,9 %.
> ⚠ **Beim RĂŒckflash zog die Firmware einen OFFENEN AP hoch** (`ap.enable=true, is_open=true`) —
> abgeschaltet und mit dem IoT-PSK abgesichert. **Nach jedem Shelly-Firmwarewechsel den AP prĂŒfen.**
>
> 📌 **Das Runbook bleibt** — es enthĂ€lt den kartierten Mechanismus (drei undokumentierte RPCs,
> Zwei-Slot-Modell), das gemessene 2,4-GHz-Bild und die ZHA-SturmzÀhler mit Baseline.
> *Der Weg ist nicht gescheitert, das Ziel war mit ihm nicht erreichbar.*
> 🔭 **Einziger Restposten:** der **FrĂŒhindikator** — `Shelly.CheckForUpdate` auf einem Gen4 auf einen
> `
MT`/Thread-`alt`-Eintrag beobachten. Erscheint er, Àndert sich die Rechnung.
<details><summary>UrsprĂŒnglicher Planungstext (historisch)</summary>
> **User-Formulierung (2026-08-23):** „wir lassen das pwd vorerst wie es ist. wir werden alle shelly
> gen4 auf thread umstellen — neue firmware. das machen wir im ha-projekt. das sehe ich als subpunkt
> zu pwd Ă€ndern. der vorteil: wir mĂŒssen dann weit weniger gerĂ€te umstellen, steigern
> thread-stabilitÀt und bringen zudem mehr ruhe ins wifi."
>
> 📋 **Runbook: [`tp17.1-shelly-gen4-funkmigration-runbook.md`](tp17.1-shelly-gen4-funkmigration-runbook.md)**
> — Bestand, die drei Wege im Vergleich, Ablauf, Abnahme, Verzahnung mit der PSK-Rotation.
> 📌 **Wohnort ist das Netz-Projekt (User-Entscheid 2026-08-23).** Eine erste Fassung lag kurz im
> HA-Projekt (`ha-xstate`); sie ist dort **entfernt**, damit es keine zweite Wahrheit gibt. **HA ist
> Betroffener, nicht EigentĂŒmer:** die Entities brechen, aber die Entscheidung ist eine Funk- und
> Netzentscheidung. *(Der Titel sagt jetzt „Thread **oder Zigbee**" — der ursprĂŒngliche
> Thread-Zuschnitt hat den heute tatsĂ€chlich verfĂŒgbaren Weg ausgeschlossen, s. Nachtrag unten.)*
- 🔀 **Die Reihenfolge ist der eigentliche Entscheid:** die **PSK-Rotation** (Follow-up unten) wird
**nachgelagert**, nicht vorgezogen. BegrĂŒndung des Users: jedes GerĂ€t, das vorher auf Thread
wandert, muss beim PSK-Wechsel nicht mehr angefasst werden. Damit ist die Rotation **Nachfolger**
von TP17.1, nicht mehr eigenstĂ€ndig. *(Sie war nie dringend — Anlass war ein Passwort in einem
Sitzungstranskript, kein Vorfall.)*
- 📊 **Bestand live gesweept 2026-08-23** (`mcp/shelly/discover.py`, read-only, VLAN30): **22 von 26
erreichbar**, davon **12 Gen4** (9× 2PM Gen4 `S4SW-002P16EU`, 1× 1PM Gen4, 2× Plug S Gen4), 8 Gen3,
2 Gen2 — alle auf Firmware 2.0.0. Nicht erreichbar: s1/s2/s3 (weihnachten_*, saisonal) und **s4
`kueche_mikrowelle`** (MetallgehĂ€use, RSSI −93 — der HĂ€rtefall des WLAN-Betriebs).
- 🔮 **Die PrĂ€misse „neue Firmware" trĂ€gt so nicht, und das Ă€ndert die Rechnung:** **Shelly
unterstĂŒtzt Matter over Thread offiziell nicht** und plant es nicht. Gen4 kann offiziell nur
**Matter over WiFi** — was hier nutzlos wĂ€re, weil das GerĂ€t im WLAN bliebe und den PSK weiter
brĂ€uchte. Thread geht nur ĂŒber **Dritt-Firmware** (die ESP32-C6-Hardware kann es). Das brauchbare
Projekt (`hencou/shelly_gen4_matter_module`) deckt 1/1 Mini/1PM/2PM Gen4 ab = **10 der 12** GerÀte;
die zwei **Plug S Gen4 fallen raus**. Preis: Garantie und Shelly-Cloud weg, RĂŒckweg nur mit
**UART-Vollbackup je GerÀt**, PM-Kalibrierung zunÀchst Platzhalter.
⇒ **Selbst bei vollem Erfolg blieben 12 Shellys im WLAN** (8 Gen3 + 2 Gen2 + 2 Plug S + die 4
ausgesteckten). Die Rotation wird **kleiner, nicht ĂŒberflĂŒssig** — und Gen3 kann nie folgen, dort
fehlt 802.15.4. **Das ist Christophs AbwÀgung vor dem ersten Flash, nicht die des Umsetzenden.**
- 📊 **Und die Rechnung ist noch etwas ungĂŒnstiger, als „Shellys" nahelegt** (live 2026-08-23):
auf `dirtyvader-iot` hĂ€ngen **26 der 27 WLAN-Clients des ganzen Netzes** — darunter Drucker
(P750W), Airfryer, SwitchBot, Twinkly, DTUBI und ein SONOFF-NSPanelPro, die von Thread **nichts**
haben. Nach zehn migrierten Gen4 blieben also grob **16 GerÀte** auf dem IoT-SSID, nicht 12.
Der WLAN-Ruhe-Effekt ist real (−38 % Clients), der PSK-Effekt ist es **halb**.
- ✅ **Was netzseitig schon steht und nicht nochmal gebaut werden muss:** Thread-Border-Router lĂ€uft
mit ~30 produktiven Matter-Knoten; der **Commissioning-Weg ist erprobt** — temporĂ€re SSID
`dirtyvader-infra` (VLAN20) nach [`matter-pairing-infra-ssid-runbook.md`](matter-pairing-infra-ssid-runbook.md),
am 2026-08-22 mit dem TIMMERFLOTTE bewiesen. `cfg-infra`/`dp-infra`/`sec-infra` stehen dauerhaft am
Manager, das Anlernen ist ein Zweizeiler plus eine Config-Transaktion.
- 🔮 **Der Umweg bleibt nötig, weil TP12.1 offen ist** (kein IPv6-Routing VLAN10↔VLAN20 → Matter-
Commissioning-Etappe 2 bricht ab), und `ble_proxy` ist wirkungslos, seit der ESP32-BT-Proxy
ausgeschlossen wurde. **Je mehr Thread-GerĂ€te kommen, desto öfter zahlt man diesen Umweg** — das
ist das stĂ€rkste neue Argument fĂŒr TP12.1, das bisher nur an einem einzigen FĂŒhler hing.
- **Abnahme (aus TP28 gelernt):** pro GerÀt ein **frischer Thread-Knoten und eine funktionierende
HA-Entity** — nicht die Anzeige in einer Tabelle. Ein GerĂ€t, das in Thread hĂ€ngt und in HA halbtot
ist, ist ein RĂŒckschritt.
- 🔬 **Nachtrag 2026-08-23 (abends) — die GerĂ€te selbst befragt (`Shelly.CheckForUpdate`, read-only).
Ergebnis: es gibt heute KEIN Thread-Update, aber die offizielle Alt-Firmware-Schiene existiert — sie
liefert bisher ZIGBEE.**
| Was | Stand am GerÀt |
|---|---|
| Stable | **2.0.0 auf allen 22** — fĂŒr **keines** ein stabiles Update verfĂŒgbar |
| Beta | `2.0.1-beta1` (Build **2026-08-19**) fĂŒr alle, auch Gen3 |
| **Alt-Varianten (nur Gen4!)** | `S2PMG4ZB` „Shelly 2 PM Gen4 **with Zigbee**" · `S1PMG4ZB` (1 PM Gen4) · `PowerStripZB` (Power Strip Gen4) — je stable 2.0.0 + beta |
| Gen3 (`S3PL-*`) | **kein `alt`-Eintrag** → Alternativfunk ist eine reine Gen4-Sache, wie erwartet |
- 🎯 **Das ist die wichtigste Erkenntnis fĂŒr die Planung:** Shelly liefert alternative
**Funk**-Firmware fĂŒr Gen4 **ĂŒber den normalen Update-Kanal**, nicht ĂŒber einen Bastelpfad. KĂ€me
eine Thread/Matter-Variante, erschiene sie mit hoher Wahrscheinlichkeit **genau dort** als weiterer
`alt`-Eintrag. ⇒ **Billiger FrĂŒhindikator statt Warten auf Pressemeldungen:**
`Shelly.CheckForUpdate` auf einem Gen4 pollen und auf einen `
MT`/Thread-Eintrag warten.
- 📰 **Presselage (recherchiert 08-23):** Shellys offizielle Linie ist **„wird evaluiert"**, nicht
„ist angekĂŒndigt" — Stand Juli 2026, mit **Flash-Platz** als genanntem Engpass. Ein Release-Datum
gibt es nicht. *(Die Thread-Firmware, die im Mai 2026 als „fĂŒr Gen4 verfĂŒgbar" durch die Presse
ging, ist die **Dritt**-Firmware von automatous-io, nicht Shelly.)*
- 💡 **Und daraus folgt eine Option, die vorher nicht auf dem Tisch lag: ZIGBEE statt Thread.** Sie
erfĂŒllt **alle drei** Ziele von TP17.1 — GerĂ€te raus aus dem WLAN (PSK-Rotation wird billiger),
Mesh-StabilitĂ€t, Funkruhe im 2,4-GHz-WLAN — und zwar **heute, mit Hersteller-Firmware ĂŒber den
offiziellen Kanal**, also ohne Garantieverlust, ohne UART-Backup, ohne Test-VID. Die Infrastruktur
steht bereits: **Zigbee2MQTT lÀuft als LXC 112 (`10.40.20.106`, `z2m25`)**.
⚠ **Zu prĂŒfen, bevor das zur Empfehlung wird:** **(a)** ob die Alt-Firmware genauso zurĂŒckrollbar
ist wie ein normales Update (Wechsel des Funkstacks, nicht nur der Version) — **offen**;
**(b)** ~~der Entity-Bruch~~ ✅ **entschĂ€rft (User 2026-08-23): der Umbau behĂ€lt die
Entity-Namen** — damit fĂ€llt der teuerste Posten der AbwĂ€gung weg, fĂŒr Zigbee **und** Thread
gleichermaßen *(zwei Fallen dazu im Runbook: die alte `entity_id` ist erst nach dem Entfernen
frei, und `unique_id`/Statistiken sind trotzdem neu)*;
**(c)** Kanalplanung ✅ **erhoben 2026-08-23** — es gibt **drei** 802.15.4-Netze, nicht eines:
**Thread 15** (~30 Matter-Knoten), **ZHA 20** (**52 GerĂ€te**, SONOFF Dongle-M ĂŒber
`socket://10.40.30.137:6638`), **Z2M 25** (Sonoff Dongle Plus). Gegen WLAN **ap1 ch1 / ap2 ch11**
ist das sauber — **außer ZHA ch20 (2450), das direkt auf der Unterkante von WLAN ch11 (2451)
sitzt**, ausgerechnet 52 GerĂ€te gegen den AP mit 26 Clients. Die LĂŒcke 2423–2451 (ZB 16/17/18) ist
unbenutzt; ⚠ ein ZHA-Kanalwechsel mĂŒsste von 52 GerĂ€ten mitgemacht werden, schlafende und Ă€ltere
Router folgen nicht zuverlĂ€ssig → **erst Energy-Scan, dann entscheiden.**
🔮 **Und der Vorbehalt, der schwerer wiegt als alle drei: Christophs Z2M-Vorfall von 2024**
(„Lichterdisko", Installation unsteuerbar, Neuaufbau). Fehlerklasse ist benennbar
(Broadcast-/Routing-Sturm — trifft ZHA genauso), Root Cause nicht mehr rekonstruierbar.
⇒ **Mitigation ohne Ursachenkenntnis = Blast Radius trennen:** die zehn neuen Router komplett in
**ein** Zigbee-Netz, und zwar in das, das **nicht** Licht und Fernbedienungen trÀgt. Details und
Abbruchkriterium im Runbook.
- đŸ©ș **HA-Gegencheck 2026-08-23: genau EIN Shelly ist offline** — `s4 kueche_mikrowelle` (23 Entities
`unavailable`). Deckungsgleich mit dem Netz-Sweep, und es ist dasselbe GerĂ€t, das bei **RSSI −93**
hinter Metall hÀngt. **s1/s2/s3 (`weihnachten_*`) sind in HA nur DEAKTIVIERT**, nicht gelöscht
(Christoph 2026-08-23) — deaktivierte Entities haben keinen Zustand und tauchen deshalb in keiner
Zustandssuche auf. Die Entities gibt es also zu Recht; sie kommen mit den GerĂ€ten zurĂŒck.
*(Meine erste Formulierung „existieren gar nicht" war falsch.)* ⇒ FĂŒr die
PSK-Rotation heißt das: **drei GerĂ€te, die niemand vermisst, aber die beim nĂ€chsten Einstecken mit
dem alten PSK kommen.** Genau dafĂŒr ist die Übergangs-`access-list` da.
- đŸ–šïž **Es gibt ZWEI Drucker — geklĂ€rt 2026-08-23, beide Angaben waren richtig:**
**(1) P750W = Etikettendrucker, VLAN30** (`10.40.30.5`, Reservierung auf `dhcp-v30`, ARP `vlan30`;
am 08-23 aus, `last-seen 3d15h` — deshalb nicht unter den 26 assoziierten Clients).
**(2) Brother MFC = der eigentliche Drucker, VLAN10** — live bestĂ€tigt `10.40.10.6`, MAC
`30:05:5C:78:86:20` (OUI Brother Industries), ARP `delay` = aktiv, **statisch konfiguriert, keine
DHCP-Reservierung**.
📌 **Folge fĂŒr TP5:** die Merkregel „Drucker fĂ€llt mit **udp/161 (SNMP)** aus, nicht mit 631"
(`ref_printer_snmp_before_ipp`) gilt dem **VLAN-ĂŒbergreifenden** Fall. Der MFC steht im **selben
VLAN** wie die Macs — dort greift die `forward`-Kette gar nicht.
- 🔀 **Reihenfolge revidiert (User 2026-08-23): PSK-Rotation und Thread-Umstellung laufen PARALLEL.**
Sie blockieren einander nicht — der Passphrase-Override je MAC (`/interface wifi access-list`,
s. Follow-up) macht den Flag-Day ĂŒberflĂŒssig: neuer PSK aufs Profil, die noch nicht migrierten
GerĂ€te ĂŒbergangsweise per MAC mit dem alten weiter. **Einzige Regel, damit die ParallelitĂ€t nichts
kostet:** ein GerĂ€t, das ohnehin auf Thread/Zigbee wandert, bekommt den neuen PSK **gar nicht** —
es kommt auf die Override-Liste und verschwindet spĂ€ter ganz. *(Die frĂŒhere Formulierung „blockt
die Rotation" war zu streng; die Reihenfolge war nie technisch nötig, nur ökonomisch.)*
- **Abh.:** keine harten fĂŒrs Netz. **LĂ€uft parallel zur PSK-Rotation** (User-Entscheid 08-23,
vorher als Blocker gefĂŒhrt). Verwandt: **TP12.1**
(IPv6/Matter — profitiert direkt), **TP25** (jedes GerĂ€t weniger im 2,4-GHz-Band ist Funkruhe),
**TP17** im [Archiv](teilprojekte-archiv.md#tp17) (Migrationshistorie + `mcp/shelly/`-Werkzeug).
</details>
### TP17.3 — Shelly-Regression nach der VLAN30-Migration ▾ ✅ **ERLEDIGT (2026-08-23, Folge-Session): beide GerĂ€te repariert, Ursache `eco_mode` bewiesen** — offen nur noch der Flotten-Entscheid (gehört TP17.1) — aus TP17 herausgelöst, User-Meldung
> **User-Meldung 2026-08-23:** „vor einiger zeit hast du an den shellys Ă€nderungen vorgenommen. das
> hatte bei einigen einen bösen seiteneffekt: **lĂŒfter-shelly musste ich doppelt drĂŒcken**. der ĂŒbelste
> ist jedoch der von **diele ug: seit deinen Ànderungen spinnt er herum und blinkt wie ein wilder.
> sobald AP on ist, ist die symptomatik weg.** ich muss vermutlich eh alle shellys neu machen."
- 🔮 **Erste Konsequenz, sofort: der aktivierte AP auf `s23` ist ein WORKAROUND, kein Rest.** Ich hatte
ihn beim WLAN-Scan am selben Tag als â€žĂŒbrig gebliebenen Anker aus TP17, gehört abgeschaltet"
eingeordnet — **das war falsch**, und es hĂ€tte Christophs Notbehelf zerstört. Er ist bewusst an.
**Nicht abschalten, bevor die Ursache behoben ist.** *(Merkregel: ein Zustand, der nach einem
Verfahren â€žĂŒbrig" aussieht, kann eine Reparatur sein. Vor dem AufrĂ€umen fragen, wozu er da ist.)*
✅ **Aufgelöst 2026-08-23:** die Ursache ist behoben, der AP auf `s23` ist **abgeschaltet** und wird
nicht mehr gebraucht. Der Workaround hat exakt das getan, was die Hypothese vorhersagte.
- **Symptome und GerÀte:**
| GerÀt | Modell | Symptom |
|---|---|---|
| **s23** `dieleug-wohnzimmer_licht` `.203` | **SPDM-002PE01EU**, app `ProDimmerx` = **Phasenanschnitt-Dimmer** (Diele UG/Licht + Wohnzimmer/Seitenlicht) | „blinkt wie ein wilder", **AP an ⇒ weg** |
| **s26** `bad_luefter` `.233` | S4SW-002P16EU (Gen4), `switch:0 in_mode=momentary` | muss **doppelt gedrĂŒckt** werden |
#### Was die Migration am GerÀt wirklich verÀndert hat (TP17, 2026-07-13)
Vier Dinge, nicht nur die WLAN-Config: **(1)** STA-SSID/PSK · **(2)** **statische IP** statt DHCP
(`ipv4mode=static`, gw/dns `10.40.30.1` — an allen 22 bestĂ€tigt) · **(3)** **`eco_mode`** nach einer
RSSI-Politik · **(4)** AP-Anker an/aus.
#### 🎯 ✅ BESTÄTIGTE URSACHE: **`eco_mode`**, nicht die WLAN-Config
- `eco_mode` **senkt den CPU-Takt und die WLAN-Sendeleistung** — so steht es in TP17 selbst.
- Ein **Phasenanschnitt-Dimmer** braucht prÀzises **Nulldurchgangs-Timing**. Ein gedrosselter Takt
erzeugt Jitter in genau diesem Timing ⇒ **Flackern**. Das ist s23.
- **Warum „AP an" heilt:** ein aktiver Access Point muss beaconen, das Funkteil darf nicht in die
SparzustĂ€nde. Der AP hebt also faktisch den Energiesparbetrieb auf — **er behandelt das Symptom
genau dort, wo die Hypothese die Ursache vermutet.** Diese Korrelation ist das stÀrkste Indiz.
- **s26:** `momentary`-Eingang + gedrosselter Takt ⇒ die erste Flanke wird verschluckt ⇒ „doppelt drĂŒcken".
- ✅ **Gegenprobe im Bestand:** **`s12 dieleug_steckdosen`** hĂ€ngt am selben Ort, ist dasselbe
Gen4-Modell wie s26 — und hat **`eco_mode=false`**. Es ist unauffĂ€llig. *(Kein Beweis, aber die
Hypothese ĂŒberlebt ihn.)*
- ✅ **Die AlternativerklĂ€rung ist damit erledigt:** der Verdacht auf gerĂ€tespezifische Dimmer-Themen
(Leading/Trailing Edge, Kalibrierung, Mindestlast/LED-Treiber) hat sich nicht bestĂ€tigt — `eco_mode`
allein genĂŒgte. *Nebenbei: die Config dieses GerĂ€ts kennt fĂŒr Phasenan-/-abschnitt ohnehin **keinen**
Parameter; Stellschrauben wÀren nur `warmup`, `range_map`, `gamma`, `min_brightness_on_toggle`
gewesen.* Der Link war mit −54 dBm die ganze Zeit sehr gut, ein reines Funkproblem war nie plausibel.
#### Der diskriminierende Test (klein, reversibel, ein GerĂ€t) — ▶ AUSGEFÜHRT 2026-08-23
1. ✅ `s23`: `Sys.SetConfig {"config":{"device":{"eco_mode":false}}}` — **AP zunĂ€chst AN gelassen**.
`cfg_rev` 91 → 92, `eco_mode=false` gelesen.
2. ✅ Christoph beobachtet: **„licht in diele ug ist jetzt flackerfrei"**.
⚠ **Das ist noch kein Nachweis** — mit AP an war es vorher schon flackerfrei. Beide Hypothesen
sagen an dieser Stelle dasselbe voraus. *(Merkregel [[feedback_abnahme_wirkung_nicht_anzeige]].)*
3. ✅ **AP aus** (`WiFi.SetConfig ap.enable=false`) — damit war der Test scharf: `eco_mode=false`,
`ap.enable=false`, STA `got ip 10.40.30.203` bei −54 dBm.
4. 🎯 **ERGEBNIS — Christoph, 2026-08-23: „beide lampenausgĂ€nge getestet. funktioniert perfekt, kein
flackern."** Genau die Konstellation, die vorher geflackert hat, ist ohne AP stabil.
⇒ **`eco_mode` war die Ursache. Hypothese bestĂ€tigt, `s23` repariert.**
5. ✅ `s26 bad_luefter` analog: `eco_mode=false` gesetzt (`cfg_rev` 18 → 19) **+ Reboot** (s.u.).
🎯 **ERGEBNIS — Christoph: „lĂŒfter perfekt."** Der Doppeldruck ist weg.
⇒ **Beide gemeldeten GerĂ€te repariert, beide Symptome durch dieselbe Ursache erklĂ€rt.**
🔮 **Korrektur einer Annahme aus dieser Session:** ich hatte gewarnt, `eco_mode` brauche einen
**Neustart**, um zu wirken, und der Test sei deshalb unvollstĂ€ndig. **Falsch** — das GerĂ€t antwortet auf
`Sys.SetConfig` selbst mit `{"restart_required": false}`. Der Test war richtig formuliert, ein Reboot
des Dimmers (= Lichtausfall in Diele UG/Wohnzimmer) wurde daraufhin **nicht** ausgefĂŒhrt.
*(Und daraus folgt der wichtigere Schluss: `eco_mode` kann das `restart_required` der 14 GerÀte unten
**nicht** verursacht haben.)*
#### Weitere Funde aus dem Sweep vom 2026-08-23 (read-only, alle 22 GerÀte)
- 🔮 **Die eco-Politik ist damit nicht nur stale, sondern WIDERLEGT.** Regel von 2026-07-13 war
„eco **an** bei RSSI ≄ −80, **aus** darunter" — sie hat an `s23` **realen Alltagsschaden** erzeugt und
war nie konsistent umgesetzt. Ist-Stand des Sweeps 2026-08-23 (22 GerÀte, live):
**eco AUS:** s7 (−90), s12 (−64), s17 (−76), s18 (−81), s19 (−88) · **eco AN:** alle ĂŒbrigen 16,
darunter s20 (−85) und s21 (−85) — die RSSI-Regel ist an keiner Kante mehr erkennbar. Die Werte haben
sich seit Juli durch TP25/TP28 ohnehin verschoben. Die in TP17 vorgemerkte „2. Evaluation nach TP3.3"
hat nie stattgefunden.
⇒ ✅ **ENTSCHIEDEN UND AUSGEFÜHRT 2026-08-23. User: „eco-mode fĂŒr alle deaktivieren. der rotz macht
nur probleme."** 13 GerÀte umgestellt (s5, s6, s8, s10, s11, s13, s14, s15, s16, s20, s21, s22, s25),
**null Fehler**; 9 standen bereits auf `false`. **Stand jetzt: `eco_mode=false` auf allen 22
erreichbaren Shellys**, einzige Ausnahme `s24` (SNDC-0D4P10WW meldet `eco_mode: None` — nicht
unterstĂŒtzt). Offen nur s1/s2/s3 (`weihnachten_*`, saisonal stromlos).
🔧 **Werkzeug:** `mcp/shelly/migrate.py eco <range> [--go|--on]` — neu, ĂŒber denselben `_rpc`-Pfad,
mit Retry je GerĂ€t (ein Timeout an einem schwachen Link darf den Sweep nicht abreißen) und einer
Fehlerliste am Ende.
🔬 **Und die Gegenmessung widerlegt meine eigene Warnung.** Ich hatte hier notiert, eco aus hebe die
**Sendeleistung** an und sei deshalb eine Airtime-Änderung, die TP25 berĂŒhre. **Gemessen stimmt das
nicht:** Signal der 13 geĂ€nderten GerĂ€te in der Registration-Table des Managers, vorher/nachher —
**Mittel −0,9 dB, Median −1 dB, Spanne −3..+3**, bei einer **Kontrollgruppe von 13 unverĂ€nderten
GerÀten mit +0,0 dB und derselben Streuung**. Das ist Rauschen, kein Effekt.
⇒ **Die Aussage aus TP17, `eco_mode` senke „den CPU-Takt UND die WLAN-Sendeleistung", stimmt nur zur
HĂ€lfte.** Der Takt-Teil ist durch das Dimmer-Flackern bewiesen; der Sendeleistungs-Teil ist an diesen
GerĂ€ten nicht messbar. **Kein Funkbild-Argument mehr fĂŒr oder gegen eco.**
- ✅ **AP-Anker-Sweep erledigt (der offene read-only-Punkt aus der Übergabe):** `WiFi.GetConfig →
ap.enable` ĂŒber alle 22 GerĂ€te. **Nur `s23` hatte einen AP an** (= Christophs Workaround, inzwischen
abgeschaltet), die ĂŒbrigen 21 stehen auf `false`. **Kein AufrĂ€umbedarf, kein weiterer Anker im Bestand.**
- đŸ”” **Nebenbefund, gehört nicht hierher, aber nicht verlieren:** alle Shellys stehen auf
`sys.sntp.server = time.cloudflare.com`. Kanonisch ist seit 2026-08-18 **der Core als Zeitquelle**,
ausgeliefert per **DHCP-Option 42** — die Shellys haben aber aus TP17 **statische IPs** und sehen die
Option nie. Funktioniert (Uhrzeit stimmt, udp/123 aus VLAN30 geht raus), ist aber ein blinder Fleck in
der NTP-Vereinheitlichung. **Gleiche Klasse fĂŒr jedes statisch adressierte GerĂ€t im Netz.**
- đŸ”” **`inventory/bf.csv` ist bei `s12` stale:** dort steht noch `10.40.41.219`, live ist das GerĂ€t auf
`10.40.30.219` (migriert). Die drei `weihnachten_*` (s1–s3) sind saisonal stromlos, `s4
kueche_mikrowelle` offline — das erklĂ€rt 26 EintrĂ€ge vs. 22 erreichbare.
- 🟠 **`restart_required = true` — nicht auf 2 GerĂ€ten, sondern auf 14 von 22** (Sweep 2026-08-23,
Folge-Session): s5, s6, s7, s10, s12, s13, s16, s17, s18, s19, s20, s21, s24, s26. Uptimes 22–41 Tage.
✅ **Entwarnung, empirisch:** `s26` wurde kontrolliert neu gestartet und die Config **davor/danach
verglichen** — sie ist **identisch**. Der Flag stand fĂŒr **keine** abweichende Konfiguration; er ist
ein *sticky* Bit, das nur nie zurĂŒckgesetzt wurde. **Die GerĂ€te sitzen nicht auf versteckten
Änderungen.** Reboots können damit gefahrlos gebĂŒndelt mit TP17.1 laufen.
- 🔍 **Was `restart_required` gesetzt hat, ist am GerĂ€t NICHT rekonstruierbar** — drei Wege zu Ende
gegangen: (a) **169 RPC-Methoden** auf `s26`, keine gibt Auskunft ĂŒber Pending-Zustand; (b) der
**Config-Diff ĂŒber die Gruppengrenze trĂ€gt nicht** — die Gen3-Familie `S3PL-00112EU` hat *identische*
Configs, davon s6/s7/s10 flagged und s8/s11/s14/s15 sauber; (c) **kein persistentes GerÀtelog**
(`sys.debug.file_log.enable=false`, `/debug/log` ist ein Live-Stream ohne Ring-Puffer).
Ausgeschlossen sind immerhin `matter.enable`, `ble.rpc.enable`, `cloud`, `mqtt`, `ws` (trennen die
Gruppen alle nicht) — und **`eco_mode`** (s.o.). *Nicht erneut untersuchen; der Aufwand ist gedeckelt
und das Ergebnis negativ.*
#### Scope / Abgrenzung
- **Gehört hierher:** alles, was die Migration am **GerÀt** verstellt hat (eco_mode, statische IP,
AP-Anker) und was daraus an Fehlverhalten folgt.
- **Gehört nicht hierher:** die Funkumstellung selbst (**TP17.1**, verworfen) und das GerÀte-Passwort
(seit 2026-08-24 **TP30 Posten #3**, vormals TP17.2).
- 🔗 **Aber die Verzahnung mit TP17.1 ist der Hebel:** wenn ohnehin **alle** Shellys angefasst werden,
ist das der Moment, `eco_mode` **grundsÀtzlich** zu entscheiden statt gerÀtweise zu pflegen.
Christophs „ich muss vermutlich eh alle shellys neu machen" ist damit nicht Resignation, sondern der
effiziente Weg — nur eben **nach** dem Test, nicht davor.
- **Governance:** Shellys laufen **nicht** ĂŒber Nautobot GC (kein NetzgerĂ€t im GC-Sinn). Änderungen
ĂŒber `mcp/shelly/` bzw. direkte RPC. ⚠ `migrate.py` hat **kein** Kommando fĂŒr `eco_mode` — der
Sweep-Weg wĂ€re eine kleine ErgĂ€nzung ĂŒber denselben Pfad.
- **Abh.:** keine. **Blockt nichts.** Der Alltagsschaden ist seit 2026-08-23 behoben.
#### 📌 Was noch offen ist (Stand 2026-08-23, Folge-Session)
1. ✅ Tastentest `s26` — **erledigt, Doppeldruck weg.**
2. **Flotten-Entscheid `eco_mode` aus** fĂŒr die ĂŒbrigen ~20 GerĂ€te — **gebĂŒndelt mit TP17.1** wegen der
Funkbild-/Airtime-Wirkung (s.o.). Gehört Christoph.
3. **`migrate.py` um ein `eco`-Kommando ergĂ€nzen**, wenn 2. beschlossen wird — heute gibt es dafĂŒr
keinen Pfad im Werkzeug, der Sweep lief ad hoc.
4. Reboots der verbleibenden 13 `restart_required`-GerĂ€te — **gefahrlos** (empirisch an `s26` belegt),
deshalb kein eigener Termin, sondern Mitnahme bei TP17.1.
### 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). **Fund F ✅ aufgelöst (08-24, gerĂ€teseitig — kein Netzfehler)**, **5-GHz-Umfeldscan ✅ (08-24)**, Kanalplan fĂŒr AP 3 ✅ gerechnet. Offen nur noch die Umsetzung, wenn der dritte AP kommt. 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.
**Beide vormals offenen Punkte sind am 2026-08-24 abgearbeitet** — Fund F ist aufgelöst, der
5-GHz-Umfeldscan gefahren und der Kanalplan fĂŒr einen dritten AP gerechnet. **Was von TP25 bleibt,
ist Umsetzung bei Bedarf, keine offene Frage:**
1. ✅ **Fund F — GEMESSEN UND AUFGELÖST (2026-08-24): kein netzseitiges PhĂ€nomen.**
Kollektor am **Manager** (`/interface wifi registration-table`, 15-s-Takt, 29 Samples ĂŒber 7,7 min,
28 Clients), Rohdaten `docs/messdaten/tp25-fundf-20260824.log`. Von den drei Kandidaten sind **zwei
erledigt, einer bleibt** — und die zwei fielen ohne Wartezeit:
| Kandidat | Ergebnis | woran es hÀngt |
|---|---|---|
| **(b)** DHCP-`lease-time` gegen die Periode | ❌ **tot** | `dhcp-v30` fĂ€hrt **`lease-time=1d`** → Renew bei 12 h. Kann 5:05 nicht erzeugen. **Eine Abfrage, keine Messung.** |
| **(a)** periodischer VAP-Re-Apply | ❌ **tot** | Ein Re-Apply wirft **alle** Clients des VAP gleichzeitig. Auf `cap-wifi4-virtual1` standen zeitgleich **drei Clients bei 16 h 51 min** Uptime, 25 von 28 ĂŒber 6 h. Mit einem 5-Minuten-Takt ist das unvereinbar. |
| **(c)** das GerĂ€t selbst | 🟡 **bleibt** | Der einzige Client, der im Fenster ĂŒberhaupt neu verband. |
🔑 **Der entscheidende Punkt an der BeweisfĂŒhrung: dafĂŒr braucht es die vier Zyklen nicht.** Ein
einziges Sample mit **16 h 51 min Uptime auf genau dem VAP**, der angeblich alle 5:05 abwirft,
widerlegt (a) vollstĂ€ndig. Die FensterlĂ€nge begrenzt nur, was man ĂŒber *abwesende* GerĂ€te sagen kann.
🔮 **Und genau die sind abwesend: die beiden Fund-F-MACs gibt es gerade nicht.**
`38:A5:C9:C0:73:1E` (`10.40.30.178`) und `38:A5:C9:BC:33:31` (`10.40.30.179`) stehen in `/ip arp` auf
**`status=failed`**, haben **keine DHCP-Lease**, stehen **nicht** in der Registration-Table und sind
**auch HA unbekannt** (kein `device_tracker` zu diesen MACs). ⇒ **Das PhĂ€nomen ist an diesen GerĂ€ten
derzeit nicht reproduzierbar, weil die GerÀte weg sind.**
📌 **Merkregel — dieselbe wie beim P750W:** bevor ein periodisches Trennen als Funk- oder
Konfigurationsfehler untersucht wird, **erst prĂŒfen, ob die betroffenen GerĂ€te ĂŒberhaupt da sind.**
Beim Drucker war die Fehldiagnose „Power-Save", hier wĂ€re sie „VAP-Re-Apply" geworden.
⇒ **Fund F wird geschlossen:** was auch immer der 5:05-Takt war, er lag **gerĂ€teseitig**, und die zwei
betroffenen GerÀte sind vom Netz. Netzseitig ist nichts zu tun. **Nicht erneut aufgreifen**, solange
`.30.178`/`.179` nicht wieder da sind *und* das Muster erneut gemessen wird.
🟡 **Nebenbefund mit Substanz — der DTU ist der einzige Wackelkandidat, den es wirklich gibt.**
`54:F2:9F:12:51:F0` (DTU/Wechselrichter, auf `cap-wifi4-virtual1` = **ap1**) war der **einzige** Client
mit einem Uptime-RĂŒcksetzer: 43 min Sitzung, dann weg fĂŒr ein Sample, dann wieder da — **bei −52 dBm**,
also bei tadellosem Signal. Das ist derselbe Mechanismus, der schon die Transaktion
`TP17.1-dtu-pin-ap2` begrĂŒndet hat: **ein ESP hat EIN Radio, sein eigener AP und die STA-Verbindung
teilen sich den Kanal.** Periode hier 43 min, nicht 5:05 — es ist **nicht** Fund F, aber es ist echt.
⇒ Gehört zur ohnehin vorgesehenen Neubewertung des DTU-Pins, sobald der Kanalplan steht (s.o.).
<details><summary>📜 UrsprĂŒngliche Fund-F-Formulierung (2026-08-22)</summary>
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`).
</details>
2. ⚖ **Entscheidung 5 GHz auf 20 MHz** (statt heute 20/40) — **✅ 5-GHz-Umfeldscan durchgefĂŒhrt
2026-08-24, Empfehlung: NICHT verschmÀlern, Entscheidung an einen Auslöser hÀngen.**
⚠ **2,4 GHz NICHT vorschnell drosseln** — dort hĂ€ngen ~20 IoT-GerĂ€te.
**Messung** (`/interface wifi scan` **am Manager**, cap-wifi3 = ap1 / cap-wifi1 = ap2, 10–12 s):
| vom Radio auf | fremdes 5-GHz-Netz | Kanal | Signal | Abstand zum eigenen AP |
|---|---|---|---|---|
| **ap1** (5180/Ce) | `Drei_H288A_5G_acHG` | 5745/ac/**80 MHz** | **−86 dBm** | 19 dB darunter |
| **ap2** (5220/Ce) | `LiwestBB93-5G` | 5200/ac/**80 MHz** (Block 5180–5240) | **−89 dBm** | 24 dB darunter |
⇒ **Das 5-GHz-Band ist an beiden Standorten praktisch leer.** Genau **ein** Fremdnetz je AP, beide
rund 20 dB unter dem eigenen Pegel. Der Nachbar `LiwestBB93-5G` liegt mit 80 MHz zwar formal ĂŒber
**beiden** unserer Blöcke — bei −89 dBm ist das ohne Wirkung.
🎯 **Warum das gegen 20 MHz spricht — die zwei ĂŒblichen GrĂŒnde treffen hier nicht zu:**
- **Fremdinterferenz:** existiert nicht (−86/−89). Ein schmalerer Kanal hĂ€tte nichts abzuwehren.
- **SelbstĂŒberlappung:** existiert nicht. ap1 `5180/Ce` = ch36+40, ap2 `5220/Ce` = ch44+48 —
ĂŒberlappungsfrei (Fund C, 08-17).
- **Bleibt allein das +3 dB Link-Budget** — und das ist zum guten Teil **schon vorhanden**: in einem
40-MHz-BSS sendet die Ratenanpassung an schwache Clients ohnehin auf dem PrimÀrkanal in 20 MHz.
Den Ceiling zahlen aber **alle** Clients dauerhaft. **Der Nutzen geht an die, die ihn schon haben.**
- **Und es löst das gemessene Problem nicht:** die offenen Schwachstellen sind die
Redundanz-LĂŒcken (Schlafzimmer −84,6 / 38 %, Bad −82,3 / 24 %) **am Gegen-AP**. +3 dB macht aus
38 % Verlust keine 0 % — das ist eine Platzierungs-/AP-Zahl-Frage, keine Kanalbreiten-Frage.
🔑 **Der echte Auslöser ist die AP-Zahl, nicht die Interferenz** — und das ist der Grund, die
Entscheidung *jetzt* zu treffen statt sie offenzulassen. Beide KanÀle stehen hart in **Band A**
(`ch-5g-ap1`=5180, `ch-5g-ap2`=5220, kein `skip-dfs-channels`), und Band A hat unter ETSI genau
**4 × 20 MHz = 2 × 40 MHz**. Mit zwei APs ist es damit **exakt aufgebraucht**:
| Szenario | bei 40 MHz | bei 20 MHz |
|---|---|---|
| 2 APs (heute) | ✅ passt genau, ĂŒberlappungsfrei | ✅ passt, +3 dB, halber Ceiling |
| **3.–4. AP** | ❌ Band A voll ⇒ **nur mit DFS** (Band B ch52–64: Radar-Events, 60 s CAC) | ✅ 4 saubere KanĂ€le, **kein DFS** |
⇒ **Empfehlung: 20/40 MHz beibehalten.** Die VerschmĂ€lerung ist heute ein Preis ohne Gegenwert.
Sie wird **fĂ€llig, sobald ein dritter AP dazukommt** — dann lautet die Wahl nicht mehr „20 gegen 40",
sondern **„20 MHz flottenweit" gegen „DFS akzeptieren"**, und dafĂŒr ist 20 MHz die ruhigere Antwort.
Ein Zwischenweg existiert (ap1 behÀlt 40 MHz, AP 2+3 fahren 20 MHz auf 5220/5240) und braucht
ebenfalls kein DFS.
📌 **Damit ist dieser Punkt entscheidungsreif und an einen Auslöser gebunden statt offen.**
#### 📐 Kanalplan fĂŒr den dritten AP ▾ **gerechnet 2026-08-24, DFS vom User genehmigt**
> **User-Vorgaben (2026-08-24):** 20/40 MHz bleibt · **DFS ist genehmigt**, soll aber auf **ap1 oder ap2**
> liegen, nicht auf dem Neuen · der Neue ist ein **MikroTik-Deckenstrahler mit ax** · **möglicherweise
> kommt er an die Stelle eines der bisherigen APs** · der vorhandene Outdoor-AP bleibt konzeptionell außen vor.
**Das Kanalbudget unter ETSI (Indoor), als Rechnung statt als GefĂŒhl.** Ein 40-MHz-Block darf keine
Bandgrenze ĂŒberschreiten — `[48+52]` ist deshalb unmöglich, und daran hĂ€ngt die ganze Knappheit:
| Band | Frequenzen | KanÀle | 40-MHz-Blöcke | DFS | EIRP |
|---|---|---|---|---|---|
| **A** | 5150–5250 | 36/40/44/48 | **2** (`5180/Ce`, `5220/Ce`) | nein | 23 dBm |
| **B** | 5250–5350 | 52/56/60/64 | **2** (`5260/Ce`, `5300/Ce`) | **ja** + TPC | 23 dBm |
| **C** | 5470–5725 | 100–140 | **5** | **ja** + TPC | 30 dBm, outdoor erlaubt |
Heute belegen zwei APs mit 40 MHz **ganz Band A**. Genau das macht den dritten AP zur Bandfrage — und
mit genehmigtem DFS ist sie lösbar, ohne irgendwo auf 20 MHz zu gehen.
**Empfohlene Zuordnung (3 APs, alle 40 MHz):**
| AP | Rolle | Kanal 5 GHz | Band | DFS | 2,4 GHz |
|---|---|---|---|---|---|
| **cAP ax (neu)** | PrimÀr, beste Position | **`5180/Ce`** (36+40) | A | **nein** | 2437 (ch6) |
| **ap1** hAP axÂČ | SekundĂ€r | **`5260/Ce`** (52+56) | B | ja | 2412 (ch1) |
| **ap2** hAP axÂČ | SekundĂ€r | **`5300/Ce`** (60+64) | B | ja | 2462 (ch11) |
| — | **Ausweichspur, frei halten** | `5220/Ce` (44+48) | A | — | — |
- **Warum Band B und nicht Band C fĂŒr die zwei DFS-Radios:** gleicher 23-dBm-Deckel wie Band A (kein
Leistungssprung zwischen den APs) und **CAC 60 s statt 600 s** — die 10-Minuten-PrĂŒfung gilt im
Wetterradar-Bereich von Band C. Band C bleibt damit frei fĂŒr den Outdoor-AP, wo seine 30 dBm auch
hingehören.
- **Warum der Neue das nicht-DFS-Band bekommt:** DFS kostet **60 s CAC bei jedem Boot und jeder
Provisionierung** plus einen erzwungenen Kanalwechsel bei Radar-Erkennung. Diese Kosten gehören auf
die Radios, deren FlĂ€che von einem anderen AP mitgetragen wird — nicht auf den bestplatzierten.
Christophs Instinkt ist hier richtig.
- **2,4 GHz fĂ€llt nebenbei sauber:** ch1/6/11 ist mit drei APs erstmals vollstĂ€ndig ĂŒberlappungsfrei
möglich (heute 1/11 mit einer LĂŒcke in der Mitte).
🔮 **Zwei Fallen, ohne die der Plan teurer wird als er aussieht:**
1. **Eine hart gepinnte Frequenz macht DFS zum Single Point of Failure.** `ch-5g-ap1`/`-ap2` tragen heute
**je genau einen** Wert (`frequency=5180` bzw. `5220`). Bei einer Radar-Erkennung **muss** das Radio
den Kanal verlassen — hat es keinen zweiten konfiguriert, bleibt das 5-GHz-Funk dieses APs **unten**.
⇒ FĂŒr DFS gehört in das Channel-Objekt eine **Liste** (z.B. `frequency=5260,5280,5220`), damit der AP
neu wĂ€hlen kann. Das ist der Unterschied zwischen „DFS ist unkritisch" und „DFS kostet einen AP".
2. **Vor dem Umzug die *erreichte* Sendeleistung messen — das ist Fund B, nochmal.** Band B/C verlangen
TPC; ohne TPC sinkt der erlaubte EIRP um 3 dB. TP25 Fund B war exakt dieses Muster: **18 dBm gesetzt,
9 dBm gesendet**, weil ch149 unter ETSI leistungsbegrenzt ist. ⇒ **Diskriminierender Test, bevor
irgendwas gekauft oder umgezogen wird:** ap2 testweise auf `5260`, dann `/interface wifi monitor`
lesen und die tatsÀchliche `tx-power` gegen die heutigen 18 dBm auf `5220` stellen. Kostet eine
Config-Transaktion und zehn Minuten, und entscheidet, ob der Plan trÀgt.
⚖ **Zur Platzierung — die Messung widerspricht dem Aufstellen an einer bisherigen Stelle.**
Die Referenzmessung vom 08-22 sagt: **17 von 21 Raumabschnitten haben 0 % Verlust.** ZusÀtzliche
*Abdeckung* ist damit wertlos. Der ganze Wert liegt im **Gegen-AP**: Schlafzimmer −84,6 / 38 %,
Bad −82,3 / 24 %, KĂŒche −82,0 / 23 %.
| Variante | was sie bringt |
|---|---|
| Neuer AP an **bisheriger** Stelle | besseres Deckenbild an einem Punkt, **der schon funktioniert**. Die Drei-Zimmer-LĂŒcke bleibt **unverĂ€ndert** — gleicher Standort, gleicher Schatten. |
| Neuer AP an **neuer** Stelle (Richtung Schlafzimmer/Bad/KĂŒche) | schließt die LĂŒcke, also genau die Redundanz, die gekauft werden soll. |
| 🎯 **Beides: cAP ax an die bisherige Stelle, der verdrĂ€ngte hAP axÂČ wandert in den Schatten** | bestes Deckenbild dort, wo die Clients sind, **und** eine zweite Option in den drei RĂ€umen. Braucht keine vierte Antenne, nur eine Steckdose/PoE im Zielraum. |
⇒ **Empfehlung: Variante 3.** Sie ist der einzige Weg, bei dem der Deckenstrahler an den guten Platz
darf, *ohne* dass die gemessene SchwÀche unangetastet bleibt.
- **Voraussetzung Neuer AP:** PoE-in am Zielort (die cAP-ax-Reihe hat einen Gigabit-PoE-Port, kein
Netzteil im Lieferumfang ĂŒblich) und ein Trunk mit VLAN 10/30/40/50/90/99 wie bei ap1/ap2. Der AP
lĂ€uft auf `wifi-qcom` und tritt damit als **regulĂ€rer CAP** dem Manager bei — kein neues Modell im GC,
nur ein weiteres GerĂ€t plus zwei `channel`-Objekte. ⚠ **Exaktes Modell vor dem Kauf prĂŒfen**
(`cAP ax` vs. `cAP XL ax`) — beide sind ax/wifi-qcom, unterscheiden sich in Abdeckung und Preis.
- **Wenn spÀter doch der Outdoor-AP dazukommt:** er gehört nach **Band C** (30 dBm, outdoor zulÀssig);
Band A/B sind dann von den drei Indoor-APs belegt und die Ausweichspur `5220/Ce` ist aufgebraucht.
**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 <if> !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 — vier Regeln, jede aus einem Fehlbefund geboren:**
- 🔮 **FĂŒr einen Kanal-/Umfeldscan NICHT `list_wifi_interfaces` benutzen** (Fund 2026-08-24): das Tool
gibt `security.passphrase` **aller** Profile im Klartext aus — ein Read fĂŒr die Kanalbreite hat so
fĂŒnf WLAN-Passphrasen in ein Transkript geschrieben, den IoT-PSK inklusive. FĂŒr KanĂ€le reicht
`/interface wifi channel print detail`; fĂŒr die `cap-wifiN`-Zuordnung `
 print where master=yes`
mit Feldauswahl. **Der Scan selbst (`/interface wifi scan`) ist unbedenklich.**
- 🔮 **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-<name>/` 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.**
<a id="tp30"></a>
### TP30 — Credentials: neu setzen & rotieren (Sammelbecken) ▾ 🔜 **ANGELEGT 2026-08-24, bewusst GEBÜNDELT gegen Projektende**
> **User-Entscheid 2026-08-24:** „ich wĂŒrde gerne daraus einen eigenen punkt machen. ich bin mir
> sicher, dass es noch öfters passwörter zu rotieren geben wird. das machen wir dann alles gegen
> projektende." — nachgeschĂ€rft am selben Tag: **„tp30 wird unser sammelbecken fĂŒr credentials,
> die neu gesetzt werden mĂŒssen"**, und **TP17.2 wandert hierher.**
>
> đŸ“„ **Scope ist damit breiter als „Rotation": jedes Credential, das neu gesetzt werden muss** —
> **Erstvergabe** (bisher gar keins vorhanden, z.B. Shelly `SetAuth`) **oder Rotation** (Wert
> verbrannt/abgelaufen). Die Trennung ist fĂŒr die PrioritĂ€t wichtig, fĂŒr die Arbeit nicht: der
> Kostentreiber ist in beiden FĂ€llen derselbe — die Konsumenten, nicht das Setzen.
> **Neue Credential-Aufgaben kommen ab jetzt hier hinein, nicht als eigenes TP.**
>
> **Warum ein eigener TP und nicht vier verstreute Follow-up-Zeilen:** die Rotationen teilen sich Werkzeug,
> Fallen und vor allem den **teuren Teil — den Konsumenten** (HA, Nautobot, MikroMCP, `~/.secrets`).
> Wer sie einzeln macht, zahlt den Re-Auth-Aufwand mehrfach. GebĂŒndelt ist es **ein** Durchgang je
> GerÀt. Deshalb steht hier die Liste, nicht der Termin.
- **Auslösekriterium (statt Datum):** wenn die offenen TPs abgearbeitet sind bzw. Christoph das
Projekt schließt. 🔮 **Harte Ausnahme, die den Termin vorzieht:** ein *neuer* Leak, ein
fremdzugĂ€ngliches GerĂ€t oder ein Personenwechsel — dann sofort und einzeln, nicht gebĂŒndelt.
| # | Credential | Umfang | Anlass | Vorarbeit | Preis der Rotation |
|---|---|---|---|---|---|
| 1 | **MikroTik `admin`** | core · branch · ap1 · ap2 (**ein** geteilter Wert) | 🔮 **zweimal in ein Transkript geraten** (2026-08-22 via `sshpass -p`; 2026-08-23 durch einen Enumerationsfehler) | ✅ **Etappe 1 durch** (s.u.) | nach Etappe 2 nur noch `~/.secrets/credentials.env` + `~/.claude.json` + MikroMCP-Neustart |
| 2 | **IoT-WLAN-PSK** (`sec-iot`) | `dirtyvader-iot`, 26 Clients | steht **im Klartext** im TP17-Text ⇒ auch in der **Git-Historie**; Redigieren holt ihn dort nicht raus | Hebel `multi-passphrase` am Core verifiziert vorhanden, Tabelle leer | 23 Shellys per Skript + **3 von Hand** (`.249` NSPanel Pro, `.244` Nuki Bridge, `.227` SwitchBot) |
| 3 | **Shelly-GerĂ€tepasswort** *(vormals TP17.2)* | 23 Shellys | HĂ€rtung (bisher **keine** Auth auf den GerĂ€ten) | ✅ Werkzeug fertig (`migrate.py cmd_auth` + Digest-Fallback) | **je GerĂ€t ein HA-Re-Auth-Flow** — das ist der Aufwand, nicht `SetAuth` |
| 4 | **CF-Access-Service-Token** (`CF_API_TOKEN`) | Cloudflare-Zugang, s. TP14.4 | ⏳ **lĂ€uft am 2027-01-09 ohnehin ab** — harter Termin, unabhĂ€ngig vom Projektende | Runbook liegt (`tp14.4-cf-access-token-runbook.md`) | Token neu ausstellen + `~/.secrets` nachziehen; **account-owned**, anderer verify-Endpoint |
> â„č **#3 war bis 2026-08-24 TP17.2** und ist jetzt vollstĂ€ndig hier (s. Detailabschnitt unten) —
> es benutzt denselben GerÀte-Durchgang wie #2, **ein Reboot statt zwei**. #4 gehört sachlich zu
> **TP14.4**, das als TP bestehen bleibt (dort steckt das CF-Access-Profil, nicht nur der Token).
#### Posten #1 im Detail — MikroTik `admin`: Radius, Etappe 1, Etappe 2
*Am 2026-08-24 aus den Follow-ups hierher gezogen — Text unverĂ€ndert ĂŒbernommen.*
**Vorgeschichte des Entscheids** (Stand bis 2026-08-23, User: „machen wir, aber erst spĂ€ter"):
⏭ ~~**Nachgelagert seit 2026-08-23: erst TP17.1, dann rotieren.**~~
**Revidiert noch am selben Tag (User): beides lÀuft PARALLEL.** Der Passphrase-Override je MAC
(s.u.) macht den Flag-Day ĂŒberflĂŒssig, damit war die Reihenfolge nie technisch nötig — nur
ökonomisch. Regel fĂŒr die ParallelitĂ€t: **ein GerĂ€t, das ohnehin auf Thread/Zigbee wandert,
bekommt den neuen PSK gar nicht**, sondern nur einen Übergangs-Eintrag in der `access-list`.
⚠ Der Entscheid betrifft **beide** Passwörter: der **IoT-WLAN-PSK** steht im Klartext im
TP17-Text ([Archiv](teilprojekte-archiv.md#tp17)) und damit auch in der Git-Historie — **bleibt
auf User-Entscheid 2026-08-23 vorerst unverÀndert**, weil Redigieren ihn nicht aus der Historie
holt und Rotieren heute ~22 Shellys kostet. ~~Nach TP17.1 sind es deutlich weniger.~~
🔮 **HinfĂ€llig seit 2026-08-23: TP17.1 ist verworfen** — die GerĂ€te bleiben WLAN-Clients, es
werden also *nicht* weniger. Die Rechnung „~23 Shellys + 3 FremdgerĂ€te" gilt unverĂ€ndert. 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.
#### 🔑 Radius-Befund 2026-08-23: das Admin-Konto teilen sich FÜNF Konsumenten
Vor dem Rotieren erhoben — das ist deutlich mehr als „vier GerĂ€te + eine Datei":
| Halter | Nachziehen |
|---|---|
| `~/.secrets/credentials.env` | Datei |
| `~/.claude.json` (MikroMCP-Env, `ROUTER_*`/`CRS326_*`) | JSON + MCP-Neustart |
| **Nautobot-Stack** `NAUTOBOT_ROUTEROS_USERNAME/PASSWORD` | Stack-Datei + **Portainer-Redeploy auf der DS923** |
| **HA: VIER `mikrotik`-Integrationen** (`.99.1/.2/.11/.12`, 40 `device_tracker`) | 🔮 **`supports_reconfigure: false` — NICHT skriptbar**, 4× Re-Auth von Hand |
| Repo-Skripte (`routeros/*.py`, `nautobot/*.py`, `docs/tp*.sh`) | ziehen aus `~/.secrets` → automatisch |
⇒ **User-Entscheid 2026-08-23: Konten trennen statt ein Passwort teilen.** Nicht das Rotieren ist
das Problem, sondern dass ein einziges `admin` von fĂŒnf Stellen benutzt wird — jede Rotation kostet
sonst wieder vier Re-Auths und einen Stack-Redeploy.
#### ✅ Etappe 1 DURCH (2026-08-23): dedizierte Service-Accounts auf allen vier GerĂ€ten
Rein **additiv**, kein laufender Dienst berĂŒhrt. Vorher existierte **nur** `admin` (Gruppe `full`).
| Gruppe | Policy | User | Zweck |
|---|---|---|---|
| `grp-ha` | `read,api,rest-api,test` | `ha` | HA-Mikrotik-Integration, **lesend** ĂŒber API 8728 |
| `grp-nautobot` | `ssh,read,write,test,sensitive` | `nautobot` | Golden Config ĂŒber SSH/Netmiko (Backup **und** Deploy) |
Passwörter: `MIKROTIK_HA_PASS` / `MIKROTIK_NAUTOBOT_PASS` in `~/.secrets/credentials.env`
(32 Zeichen, je Dienst eigen, gerĂ€teĂŒbergreifend gleich).
🔒 **Angelegt ĂŒber ein Skript, das die Werte aus der Datei liest** — bewusst *nicht* ĂŒber
`manage_user`, dessen `password`-Parameter im Sitzungstranskript landen wĂŒrde.
**Abnahme, auf allen vier GerĂ€ten geprĂŒft:**
- `ha` liest (`identity`, `dhcp-lease` — am Core 59 EintrĂ€ge, genau was das Device-Tracking braucht),
**Schreibversuch wird abgewiesen**.
- `nautobot` meldet sich per SSH an und exportiert; **kein REST** (bewusst kein `rest-api` in der Policy).
- 🎯 **Der Export von `nautobot` ist byte-identisch zu dem von `admin`** (391/56/87/87 Zeilen je GerĂ€t)
⇒ **die GC-Compliance driftet beim Umstellen nicht.** Das war das Hauptrisiko dieser Etappe.
- `/user` wird von **keiner** ComplianceRule abgedeckt ⇒ die neuen Konten erzeugen selbst keinen Drift.
#### ⏭ Etappe 2 offen — die Konsumenten umhĂ€ngen, DANN `admin` rotieren
1. **Nautobot** auf `nautobot` umstellen (Stack-Env + Portainer-Redeploy), GC-Backup-Lauf als Abnahme.
2. **HA**: die vier `mikrotik`-EintrĂ€ge auf den `ha`-User bringen. ⚠ Reconfigure ist nicht skriptbar;
Entfernen-und-neu-Anlegen **wÀre** skriptbar, riskiert aber die 40 `device_tracker`-Entity-IDs
(sie leiten sich aus der MAC ab, kĂ€men also gleich zurĂŒck — **aber erst nachdem** die alten
Registry-EintrÀge weg sind, sonst hÀngt HA ein `_2` an; dieselbe Falle wie beim Shelly-Rename).
3. **Erst danach** `admin` rotieren — dann berĂŒhrt es nur noch `~/.secrets` + `~/.claude.json`.
🔮 **Eigener Fehler, protokolliert:** beim Erheben des Radius hat ein `json.dumps`-Aufruf ĂŒber
`~/.claude.json` das **ap1-Passwort im Klartext ins Transkript geschrieben**. Da alle vier GerÀte
dasselbe `admin`-Passwort teilen, ist es **derselbe Wert, der am 2026-08-22 bereits verbrannt ist** —
keine neue Expositionsklasse, aber ein zweiter Beleg dafĂŒr, dass die Rotation fĂ€llig ist.
**Merkregel: Secrets-Enumeration gibt nur SchlĂŒsselnamen aus, nie Werte** — auch nicht abgeschnitten.
✅ **Vorbedingung erfĂŒllt, geprĂŒft 2026-08-23:** alle vier
Skripte laufen auf `sshpass -e` (`tp6-marker/server.py`, `tp6-monitor-core.sh`,
`tp25-walk-messung.sh`, `tp25-pin-s22.sh`) — die frĂŒhere Notiz, zwei davon hĂ€tten die SchwĂ€che
noch, war veraltet. Übrig blieb nur **`CLAUDE.md`, das `sshpass -p` weiterhin aktiv als Reboot-Weg
empfahl** — am 2026-08-23 auf `sshpass -e` korrigiert. **Damit ist die Rotation ohne RĂŒckfallgefahr
fahrbar.**
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.
- 🔎 **Nachtrag 2026-08-23 (Recherche-Session, read-only — kein Eingriff): der PSK in der Doku ist
noch der LIVE konfigurierte.** GegengeprĂŒft am Manager `crs326-core` (`/interface wifi security`,
Profil `sec-iot` → `cfg-iot` → SSID `dirtyvader-iot`, `datapath.vlan-id=30`,
`wpa2-psk,wpa3-psk`) — und zwar **per Fingerprint statt Klartext** (LĂ€nge + drei Zeichenpaare),
damit der Wert nicht ein zweites Mal in ein Transkript wandert. **Diese Methode ist die Merkregel
daraus:** einen Verdacht auf Übereinstimmung prĂŒft man mit Stichproben, nicht durch Ausgeben.
- ✅ **User-Entscheid 2026-08-23 zur Git-Historie: belassen, im Nachtrag dokumentieren** — **kein**
`git filter-repo`. BegrĂŒndung trĂ€gt: genau **eine** getrackte Fundstelle
([Archiv](teilprojekte-archiv.md#tp17)), drei Commits (`e76289c` Ersteintrag 2026-07-11,
`f0d1ff9` 08-08, `7ee64b5` Doku-Split 08-23), Remote **ausschließlich** `gitea.emsenhuber.net`,
**ein** lokaler Klon. Eine History-Rewrite hÀtte hier also nichts gerettet, was nicht ohnehin nur
auf der eigenen Infrastruktur liegt — und den Preis (alle Hashes neu) fĂŒr nichts bezahlt.
- 📊 **Warum die Rotation heute teuer ist — live gemessen 2026-08-23:** **26 der 27 WLAN-Clients des
gesamten Netzes hÀngen auf `dirtyvader-iot`** (`dirtyvader-main` 1, MEDIA/UNTRUSTED/GUEST je 0).
VLAN30 fĂŒhrt **41 Leases/Reservierungen** (5 aktuell `bound`, der Rest sind statische
Reservierungen ausgeschalteter GerÀte). Neben den ~26 Shellys hÀngen dort **P750W** (Drucker),
**Airfryer** (`espressif`, `.180`), **SwitchBot floor-lamp**, **Twinkly** `.228`, **DTUBI** `.8`,
**SONOFF-NSPanelPro** und ein **iPhone** `.177`. ⇒ Ein Passwortwechsel ist heute eine
Batch-Aktion ĂŒber ~26 GerĂ€te, und **das ist genau die Rechnung, die TP17.1 verkleinert.**
- 🔧 **Zwei Umsetzungshinweise fĂŒrs spĂ€tere Rotations-Paket:**
**(a)** `mcp/shelly/migrate.py` hat **kein** Rotate-Kommando (nur `migrate`/`deanchor`/`auth`/
`table`) — es brĂ€uchte eine kleine Variante ĂŒber denselben `set_sta`-Pfad.
**(b) Ein Flag-Day ist vermeidbar:** RouterOS 7 kann in `/interface wifi access-list`
**Passphrase-Overrides je MAC**. Also neuer PSK aufs Profil, AltgerĂ€te ĂŒbergangsweise per MAC mit
dem alten weiter, danach die Liste leeren. 💡 Nebeneffekt: der TP25-Befund „keine `access-list`"
bekĂ€me damit endlich einen Zweck — und seit dem 08-23 gibt es die ComplianceRule
`wifi-access-list`, die EintrÀge dort auch sichtbar macht.
- **Mitzuziehen bei der Rotation** (legitime, gitignorete Ablagen desselben Werts):
`~/.secrets/credentials.env` (+ `.bak-20260808`), `routeros/.secrets/wlan-psks.env`,
`mcp/shelly/.env`.
- **CF-Access-Service-Token** — **Rotationsposten #4**, am 2026-08-24 aus den Follow-ups hierher
gezogen (stand dort als „TP14.4 — CF-Access-Service-Token rotieren"). Sachlich gehört er zu
**TP14.4** (CF-Access-Profil fĂŒr Claude, Runbook `docs/tp14.4-cf-access-token-runbook.md`); hier
steht er, damit die Rotationsliste vollstĂ€ndig ist. ⚠ Der `CF_API_TOKEN` lĂ€uft ohnehin
**2027-01-09** ab — spĂ€testens dann ist dieser Posten fĂ€llig, unabhĂ€ngig vom Projektende.
#### Posten #3 im Detail — Shelly-GerĂ€tepasswort (`SetAuth`), vormals TP17.2
*Am 2026-08-24 als eigenes TP aufgelöst und hierher gezogen — Text unverĂ€ndert ĂŒbernommen.*
> **User 2026-08-23:** „außerdem haben wir einen punkt, um die shellys mit einem pwd zu schĂŒtzen."
> Damit ist der ZurĂŒckgestellt-Status von 2026-07-13 aufgehoben. **BegrĂŒndung der Kopplung:** die
> PSK-Rotation fasst ohnehin jeden Shelly an und rebootet ihn — `SetAuth` gehört in denselben
> Durchgang, ein Reboot statt zwei.
>
> ✅ **Werkzeugseitig ist nichts zu bauen:** `mcp/shelly/migrate.py` hat `cmd_auth` (setzt
> `Shelly.SetAuth` mit SHA-256-`ha1` gegen die GerÀte-`realm`, Dry-Run als Default), und `_rpc` hat
> einen **Digest-Auth-Fallback** auf 401 mit `SHELLY_DEVICE_PW`.
>
> 🔮 **Der teure Teil ist nicht `SetAuth`, sondern Home Assistant.** Mit aktiver Auth verlangt die
> Shelly-Integration je GerĂ€t einen **Re-Auth-Flow** — bei 23 GerĂ€ten ist *das* der Aufwand, und genau
> der Grund fĂŒr die frĂŒhere Einstufung als „Kosmetik". ⇒ **Erst an EINEM GerĂ€t machen und den
> HA-Aufwand messen** (Vorschlag `s15 technik_pve`, RSSI −36, unkritisch), bevor der Rest folgt.
> Sonst bĂŒndelt man ein ungemessenes Risiko in eine 23-GerĂ€te-Aktion.
<details><summary>UrsprĂŒnglicher Text (historisch)</summary>
- **Was:** je GerÀt `Shelly.SetAuth` (User `admin`, realm-individueller `ha1` = sha256("admin:<device-id>:<pw>"), 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.
</details>
#### 🔮 Neues Leak-Ereignis 2026-08-24 — der IoT-PSK ist erneut exponiert
Beim 5-GHz-Umfeldscan fĂŒr TP25 wurde `mcp__mikromcp__list_wifi_interfaces` gegen den Manager gefahren,
um die `cap-wifiN`-Zuordnung zu bestimmen. **Das Tool gibt `security.passphrase` aller Profile im
Klartext zurĂŒck** — damit stehen **alle fĂŒnf WLAN-Passphrasen** (`main`, `iot`, `media`, `untrusted`,
`guest`) in einem Sitzungstranskript. Kein Werkzeug hat versagt; es war das falsche Werkzeug fĂŒr eine
Kanalabfrage. **Betrifft Posten #2 (IoT-PSK) und zusÀtzlich vier bisher unverbrannte Passphrasen.**
⚖ **Nach der „harten Ausnahme" oben ist das ein Vorziehgrund** — Entscheidung gehört Christoph.
Gegenargument, das dieselbe Rechnung wie am 08-23 ergibt: der IoT-PSK lag ohnehin schon im Klartext
in der Git-Historie, neu exponiert sind vor allem `main`/`media`/`untrusted`/`guest` — und die kosten
beim Rotieren **wenige** Clients, nicht 26. ⇒ **`main` und `guest` wĂ€ren billig und einzeln machbar,
unabhĂ€ngig vom gebĂŒndelten Durchgang.**
#### Fallen, die fĂŒr jedes Setzen/Rotieren gelten (nicht neu erheben)
- 🔮 **Kein Read auf `/interface/wifi`, wenn nur KanĂ€le/Interfaces gebraucht werden** —
`list_wifi_interfaces` liefert alle Passphrasen im Klartext mit (Leak vom 2026-08-24, s.o.).
Feldauswahl benutzen oder `/interface wifi channel print detail`.
- 🔮 **Niemals `sshpass -p`** — schreibt das Passwort in die Kommandozeile, sichtbar in `ps` und in
jedem argv-Trace. **Genau so entstand Leak #1.** `-e` hÀlt es in der Umgebung des Kindprozesses.
Der Repo-Stand ist bereits durchgÀngig `-e`.
- 🔮 **Passwörter nie per MCP-`password`-Parameter setzen**, sondern per Skript aus `~/.secrets`
(`manage_user set-password`; `/user set*` ist per Deny-Policy blockiert).
- 🔮 **Keine Secrets-Enumeration im Transkript** — das war Leak #2, ohne dass irgendein Werkzeug
fehlerhaft war.
- 🔒 **`wifi-security` ist als ComplianceRule grĂŒn, aber NICHT deploybar** (Passphrasen stehen als
`<<REDACTED>>` im Template). Ist-Stand fĂŒr #2 immer per REST vom GerĂ€t lesen
(`GET http://10.40.99.1/rest/interface/wifi/security`), **nie** aus `wlan-psks.env`.
- ⚠ **CAPsMAN, fĂŒr #2:** eine ProfilĂ€nderung wirkt erst nach `remote-cap provision` fĂŒr **beide**
APs — und die Abnahme ist eine **frische DHCP-Lease je SSID**, nicht die Registration-Table.
- ⚠ **FĂŒr #2 zuerst `multi-passphrase` gegen WPA3/SAE testen — auf einer Wegwerf-SSID, nie an
`dirtyvader-iot`.** `sec-iot` fÀhrt `wpa2-psk,wpa3-psk`; trÀgt multi-passphrase SAE nicht, sperrt
man **26 IoT-GerÀte auf einmal** aus, inklusive Nuki und NSPanel.
- ⚠ **`s1`/`s2`/`s3` sind ausgesteckt** und kommen im Dezember mit dem **alten** PSK zurĂŒck — der
Übergangs-Eintrag muss sie ĂŒberleben oder sie werden bei RĂŒckkehr von Hand nachgezogen.
- 🔮 **HA- und Repo-Nummerierung der Shellys weichen ab** (`s10`, `s17`) — **immer ĂŒber MAC/IP
zuordnen, nie ĂŒber die s-Nummer.**
- **Abh.:** keine harten; #2 und #3 laufen sinnvollerweise in **einem** GerÀte-Durchgang.
**Blockiert nichts.** Die frĂŒhere Kopplung „erst TP17.1, dann rotieren" ist **gegenstandslos** —
TP17.1 ist am 2026-08-23 verworfen, die GerÀte bleiben WLAN-Clients.
<a id="tp31"></a>
### TP31 — Reverse Proxy fĂŒr innen und außen; cloudflared von sechs Knoten auf einen ▾ 🔜 **GEPLANT 2026-08-25**
> **Auslöser (User 2026-08-24):** „ich weigere mich, fĂŒr public applications 2 cloudflare container zu
> installieren. 
 ich habe [den Core] unter der prĂ€misse gekauft, dass ĂŒber diesen dann auch die public
> apps laufen können. wir wollten doch den core als single point of failure platzieren."
#### Der Vorwurf, fair geprĂŒft
Eine schriftliche Zusage, dass die Public-Apps auf den Core wandern, existiert **nicht** —
[TP16.1](teilprojekte-archiv.md#tp16-1) ist durchgehend auf den *privaten* Zugang zugeschnitten und hÀlt
mehrfach fest, dass „der cloudflared-Public-Teil unberĂŒhrt blieb". **Aber der Vorwurf trifft trotzdem
etwas Richtiges:** dasselbe Dokument begrĂŒndet die gesamte Auswahl mit **Christophs** Prinzip —
*„Router = einziger SPOF, keine AbhĂ€ngigkeit zu anderen Rechnern"* — und **niemand hat je geprĂŒft, ob der
öffentliche Strang ohne sechs Container auskommt.** Keine TĂ€uschung, aber eine **ungeprĂŒfte Annahme**.
#### Die Lösung ist nicht „raus aus Cloudflare", sondern „ein Knoten statt sechs"
**Caddy** als Reverse Proxy fĂŒr **innen und außen**, `emsenhuber.net` in beiden Richtungen, plus **ein**
cloudflared als Tunnel-Endpunkt.
- ⚖ **Erst geprĂŒft, dann verworfen: der Weg ĂŒber `dst-nat`.** Der Core hĂ€lt `90.146.33.177` direkt ohne
CGNAT, Liwest lĂ€sst eingehend alles durch (User: „hatte frĂŒher schon nginx hier laufen"), und
Origin Rules (Ziel-Port, **Free = 10 Regeln**), die CF-HTTPS-Ports (`443, 2053, 2083, 2087, 2096, 8443`)
sowie Authenticated Origin Pulls sind alle im Free-Tarif enthalten. Es **ginge** also ohne jeden Container.
- 🎯 **Christophs Einwand ist der bessere Weg:** *„caddy muss so oder so. nachdem dieser vorhanden ist,
fahren wir natĂŒrlich ĂŒber zero trust apps. noch etwas sicherer, aber kein zusĂ€tzlicher knotenpunkt,
der ausfallen kann."* Der Tunnel spart drei Risiken auf einmal: **keine angreifbare Origin-IP, keine
CF-IP-Allowlist, kein DDNS als Voraussetzung** (der TP10-Updater bliebe sonst zwingend).
#### Zielbild
```
Internet ─â–ș Cloudflare (Access, WAF) ─â–ș Tunnel »bf-public« ─â–ș cloudflared auf ap1/ap2
WARP ─â–ș cf-mesh (nativ am Core, kein Container) ─┐
LAN ─â–ș Split-Horizon-DNS ───────────────────────┮─â–ș Caddy (LXC 130, 10.40.20.40)
└─â–ș alle Dienste per Host-Header
```
**Öffentlich bleiben vier:** `vw` (Bitwarden-Clients), `hass` (Companion-App), `n8n` (Webhooks Dritter),
`gitea` (Access **nur fĂŒr die Web-UI**, Git-/API-Pfade daran vorbei ⇒ **Push ohne WARP bleibt**).
Alles andere ist intern; **19 Ingress-Zeilen ĂŒber drei Tunnel werden EINE Catch-all-Regel auf Caddy.**
#### Wo cloudflared lĂ€uft — und warum die APs (live gemessen 2026-08-24/25)
| GerÀt | Arch | Flash frei | RAM frei | Container? |
|---|---|---|---|---|
| **ap1 / ap2** (hAP axÂČ) | **arm64** | **95 MB / 128 MB** | **690 MB / 1 GB** | ✅ ja |
| **crs326-core** | arm **32-bit** | **2,9 MB / 16 MB** | 512 MB | ❌ **nie** |
- ✅ **Christophs Argument, das den Ausschlag gibt:** *„cf auf den aps hat den vorteil, dass wir gegenĂŒber
unseren hosts/container nicht blind sind."* — Der AP ist eine **eigene Maschine**, kein Docker-Host;
die macvlan/ipvlan-Blindheit kann dort **prinzipiell** nicht auftreten. Kein anderer Ort hat das.
💡 Daraus folgt eine Reserve: fĂ€llt Caddy aus, kann derselbe Connector ĂŒber eine zweite Ingress-Regel
**direkt** auf ein, zwei kritische Backends zeigen.
- 🔮 **Ehrliche EinschrĂ€nkung:** cloudflareds einziges Origin ist Caddy. Solange Caddy auf pve liegt,
kauft ein Connector auf dem AP **Hardware-DiversitĂ€t, aber keine VerfĂŒgbarkeit** — fĂ€llt pve aus, ist
alles weg. Der echte Gewinn kommt erst mit `caddy-bf2` (LXC 131).
- **Caddy oder AGH zusĂ€tzlich auf die APs? Nein.** 95 MB minus RouterOS-Reserve fĂŒrs eigene `.npk`
(~20 MB) = **ein Container pro AP**. Kriterium, das auch kĂŒnftig trĂ€gt: **auf die Infrastruktur darf,
was sich selten Ă€ndert und wenig schreibt** — cloudflared ja (Config liegt in Cloudflare, schreibt
nichts); **Caddy nein** (Caddyfile Àndert sich bei jedem neuen Dienst); **AGH nein** (Query-Log
schreibt dauernd → NAND-Verschleiß).
- ⚠ **Preis:** `container` verlangt eine **`device-mode`-Änderung mit physischer BestĂ€tigung** am GerĂ€t
(ap1 Technik UG, ap2 Technik OG). Und der AP bekommt eine zweite Rolle neben dem WLAN.
#### Umsetzung
1. **Leichen löschen:** `120 adguard-bf1`, `121 adguard-bf2`, `128 nginx-proxy-manager`, `129 caddy`,
`130 pihole1`, `131 pihole2` — alle `stopped`, alle auf **totem VLAN1** (`10.40.41.116/.117`,
GW `.41.254`), `onboot: 0`. ⚠ `130`/`131` **mĂŒssen** weg, bevor die neuen Nummern vergeben werden.
**Alte Backups radieren** (Job `backup-6dcf5c10-610f`, So 01:00, Storage `pbs`, fĂŒhrt heute `120`
und `128`), **`130` neu aufnehmen — derselbe Job.**
2. **LXC 130 `caddy-bf1`** neu anlegen: VLAN20 `tag=20`, `10.40.20.40/24`, GW/DNS `10.40.20.1`,
**`onboot: 1`**, ~4 GB / 512 MB. *(Neu bauen statt umkonfigurieren — die Altlasten sind
Helper-Script-AdGuard-Container und wĂŒrden auf Jahre eine falsche IdentitĂ€t fĂŒhren.)*
3. **Caddy mit Cloudflare-DNS-Modul** → **DNS-01**, damit auch rein interne Namen echte Zertifikate
bekommen. 🔑 **Eigenes, eng geschnittenes Token** (`Zone:DNS:Edit` nur auf `emsenhuber.net`), **nicht**
das account-weite `CF_API_TOKEN` ⇒ neuer Posten fĂŒr **TP30**.
4. **Split-Horizon**: Service-FQDNs → Caddy. 🔗 **Vorher entscheiden: Core (`/ip dns static`) oder
AdGuard?** Sobald AGH nach **TP23 Stufe 2** scharf ist, gehören die EintrĂ€ge dorthin — sonst zweimal gebaut.
5. **Tunnel `bf-public`** + Connectoren auf ap1/ap2, CNAMEs umhĂ€ngen (`n8n` → `gitea` → `hass` → `vw`).
6. **Abbau:** `bf-nas`/`bf-pve`/`bf-mm` löschen, sechs Container weg, SSH-Browser-Rendering entfÀllt,
**MCP-Clients auf FQDN umstellen** (`~/.claude.json` spricht heute `10.40.20.105:9583` und
`10.40.20.173:3000` roh; `n8n-mcp`/`gitea-mcp` kommen dabei wieder in Betrieb).
🎯 **Kernabnahme: WAN trennen, dann alle Dienste per FQDN.** Das ist die Autarkie, um die es geht.
⚠ **Preis, offen benannt:** mit Split-Horizon greift **Access innerhalb des Netzes nicht mehr**; dort
tragen TP5-Segmentierung und die App-eigene Auth.
#### HA-Ausblick (nicht Teil der Umsetzung)
**Es bleibt bei Caddy** — zustandslos bis auf den Zertifikatsspeicher, identisches Caddyfile je Instanz,
versionierbar; NPM hĂ€tte eine Datenbank, die man mitreplizieren mĂŒsste.
🔮 **Prinzip fĂŒr `vw`: der Eingang darf nicht klĂŒger sein als die Datenbank.** [TP20.1](#tp20-1) sieht
**manuelles Promote** vor. Zwei Connectoren auf **verschiedene** Caddys an verschiedenen Standorten
wĂŒrden die HĂ€lfte der **Schreib**zugriffe auf einen read-only Standby schicken — das #1033-Muster,
diesmal mit Datenverlust statt 530ern. **Automatisches Ingress-Failover erst, wenn der DB-Teil es trÀgt**
(User: vertagt bis TP20.1 Phase 1+2 laufen).
- **Abh.:** [TP32](#tp32) (Nummern/IPs — vergibt `130`/`.40`), TP16.1 ✅ (Mesh), **TP23 Stufe 2**
(Split-Horizon-Ort). **Löst ab:** TP16 (reziprokes HA) und **TP16.2** (der `vw`-bypass-Strang bekommt
mit Caddy + CF davor einen anderen Schutz). **TP16.3 ist der Pilot dieses TP.**
- 📋 **VollstĂ€ndiger Plan mit allen AbwĂ€gungen:** `~/.claude/plans/expressive-pondering-clarke.md`
<a id="tp32"></a>
### TP32 — Nummern- und Adress-Systematik ▾ 🟱 **KONZEPT STEHT (2026-08-25), Startreihenfolge bereits repariert**
> **User-Auftrag 2026-08-24:** „du/ich sollst in der lage sein, selbststĂ€ndig nach einem vorgegebenen
> system freie ips vergeben zu können 
 und diese systematik findet sich in anderen netzen kĂŒnftig auch
> wieder" · „ich meine 100 sollte kĂŒnftig fĂŒr die core services stehen."
>
> **Eigener TP, weil es eine Konvention ist, kein Bauteil** — TP31 ist ihr erster Kunde.
> **Regel: Bestand bleibt, wo er ist; jeder NEUE Gast folgt der Systematik.**
🔑 **Ein gemeinsamer VMID-Raum fĂŒr VMs *und* LXCs.** `100 haos` und `330 RaspberryMatic` sind **VMs** —
die Klasse bestimmt die Nummer, nicht die Virtualisierungsart.
| Kreis | Klasse | heute dort (VM *kursiv*) |
|---|---|---|
| **100–199** | **Core / Infrastruktur** | `108 mcast-relay` |
| **200–299** | **Daten / DBs** (Precious-Tier) | *(`105`, `106`, `107`, `302` → spĂ€ter hierher)* |
| **300–399** | **Security / Identity** | — |
| **400–499** | **Platform / Runtime** | ✅ `400 docker` passt bereits |
| **500–599** | **App-Services / Smart Home** | `101`, `102`, `112`, `150`, *`100`*, *`330`* → spĂ€ter hierher |
| **600–699** | **Business / ERP** | `201 openproject` |
| **700–799** | **KI / ML** | — |
| **800–899** | **Dev / R&D / Test** | — |
| **900–999** | **Ephemeral / Scratch** | wird ungefragt gelöscht |
**Zehnerschritte innerhalb eines Kreises** („Respektabstand", User), damit Instanzen und Nachbarn Platz
haben: `100–109` netznah · **`110–119` DNS** · **`130–139` Reverse Proxy** · `150–159` Monitoring ·
`170–179` PKI/Zeit. ⇒ **AGH `110`, Caddy `130`.**
**Letztes Oktett je /24 — gilt in jedem VLAN, an jedem Standort:**
| Oktett | Rolle | Anker heute |
|---|---|---|
| `.1–.9` | Gateways / L3 | `.1` je VLAN ✅ · `99.1` core, `99.2` branch ✅ |
| `.10–.29` | physische Hosts (Storage, Hypervisor, APs) | NAS `20.10` ✅ · APs `99.11/.12` ✅ |
| `.30–.99` | virtuelle Core-Services, Zehnergruppen wie oben | DNS `.3x` · Ingress `.4x` · DBs `.5x` · Security `.6x` · Monitoring `.7x` |
| `.100–.199` | App-Services | |
| `.200–.249` | DHCP-Pool | |
| `.250–.254` | VIPs / Relays | |
🔑 **Der Merk-Trick: die Zehnergruppe im Oktett spiegelt die der VMID.** `110 agh` → `.3x`,
`130 caddy` → `.4x`. Wer eine Zahl kennt, kennt die Klasse der anderen.
#### Warum der Bestand anders aussieht — er war nicht falsch, nur auf einer anderen Achse
**User 2026-08-25:** „zuerst war haos, welches mit 100 den nummernkreis fĂŒr iot eröffnet hat. und die
anderen 
 gehörten zu ha, daher 1xx. erst spĂ€ter habe ich erfahren, dass die nummer die
startreihenfolge definiert."
⇒ Der Bestand gruppiert nach **Zugehörigkeit**, die neue Systematik nach **Klasse**. Beide Achsen sind
legitim; die zweite ist die, die das System auswertet. Der alte `1xx`-Block ist der **Smart-Home-Block**
und wandert spÀter als Gruppe nach `5xx`.
#### ✅ ERLEDIGT 2026-08-25: die Startreihenfolge war nachweislich falsch
🔮 **Und der Hebel ist NICHT die VMID.** Drei GĂ€ste hatten ein explizites `startup: order=`
(`101 iob-master` 110, `102 mqtt5` 120, `100 haos` 125), alle ĂŒbrigen keines. **Proxmox startet erst
alle GĂ€ste mit `order=`, dann den Rest nach VMID** — real lief also `iob-master → mqtt5 → haos` und
**erst danach** `platform-pg`, `mariadb`, `z2m25`, `docker`.
⇒ **Home Assistant startete vor seiner eigenen Datenbank.**
**Repariert (wirkt beim nÀchsten pve-Neustart):**
| `order=` | Stufe | GĂ€ste |
|---|---|---|
| 10 | Core | `108 mcast-relay` |
| 20 | Daten | `105 platform-pg` (`up=15`), `302 mariadb` (`up=15`), `106 influxdb2`, `107 redis` |
| 30 | Platform | `400 docker` (`up=20`) |
| 40 | Broker / Funk | `102 mqtt5` (`up=10`), `112 z2m25`, `330 RaspberryMatic` |
| 50 / 51 | Anwendungen | `101 iob-master`, **`100 haos`**, `150 iob-exposed` |
🎯 **Die wichtigste Erkenntnis des TP: VMID = Klassifikation, `startup: order=` = AbhĂ€ngigkeitsreihenfolge.**
Die Umnummerierung muss die Startreihenfolge gar nicht reparieren — das ist bereits erledigt, ohne eine
einzige ID zu Àndern. **Die Nummernkreise sind damit reine Ordnung und Lesbarkeit**, und der Bestand
kann in Ruhe nachziehen.
- **Offen:** Migration des Bestands (Tabelle oben) — *am Ende der Reise, nicht jetzt*. Und die
Kollision **AGH will `.30`, dort sitzt Nautobot** (`.31` = nautobot-worker) ⇒ Vorschlag `.36` als
Interim, `.30` erst nach dem Nautobot-Umzug in den App-Bereich. **FĂ€llt vor dem AGH-Neubau an.**
- **Abh.:** keine. **Blockiert nichts**, aber TP31 vergibt bereits danach.
---
## 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).
- 🔑 **Alle Passwort-/Token-Rotationen laufen seit 2026-08-24 unter [TP30](#tp30) — Sammel-TP,
gebĂŒndelt gegen Projektende (User-Entscheid).** Dort steht die Rotationsliste (MikroTik `admin`,
IoT-PSK, Shelly-GerĂ€tepasswort, CF-Access-Token), der Radius der fĂŒnf Konsumenten, der
Etappe-1-Abschluss und die Fallenliste. **Etappe 1 ist durch**, Etappe 2 wartet bewusst.
- ~~**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) · **TP30** (Credential-Rotation — nicht research-, sondern
**termin**-gated: gebĂŒndelt gegen Projektende, User-Entscheid 2026-08-24).
*(**TP17.1** — Shelly Gen4 → Thread, aktiviert 2026-08-23 — lĂ€uft **nicht hier**, sondern im
HA-Projekt `~/dev/ha-xstate`; netzseitig ist nichts zu bauen. Es blockt bewusst die PSK-Rotation.)*
*(**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").
<details><summary>📜 Historische Fassung dieses Abschnitts (bis 2026-08-14 fortgeschrieben, hier bewusst erhalten)</summary>
> 🎯 **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).
</details>