-infra auf beiden APs und beiden Baendern disabled (User-Entscheid). Am Geraet gegengeprueft: aktive-vaps 11 -> 9, w2infra/w5infra disabled=true auf ap1+ap2. sec-/dp-/cfg-infra bleiben stehen, die Zone ist ohne Neuaufbau reaktivierbar. Zur Rueckfrage "hidden statt disabled?": Verstecken spart KEINE Airtime. Eine versteckte SSID sendet ihr Beacon weiter, sie laesst nur das SSID-Feld leer. Airtime spart ausschliesslich das Abschalten der VAP. Reconnaissance fuer die /ip firewall filter Compliance-Rule: core 25 Regeln, branch 0, ap1+ap2 je 12 defconf-Reste (inert, inkl. "accept to local loopback (for CAPsMAN)"). Zwei Entscheidungen vor dem Template-Bau festgehalten — AP-Defconf abraeumen vs. als Soll schreiben, und branch als leer rendern. Ohne die meldet die Rule sofort flaechendeckend Drift. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1282 lines
245 KiB
Markdown
1282 lines
245 KiB
Markdown
# 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`.
|
||
|
||
## 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 ap1) |
|
||
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-16 — live gegen die Geräte geprüft (MikroMCP), nicht aus der Doku abgeschrieben.**
|
||
|
||
- **L3 + WAN-Edge = `crs326-core`** (CRS326-24G-2S+, RouterOS 7.19.5, Technik UG): Routing, DHCP (7 Server,
|
||
54 Reservierungen), DNS, NAT und der WG-Hub (TP10, Peers `fm`/`dw`) laufen hier. Mgmt-SVI **`10.40.99.1`**
|
||
(vlan99), Gateway `.1` je VLAN (vlan10/20/30/40/50/90/99 alle `running`). **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 aktuell **plain `1.1.1.1`** (DoH-Gateway offen: TP21.1 TODO 1 = TP23 Stufe 1).
|
||
- **L2-Branch = `crs326-branch`** (Technik OG, RouterOS 7.19.5): reiner L2-Switch, Mgmt **`10.40.99.2`**,
|
||
Uplink `ether1` → core `ether8`. ✅ **Bring-up-Reste entfernt (2026-08-16):** SVI `vlan10` + `10.40.10.2`
|
||
(„TEMP Bring-up VLAN10") sind weg — Mgmt läuft ausschließlich über `vlan99`.
|
||
- **WLAN = 2× hAP ax² als reine Standalone-APs** (RouterOS 7.23, **kein CAPsMAN**): ap1 **`10.40.99.11`**
|
||
(an core `ether15`), ap2 **`10.40.99.12`** (an branch `ether24`), Uplink je `ether1` (PoE-Port). 6 SSIDs
|
||
`dirtyvader-*`, jede mit eigenem `datapath` → kein ungetaggter VLAN1-Egress mehr. 802.11r/k/v aktiv
|
||
(`st-main`, seit TP3.3 fester Bestandteil des GC-Templates).
|
||
- **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). `cudy1` hängt noch an core `ether11`, hat aber **seit
|
||
2026-08-08 19:33 keinen Link** (live bestätigt) und steht in Nautobot auf *Offline*; `cudy2` tot.
|
||
→ **Kein aktiver VLAN1-Leak mehr**, der formale Teardown bleibt TP19.
|
||
- **Kontrolle / Governance:** MikroMCP für Reads/Debug (alle 4 Geräte in der Registry: `crs326-core`,
|
||
`crs326-branch`, `ap1`, `ap2`), **Config-Änderungen ausschließlich über Nautobot Golden Config**
|
||
(TP21/TP22 — Deploy-Pipeline scharf, **68/68 Compliance-Checks grün, 0 Drifts** seit 2026-08-16).
|
||
|
||
<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-17): TP5 Etappe 3 — den Drop scharf schalten, sobald das Log mehrere Tage still bleibt.** Etappe 1 (Log-Lauf) und **Etappe 2 (11 Whitelist-Regeln, ausgerollt 2026-08-17)** sind durch; die Log-Regel ist im Moment des Deploys verstummt. Offene Vorbedingungen für Etappe 3: **mehrtägiges stilles Fenster**, iPhone `.30.201` aus dem IOT-SSID (D2), `seal-lan` verengen. Parallel neu: **TP25** (WLAN-Stabilisierung — Audit durch, 6 Funde) und **TP16.3** (cloudflared-Reduktion via Mesh — Recherche durch).
|
||
> *Vorherige Fassung (Stand 2026-08-14, überholt): „TP5 — Deny-by-default am Ende von `forward`." Alles Davorliegende ist durch:* CRS326-Bring-up + L3-Umzug ap1→`crs326-core` (TP15/TP21.1 ✅ 2026-08-08), WLAN-Neuprovisionierung ohne CAPsMAN (TP3 ✅ 2026-08-08), Nautobot-Plattform + Fleet-Adoption + Deploy-Pipeline (TP21/TP22 ✅ 2026-08-13). Danach **TP6 (CAKE) = das Projektziel**. Kleine Follow-ups nebenher: DoH-Cloudflare auf core, DC-USV (**TP24**, seit 2026-08-16 eigener TP). ⚪ **Omada-PVID-Fix ist obsolet** (User-Entscheid 2026-07-22 — Omada spielt seit der TP15-Korrektur keine Rolle mehr im Netz, nie mehr aufgreifen).
|
||
> *Vorherige Fassung (Stand 2026-07-22, erledigt): „TP15 CRS326-Bring-up als neuer L3-Core, danach WLAN-Neuprovisionierung ohne CAPsMAN; TP5 folgt nach TP21/CRS326-Adoption."*
|
||
> 🎯 **Ziel: sauberes System „from scratch", keine Leichen/Altlasten.** Migrations-Session-Endstand = **VLAN1 + altes cudy-WLAN komplett weg** (VLAN1 nur noch Mgmt, `defconf`-Client-DHCP zurückgezogen, cudy-Uplinks aufs Ziel-Client-VLAN getaggt oder cudy abgebaut). **Unterpunkte/Aufräum-Liste bei Migration:** (a) die Interim-Härtung ap2 `wifi1/wifi2 frame-types=admit-only-vlan-tagged` (TP3.1, 2026-07-06) bleibt gültig — verschwindet automatisch mit VLAN1; (b) ~~`st-main rrm/wnm` = reines Roaming-Provisorium~~ → **kein Provisorium mehr (2026-08-13, TP3.3): Steering ist fester Bestandteil des Golden-Config-Templates + ComplianceFeature `wifi-steering`** — es war die Neuprovisionierung, die es stillschweigend verloren hatte; (c) ~~**cudy1 = verbleibender aktiver VLAN1-Leak**~~ → **ERLEDIGT (User-bestätigt + verifiziert 2026-08-14): cudy1 ist offline.** `core ether11` trägt **kein Link** (kein `R`-Flag), Nautobot-Status *Offline* (TP22 Schritt 5). Damit existiert kein aktiver VLAN1-Leak mehr; der Dual-DHCP-Race aus `project_vlan1_dhcp_incident` ist Historie. Der formale Teardown (Gerät ausbauen, Doku/Inventar) bleibt TP19.
|
||
> ⚠️ **HW-Constraint hAP ax²:** 1 GB RAM, aber nur **128 MB Flash + KEIN USB** → **Container auf dem Router NICHT praktikabel**.
|
||
> Folge: **native RouterOS-Features bevorzugen** (z.B. Built-in-mDNS statt Container); Container (mDNS-Reflector, BIND9-DNS, Omada-Controller) laufen auf **NAS/pve**, nicht am hAP.
|
||
> 🔒 **Governance-Entscheid (User, 2026-07-16, ausgeweitet 2026-07-16): Config ausschließlich über Nautobot — keine Direkt-Changes mehr an einzelnen im Netz verstreuten Geräten.** Ursprünglich als ap1/ap2-Config-Freeze bis TP21 formuliert, noch am selben Tag verallgemeinert: **jede** Netz-Gerätekonfiguration (Router, APs, künftig auch die CRS326-Switches) läuft ab jetzt exklusiv über Nautobot Golden Config (TP21), sobald das steht — keine ad-hoc MikroMCP-Writes/UI-Klicks mehr an Einzelgeräten. **TP19.1 war die letzte Ausnahme** (ap1-DNS-Fix + ap2/sw1/sw2-Mgmt-VLAN-Umzug, s.u.) — davon ist nur der risikolose ap1-Teil noch direkt gemacht worden, ap2 wurde bewusst auf „nach Nautobot" vertagt. **Macht Nautobot + alle Prerequisites (TP18→TP20→TP20.1→TP21, jetzt auch Komodo) zum aktuell kritischen Pfad**, vor TP5/TP6. Betrifft nicht Software-Migrationen auf NAS/pve (anderes Substrat) und die Frage, ob sw1/sw2 vor der CRS326-Ablösung noch angefasst werden (offen, s. TP15/TP19.1).
|
||
> ✅ **Genehmigte Ausnahme (User, 2026-07-17): der zentrale CF-Tunnel-Zugang auf ap1 (TP16/TP16.1).** Alle für den zentralen Cloudflare-Zugang **auf ap1** notwendigen (Vor-)Arbeiten dürfen direkt via MikroMCP/CF-API gemacht werden, ohne auf Nautobot GC zu warten — konkret die nativen WireGuard-Mesh-Zeilen aus TP16.1 (und analoge cloudflared/WG-Anpassungen am ap1-Edge). Begründung: Remote-Erreichbarkeit ist die Voraussetzung, um überhaupt sicher am Netz zu arbeiten (Henne-Ei zu Nautobot). **Scope-Grenze:** Die Ausnahme gilt **nur für ap1**. Sobald der zentrale Zugang später auf die **CRS326** wandert (TP15), gilt die Ausnahme dafür **vorerst NICHT** — CRS326-Config läuft dann regulär über Nautobot GC (oder braucht eine eigene, dann neu zu erteilende Ausnahme). Nachtrag der ap1-Ausnahmezeilen in die GC als Follow-up, sobald Nautobot steht.
|
||
> ✅ **Genehmigte Ausnahme #4 (User, 2026-08-16): die WireGuard-Zeilen des Cloudflare-Mesh-Bring-ups auf `crs326-core` (TP16.1).** Dürfen direkt via MikroMCP/REST gesetzt werden. **Begründung ist strukturell, nicht bequem:** TP22-Regel 1 schließt jede Sektion mit `<<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.
|
||
|
||
---
|
||
|
||
## Teilprojekte
|
||
|
||
### TP1 — ALLNET Core-Switch finalisieren ▸ ✅ FERTIG (2026-06-15) → ❌ Gerät AUSSER BETRIEB (2026-08-08, durch crs326-core ersetzt)
|
||
- ✅ GE8 Trunk (native vlan1, tagged 10/20/30/40/50/90/99/100) — war bereits aktiv.
|
||
- ✅ VLAN 40 umbenannt: UNTRUSTED → **MEDIA** (`switch/cli/04-vlan50-media-untrusted.cli`).
|
||
- ✅ VLAN 50 angelegt + benannt: **UNTRUSTED**.
|
||
- ✅ GE1/GE2 (AP-Trunks) um VLAN 50 ergänzt; GE8 auto-includiert (Trunk).
|
||
- Ergebnis: Core trägt alle VLANs (10/20/30/40/50/90/99/100) an P1/P2/P8.
|
||
|
||
### TP2 — Omada Access-Switch + Controller ▸ ✅ FERTIG (2026-06-15)
|
||
- ✅ Omada Controller 6.2.10.17 auf DS923 (macvlan `.175`): `omada/docker-compose.yml`, Stack via Portainer endpointId=14. **Wizard abgeschlossen** (configured=true), Creds in `mcp/omada/.env`.
|
||
- ✅ pve-mcp (samik081) in Claude Code eingetragen (`~/.claude/settings.json`, SSE `.173:3000`).
|
||
- ✅ omada-mcp **live** auf **pve-LXC (`.126`, endpointId=2), ipvlan-IP `.176`**, Stack Id=200, URL in `~/.claude/settings.json`.
|
||
- **Transport:** StreamableHTTP `http://10.40.41.176:3000/mcp` (Health `/health` → 200). Settings-Bug (doppelter Eintrag) behoben 2026-06-15.
|
||
- **Auth:** Omada **Open API Client-Credentials**. Creds in `mcp/omada/.env`. Token-Format: `Authorization: AccessToken=<token>` (nicht Bearer). OMADA_TOOL_CATEGORIES=all (alle 84 read-Tools aktiv; write für VLANs/Ports nicht im MCP implementiert → direkte Open API oder Controller-UI).
|
||
- omadac_id=`adbef8fa…`, site_id=`6a2fe68e…`.
|
||
- ✅ **VLANs im Controller:** 1/10/20/30/40/50/90/99/100 — alle angelegt, Switch adopted (switchConsistent=true).
|
||
- ✅ **Port-Plan (ES208G, alle 8 Ports konfiguriert):**
|
||
| Port | Name | Profil | Gerät | Status |
|
||
|------|------|--------|-------|--------|
|
||
| 1 | uplink | Trunk-ALL | → ALLNET GE8 | ✅ korrekt |
|
||
| 2 | ap2 | Trunk-ALL | hAP ax² #2 | ✅ korrekt |
|
||
| 3 | Port3 | Access-MAIN | — (frei) | ⚠️ PVID=1 |
|
||
| 4 | dock/monitor | **Access-MAIN** | Docking-Station | ⚠️ PVID=1 · **Lifeline-Port, nicht anfassen** |
|
||
| 5 | drucker | Access-MAIN | Drucker | ⚠️ PVID=1 |
|
||
| 6 | Port6 | Access-MAIN | — (frei) | ⚠️ PVID=1 |
|
||
| 7 | macmini | Access-INFRA | Mac mini | ⚠️ PVID=1 · **fixe IP 10.40.41.x, nicht anfassen** |
|
||
| 8 | ds923+ | Access-MAIN | NAS (2. Port) | ⚠️ PVID=1 · **nicht anfassen** |
|
||
- ⚠️ **Profile-PVID-Constraint (bis TP4 offen):** NAS, Mac mini und andere Geräte haben fixe IPs im
|
||
Bereich `10.40.41.x` (VLAN-1-Subnetz der FritzBox). Solange diese nicht auf VLAN-10/20-Subnetze migriert
|
||
sind, muss `nativeNetworkId=Default(VLAN 1)` in allen Access-Profilen bleiben — sonst kein DHCP, kein
|
||
Internet für diese Geräte. Fix nach TP4.
|
||
- ⚠️ **Bekannter Fehler `untagNetworkIds` (Analyse 2026-06-15 via Controller-API v2):**
|
||
Access-MAIN hat `untagNetworkIds=[VLAN1, VLAN20, VLAN10]` (3 untagged!) statt `[VLAN10]`.
|
||
Access-INFRA hat `untagNetworkIds=[VLAN20, VLAN1]` statt `[VLAN20]`. Geräte erhalten Frames
|
||
aus mehreren VLANs ungetaggt → Inter-VLAN-Tests verfälscht. Fix erst sinnvoll nach TP4 zusammen
|
||
mit PVID-Korrektur.
|
||
- **Sichere Testports (kein kritisches Gerät):** P3, P5, P6.
|
||
- ✅ Portainer-Ablösung: **Komodo** empfohlen (einzige Option mit nativem MCP `mcp-server-komodo`). Eigener Task.
|
||
- Abh. erfüllt: TP1 (GE8 Trunk ✅).
|
||
- **→ TP4 wird vorgezogen:** Alle VLANs im Controller definiert (status=false = kein Management-IP, normal).
|
||
Traffic läuft noch auf VLAN 1 bis TP4 die L3-Interfaces + DHCP-Server je VLAN aktiviert.
|
||
|
||
### TP2.1 — Omada-Switch (sw2/ES208G) → Standalone-Recovery (kein Controller) ▸ ✅ FERTIG (2026-07-16, User solo)
|
||
- **Root Cause:** beim VLAN20-Umzug des Omada-Controllers (TP14.1, 2026-07-10) ist die Controller↔sw2-Verbindung zerbrochen (sw2 seither „Disconnected", ursprünglich als reiner Mgmt-Loss vertagt). Beim Rettungsversuch hat der User versehentlich einen **Werks-Reset** am Switch ausgelöst. Ein anschließender Wiederherstellungsversuch (durch Claude) hat Teile der Config **unbemerkt halluziniert** — der damalige „wiederhergestellte" Stand war **nicht vertrauenswürdig**.
|
||
- **Entscheidung (User 2026-07-15): Controller-Zustand als invalid betrachtet, sw2 komplett neu — diesmal OHNE Managementsoftware.** Kein Omada-Controller-Re-Adopt, kein Omada-Ecosystem-Anschluss (s. TP15-Korrektur — Omada bekommt generell keine Rolle mehr, auch nicht WLAN). sw2 direkt über eigenes Web-UI konfiguriert, wie ein eigenständiger Switch.
|
||
- **✅ 2026-07-16 (User-Aussage): „voll durch, Funktionsweise erfolgreich getestet."** Nach dem gescheiterten Claude-Versuch hat der User sw2 **komplett allein** neu aufgesetzt (Runbook `docs/tp2.1-omada-switch-standalone-runbook.md` als Playbook-Referenz, nicht Schritt-für-Schritt-Log). **Keine formale Einzelschritt-Verifikation dieser Session** (kein Port-für-Port-Protokoll, keine Live-Prüfung durch Claude) — Status beruht auf User-Bestätigung „es geht einfach", nicht auf eigener Nachkontrolle.
|
||
- **sw2 bleibt Solo:** „bekommt nie Geschwister" — keine weiteren Omada-Geräte geplant. Interimslösung bis zur Ablösung durch CRS326 (TP15).
|
||
- **Offen/nachzuziehen (nicht blockierend):** finale Portbelegung + IP von sw2 in `docs/ip-plan.md`/CLAUDE.md-Hardware-Tabelle nachtragen (aktuell dort noch „Adoption pending" — stale, aber Wert unbekannt, nicht geraten); `omada/.secrets` auf neue Standalone-Creds prüfen; ob Omada-Controller-Container jetzt komplett überflüssig ist.
|
||
- Abh.: TP1 ✅ (VLAN-Trunk am Uplink). Verwandt: TP15 (löst sw2 mittelfristig durch CRS326 ab), TP14.1 (Auslöser).
|
||
|
||
### TP3 — WLAN (Standalone-APs) ▸ ✅ **REBUILD DURCH (2026-08-08): beide hAP ax² sind reine Standalone-APs, CAPsMAN abgeschafft** — Erstaufbau ✅ 2026-06-18 (`routeros/tp3-capsman.rsc` = **historisch**, aktuelle Configs `routeros/.secrets/ap{1,2}-prov-base.rsc`)
|
||
> ⚠️ **Lesehinweis:** die folgenden Punkte bis zum ✅-DURCH-Eintrag am Ende beschreiben die **CAPsMAN-Ära (Juni/Juli 2026)** und sind bewusst als Historie erhalten — der Ist-Stand steht im letzten Punkt dieses TPs.
|
||
- ✅ **5 sichtbare SSIDs live, beide APs, beide Bänder, je SSID→VLAN** (wifi datapath vlan-id):
|
||
`dirtyvader-main`(10, WPA3-only, FT), `-iot`(30, **nur 2,4 GHz**, WPA2+3), `-media`(40, WPA2+3, **FT=no** wg. Sonos),
|
||
`-untrusted`(50, WPA2+3), `-guest`(90, WPA2+3). Alt-SSIDs `install*`/`BF-Main`/`wv*` entfernt. Temp-PSK (User setzt echte).
|
||
- ✅ **CAPsMAN-Architektur:** ap1=Manager+AP (lokale Radios), ap2=CAP (dynamisch via Provisioning, `remote-cap=Ok`).
|
||
**Kernlektion:** Der Manager kann seine **eigenen** Radios NICHT über CAPsMAN provisionieren → ap1 lokal zuweisen
|
||
(Master via `set` + statische Slave-VAPs), ap2 zieht Master+Slaves dynamisch. Ein CAP hält **keine** Eigen-Config.
|
||
- ✅ **Kanal-Plan (non-DFS, überlappungsfrei):** ap1 ch36/5180 + ch1/2412 · ap2 ch149/5745 + ch11/2462.
|
||
(Auto-Channel hatte beide APs auf 5500-DFS/2437 gelegt = Co-Channel → fix gepinnt. ap2-Kanaländerung braucht
|
||
`remote-cap provision`-Push.) `bound`-Problem damit obsolet/sauber gelöst.
|
||
- ✅ **Sonos-Migration abgeschlossen (2026-07-02):** alle 10 Sonos auf `dirtyvader-media`/VLAN 40 mit MAC-fest
|
||
reservierten DHCP-Leases in `dhcp-v40`. Household geschlossen, iOS-App findet alle Geräte (mDNS via Repeater).
|
||
Inventar/IPs = SSoT `docs/sonos-inventar.md` (IPs haben sich verschoben — Arc jetzt `.199`, Arbeitszimmer-Paar auf `.191/.192`).
|
||
- **Vertagt:** hidden `dirtyvader-infra`(20)+`-mgmt`(99) (Mgmt verkabelt). **TP8:** eine 802.1X-SSID
|
||
(`dirtyvader-secure`) mit FreeRADIUS-Dynamic-VLAN → dann PSK-`main`/`infra` einstampfen (Konsolidierung).
|
||
- **SSID-Strategie-Entscheid (Begründung):** unterschiedl. WPA-Typ/Band erzwingen separate SSIDs; „alles in 1 SSID
|
||
per Auth" nur via 802.1X (Geräte ohne EAP wie Sonos/TV/IoT brauchen ohnehin PSK) → Hybrid in TP8.
|
||
- **Mesh = NEIN** (beide APs wired-trunk → Loop-Risiko). DoH-Upstream = Cloudflare Gateway (seit TP4 aktiv).
|
||
- Abh. erfüllt: TP4 ✅ (L3/VLAN-Interfaces). Folge: TP8 (802.1X), Sonos-Migration.
|
||
- 🔄 **CAPsMAN wird abgeschafft (User-Entscheid 2026-07-22) — WLAN-Neuaufbau from scratch.** Anlass: WLAN dauerhaft instabil, besonders wenn **beide** APs laufen. Beide APs bekommen künftig **eigenständige, von Nautobot Golden Config identisch generierte RouterOS-Configs** statt Manager/CAP.
|
||
- **Begründung (kein Widerspruch zu Nautobot, aber ein echter Reibungspunkt):** CAPsMAN erzeugt auf dem CAP **dynamische** Objekte (`wifi13–22`), die nie in dessen eigener Config stehen → Golden-Config-Compliance sieht auf ap2 faktisch nichts. Genau diese Halbheit war die Ursache von TP3.1 (CAPsMAN schrieb `datapath.vlan-id` nicht auf die Leitung und legte die tagged-Member am CAP nicht an).
|
||
- **Was NICHT verloren geht:** 802.11r/k/v braucht kein CAPsMAN, sondern nur gleiche SSID/PSK/Mobility-Domain → Fast-Roaming bleibt. Preis: Radio-/Kanaländerungen sind zwei Deployments statt eines Provision-Pushes — mit Nautobot ohnehin ein Job-Run.
|
||
- **Reihenfolge:** WLAN-Neuprovisionierung erst **nach** dem CRS326-Bring-up (TP15), da Routing/DHCP/DNS vorher umziehen.
|
||
- ✅ **DURCH (2026-08-08): beide APs als reine Standalone-APs neu provisioniert, CAPsMAN weg.** ap1 `10.40.99.11` (an core `ether15`), ap2 `10.40.99.12` (an branch `ether24`); Uplink geräteseitig auf **`ether1`** (PoE-Port, `poe-out=off`) umgestellt, ether2 aus dem Trunk entfernt. 6 SSIDs (main WPA3+FT / infra/iot/media/untrusted/guest WPA2+3, iot nur 2,4 GHz, media FT=no); **jede SSID mit eigenem `datapath` bridge+vlan-id** → das TP3.1-„cfg-main-2g ohne datapath"-Leck ist strukturell weg. Kanäle non-DFS ap1 ch36/ch1, ap2 ch149/ch11. Client-Test grün (VLAN10/30-Leases korrekt). Configs `routeros/.secrets/ap{1,2}-prov-base.rsc`, PSKs `routeros/.secrets/wlan-psks.env`, As-built → Nautobot via `nautobot/ingest-ap-rebuild.py`. **Einheitliches Admin-PW auf allen 4 MikroTik** (User-Vorgabe). Henne-Ei beim Bring-up: Werks-`192.168.88.1` über Core-Temp-Pfad (`192.168.88.2` + masq, wieder entfernt) via scp+`/import`; Werks-Inline-Overrides auf wifi1/wifi2 mussten geleert werden (`!configuration.ssid !security.*`), sonst funkt die Main-VAP die Werks-SSID. Offen: DoH auf core (nur plain 1.1.1.1), breiterer CLAUDE.md-Gotcha-Cleanup (ap1-als-L3-Router-Referenzen sind überholt).
|
||
|
||
### TP3.1 — ap2 VLAN-Trunk-Fix ▸ ✅ Config live (2026-07-01) — `routeros/tp3.1-ap2-vlan.rsc`
|
||
- **Root Cause:** ap2 (CAP, local forwarding) hatte `bridge vlan-filtering=no` → `datapath.vlan-id` wurde nie
|
||
auf die Leitung geschrieben → **ALLE** WLAN-Clients auf ap2 (main/media/iot/…) egressten **ungetaggt in VLAN1**
|
||
(defconf/`10.40.41.x`) statt ins Ziel-VLAN. Symptom: iPhone (VLAN10) im OG „verbunden, aber sporadisch kein
|
||
WLAN-Symbol" — beim Roaming ap1↔ap2 sprang es VLAN10↔VLAN1 (Subnetz-Flip → Abbruch). Sonos-Terrasse landete
|
||
auf ap2 fälschlich auf `10.40.41.183`. TP3 „ein CAP hält keine Config" gilt nur für Manager-Forwarding — hier
|
||
local forwarding, daher **braucht ap2 doch VLAN-Config**.
|
||
- ✅ **Fix (wie ap1):** ap2-Bridge `vlan-filtering=yes`; VLAN1 untagged=bridge,ether2 (Mgmt), VLANs 10/30/40/50/90
|
||
tagged auf ether2. Da nur die Master-Radios wifi1(5G)/wifi2(2.4G) Bridge-Ports sind (Slave-VAPs forwarden über
|
||
den Master), zusätzlich **wifi1/wifi2 als tagged-Member** je Client-VLAN (wifi1: 10/40/50/90, wifi2: 10/30/40/50/90).
|
||
CAPsMAN legt diese auf dem CAP **nicht** automatisch an → manuell gesetzt. Danach `remote-cap provision`.
|
||
- **Lockout-Risiko gehandhabt:** ap2-Mgmt (10.40.41.2) untagged VLAN1 blieb erhalten; kein Scheduler (device-mode=home)
|
||
→ Recovery = Power-Cycle OG. Ausgeführt im leeren-registration-table-Fenster.
|
||
- ⏳ **Offen — funktionaler OG-Test durch User:** Handy auf `dirtyvader-main` im OG → Lease muss `dhcp-v10`/`10.40.10.x`
|
||
sein (nicht `defconf`/`10.40.41.x`). Falls kein DHCP: Omada-Port-2-Trunk (tagged 10/30/40/50/90) prüfen.
|
||
- Abh.: TP3 ✅, TP4 ✅ (Bridge-VLAN-Muster gespiegelt). Config ap2-lokal (nicht CAPsMAN-verwaltet).
|
||
- 🔁 **Interim-Härtung 2026-07-06 (Migrations-Provisorium, fliegt mit VLAN1 raus):** Symptom „kein DHCP auf
|
||
`dirtyvader-main`, Altnetz ebenso, nichts geändert". Diagnose via MikroMCP (ap1+ap2): **Dual-DHCP-Race** — dieselben
|
||
Main-MACs (`56:71:6C:22:E6:A9`, `F2:62:4C:E1:AF:09`, `C0:C7:DB:DE:71:BE`) hielten gleichzeitig eine korrekte
|
||
VLAN10-Lease (`dhcp-v10`/`10.40.10.x`) **und** eine VLAN1-Lease (`defconf`/`10.40.41.18x`); `defconf` und `dhcp-v10`
|
||
boten parallel → `offering ... without success` + Minutentakt-Flapping. `bridge`-ARP auf ap1 = 333 Einträge (flache
|
||
VLAN1 lebt voll weiter; IoT/Shelly untagged auf `10.40.41.2xx`). **Griff:** auf ap2 die Master-Radio-Bridge-Ports
|
||
`wifi1`/`wifi2` von `frame-types=admit-all` auf **`admit-only-vlan-tagged`** — untagged Main/Slave-Frames werden
|
||
verworfen statt in VLAN1 gedumpt (im Zielbild ohnehin korrekt, daher kein Rückbau nötig, verschwindet mit VLAN1).
|
||
`ether2` bleibt `admit-all` (VLAN1-Mgmt/Trunk, kein Lockout). **Rollback:** `frame-types=admit-all` auf beiden Ports.
|
||
⚠️ **Rest-Leak bleibt: cudy1 (altes WLAN)** bridged Clients weiter untagged in VLAN1 — nur per Switch-Port-Tag bzw.
|
||
Alt-WLAN-Abbau (Migration) zu schließen, NICHT auf der MikroTik-Seite. Zusätzlich `st-main rrm=yes wnm=yes` (802.11k/v,
|
||
behandelt nur das Roaming-Symptom). SSoT-Detail: Memory `project_vlan1_dhcp_incident`.
|
||
- 🎯 **ROOT CAUSE des ap1-Lecks gefunden (2026-07-22, live aus `/interface/wifi/configuration print`) — es ist KEIN `frame-types`-Problem:** `cfg-main-2g` (SSID `dirtyvader-main` auf 2,4 GHz, gebunden an Master-Radio `wifi2`) hat **überhaupt keinen `datapath`-Block** — weder `bridge` noch `vlan-id`. Das 5-GHz-Pendant `cfg-main-5g`/`wifi1` taggt sauber nach VLAN 10, **2,4 GHz taggt gar nicht** → egress ungetaggt in VLAN 1. Ein Client, der zwischen den Bändern **derselben SSID** wechselt, springt damit `10.40.10.x` ↔ `10.40.41.x` — Subnetzwechsel mitten in der Verbindung. Erklärt das Dual-DHCP-Race und das „verbunden, aber sporadisch kein WLAN" ohne jede Zusatzannahme. **Fix nicht mehr direkt anwenden** — geht mit der WLAN-Neuprovisionierung (CAPsMAN-Abschaffung, TP3) über Nautobot ein. Nebenbefund: `cfg-infra` existiert auf ap1, wird von **keinem** Interface benutzt (deckt sich mit TP3.3), und ap1 funkt real auf **ch36/ch1** — die Interfaces überschreiben das Channel-Profil `ch-5g` (5745/ch149).
|
||
- 🔴 **Update 2026-07-15: gleiches Leck jetzt auf ap1 vermutet.** `dirtyvader-main`-Clients bekommen zeitweise
|
||
`10.40.41.x`-IPs statt `10.40.10.x` — identisches Dual-DHCP-Race-Muster wie oben, aber die 2026-07-06-Härtung
|
||
wurde **nur auf ap2** gemacht. Nächster Schritt: gleiche `admit-only-vlan-tagged`-Umstellung auf ap1s lokalen
|
||
Main-Radio-Bridge-Ports (⚠️ NICHT `ether2` anfassen — das ist ap1s Mgmt-/WAN-Trunk-Pfad). Diagnose+Fix-Schritte:
|
||
`docs/tp19-vlan1-cudy-teardown-runbook.md` Phase A (~30-60 Min). Diese Härtung ist wie die ap2-Variante ein
|
||
Provisorium, das mit TP19s VLAN1-Abbau automatisch obsolet wird.
|
||
|
||
### TP3.2 — WLAN Coverage / P750W-Discovery ▸ ⏳ teil-erledigt (2026-07-02) — `docs/wifi-p750w-coverage-and-map.md`
|
||
- ✅ **Brother P750W (VLAN30) gelöst:** DHCP-`client-id`-Fix (matcht über MAC → feste `10.40.30.5`); **an ap1 gepinnt**
|
||
(geordnete wifi-access-list `accept w2-iot` → blanket `reject`, überlebt ap2-Re-Provision) — dozende Legacy-Clients
|
||
nur am co-located-GW ap1 per ARP erreichbar, CAP ap2 nicht; mDNS `vlan30` in `mdns-repeat-ifaces`+5353 → in MAIN
|
||
auffindbar. Druck+Selbsttest OK. Web-UI `http://10.40.30.5/general/information.html`.
|
||
- ✅ **Nebenbei:** `multicast-enhance=enabled` (iot+media), Guest `ft=yes`, INFRA-SSID(20) angelegt (**nur ap2**),
|
||
Steering-Profil `st-main`/`neighbor-group=bf-main` auf beide Main-Configs.
|
||
- **Nomenklatur:** dynamische ap2-CAP-Slaves (`wifi13–22`) nicht praktikabel umbenennbar (`name-format` unzuverlässig)
|
||
→ Map dokumentiert statt umbenannt. Backups `bf-ap{1,2}-pre-nomen-20260702.backup`/`.rsc` auf den Geräten.
|
||
- ⏳ **Offene Coverage-Arbeit → ausgelagert nach TP3.3** (Fortsetzung in neuer Session).
|
||
|
||
### TP3.3 — WLAN Coverage-Kur ▸ 🔜 TODO (Fortsetzung, neue Session) — `docs/wifi-p750w-coverage-and-map.md`
|
||
- ✅ **BEHOBEN 2026-08-13, noch am selben Abend (User: „aus Zeitgründen zuerst 11k/v, der nächste Call steht an").** `st-main` (`rrm=yes wnm=yes neighbor-group=bf-main`) auf beiden APs wiederhergestellt und an `cfg-main-5g`/`cfg-main-2g` gehängt — **via GC-ConfigPlan**, bewusst nicht per Direkt-Write: der Push läuft so NAS→Kabel→AP und nicht über die WLAN-Verbindung, die man gerade umkonfiguriert. `/system backup` je AP davor (`ap{1,2}-pre-steering-20260813.backup`). **Gegengeprüft am Gerät** (nicht am Plan-Status): `st-main rrm=true wnm=true ng=bf-main`, beide Main-Configs verweisen darauf.
|
||
- ⚠️ **Erwartete Nebenwirkung: alle Clients haben kurz reassoziiert** (ap1 25→2, ap2 7→14 unmittelbar danach) — `steering=` auf einer `wifi configuration` zu setzen re-applied die VAPs, auch die nicht angefassten. Nach ~2 Min eingependelt (ap1 15 / ap2 13, VLAN30 = 28 Hosts auf der Core-Bridge). **Nicht während eines Calls machen.**
|
||
- ✅ **In GC verankert:** Steering steht jetzt im AP-Zweig des Templates (`st-main`/`bf-main` als Konstante — es gibt genau eine Roaming-Domain pro Standort) + neues ComplianceFeature **`wifi-steering`**. Eine künftige Neuprovisionierung kann es damit nicht mehr stillschweigend verlieren — genau das war der Fehler vom 2026-08-08.
|
||
- ⏳ **Offen: der Praxistest.** Dieselbe Route noch einmal gehen. Reißt es weiterhin ab, ist es echte Coverage → Dead-Spot-Kartierung.
|
||
- 🔴 **Der Befund (2026-08-13): Steering war auf BEIDEN APs weg.** `/interface/wifi/steering` = **0 Einträge** auf ap1 *und* ap2 (live geprüft). Vor dem Rebuild war `st-main` mit `rrm=yes wnm=yes` + `neighbor-group=bf-main` auf beiden Main-Configs gesetzt (s. TP3.2 + TP3.1-Interim). Die Neuprovisionierung am 2026-08-08 aus `routeros/.secrets/ap{1,2}-prov-base.rsc` hat es **nicht wieder angelegt**.
|
||
- **Wirkung:** kein **802.11k** (Neighbor Reports → der Client kennt die Nachbar-APs gar nicht) und kein **802.11v** (BSS Transition → der AP kann den Client nicht wegschicken). Der Client bleibt am sterbenden AP kleben, bis die Verbindung zusammenbricht, und muss dann komplett neu scannen + assoziieren = **harter Abriss statt Übergabe**. Genau das Symptom „einmal durch die Wohnung, WLAN weg" (User-Erlebnis 2026-08-13 während eines Telegram-Videocalls, musste auf 5G ausweichen).
|
||
- ⚠️ **`ft=yes` ist KEIN Gegenbeweis** (auf beiden APs gesetzt, `ft-mobility-domain` beidseitig leer = gleicher Default, FT selbst also intakt). **802.11r macht die Übergabe schnell, sobald der Client sie beschließt — es bringt ihn nicht dazu, sie zu beschließen.** Ohne 11k/v fällt die Entscheidung viel zu spät. „FT ist an" ≠ „Roaming funktioniert".
|
||
- **Reihenfolge-Konsequenz:** Diese Regression **vor** der Dead-Spot-Kartierung beheben und dieselbe Route nachlaufen — sonst kartiert man Löcher, die in Wahrheit Roaming-Verhalten sind, und zieht daraus womöglich Hardware-/Platzierungs-Entscheidungen (s. „ap1 ins Sideboard"-Idee unten).
|
||
- **Weg (Governance):** Steering gehört ins **GC-Template** (`/interface/wifi/steering` + `steering=` an der Main-Configuration) → feature-scoped Deploy. Kein Direkt-Write. Betrifft `wifi-configuration` (bereits Compliance-Feature) + ein neues Feature `wifi-steering`.
|
||
- 💡 **Idee „ap1 ersetzt den Sideboard-Switch" (User 2026-08-13):** ap1 hat 4 freie Ports (`ether2–5`; `ether3/4/5` sind bereits Bridge-Ports mit `pvid=1`, `ether2` ist seit der ether1-Umstellung **kein** Bridge-Port mehr und müsste wieder aufgenommen werden) → die Wohnzimmer-Multimediageräte könnten direkt an ap1, der Smart-Managed-Switch entfiele. **Technisch machbar** (untagged VLAN40 wie `core ether2`), **aber platzierungsgebunden:** ein Media-Sideboard ist RF-mäßig einer der schlechtesten AP-Standorte (geschlossen, Metallgehäuse der AV-Geräte, niedrig). **User-Vorgabe: Platzierung hat Vorrang vor dem eingesparten Gerät.** Entscheidung daher erst **nach** der Steering-Reparatur + Re-Walk.
|
||
**Problem:** Kanten/Terrasse grenzwertig — Clients (iPhone/iPad) landen bei **−76..−89 dBm** und springen zwischen
|
||
allen 4 Main-Radios (ap1-5G/2,4G ↔ ap2-5G/2,4G) → „0–1 Striche + häufiger Abriss"; **Terrasse auch mittags** schlecht.
|
||
FT kaschierte das bisher als „Roaming" statt „schwache Abdeckung".
|
||
|
||
**Bereits geklärt/erledigt (nicht nochmal aufrollen):**
|
||
- NICHT config-verursacht (ap1 kein Reboot, RF-Konfig unverändert). **TX schon am AT-Max** (18/15 dBm, EIRP-Deckel — kein Hebel).
|
||
- Kanalplan intern überlappungsfrei (ap1 ch1/ch36, ap2 ch11/ch149). **Steering** `st-main`/`neighbor-group=bf-main`
|
||
auf beiden Main-Configs gesetzt (hilft Client-Entscheidung, macht Signal aber nicht stärker).
|
||
- **ap1-only ist vom Tisch** (echte Funklöcher) → beide APs nötig, aber besser platziert.
|
||
|
||
**Offene Arbeit:**
|
||
1. **Dead-Spot-Kartierung** (Tageslicht): User stellt sich in jeden Problempunkt (Terrasse zuerst, entfernte Räume,
|
||
dicke Wand) → je Punkt `registration-table` + `monitor` (Signal je Radio/Band/AP). Zusätzlich Nachbar-WLAN-Scan
|
||
`/interface/wifi/scan` je AP (**störend** — wirft Clients kurz ab) gegen Abend-Congestion. Output → SSoT-Doku.
|
||
2. **Remediation nach Befund:** Platzierung (ap2 Richtung Schwachseite umstellen / **3. AP** / Outdoor-Unit / Kabelweg);
|
||
Roaming-Feintuning (802.11v `transition`-Schwellen ab 7.21, Band-Overlap reduzieren); Kanalplan aus Scan nachziehen.
|
||
3. **INFRA(20) auf ap1 ergänzen** (fehlt — sendet nur auf ap2): lokaler `w2-`/`w5-infra`-Slave analog w2-/w5-media.
|
||
4. Danach Re-Walk-Test (wie 2026-07-02, aber mit Kartierung als Baseline).
|
||
|
||
**Sicherheitsnetz:** Backups `bf-ap{1,2}-pre-nomen-20260702.backup`/`.rsc` auf den Geräten. Kontext-Memory `project_wifi_coverage`
|
||
+ `ref_wifi_powersave_multicast`. Abh.: TP3 ✅, TP3.1 ✅, TP3.2 ✅.
|
||
|
||
### TP4 — Router-Cutover (hAP#1 = Router + WAN-Edge) ▸ ✅ FERTIG (2026-07-01) — ⚠️ **Rolle seit 2026-08-08 auf `crs326-core`** (TP21.1); alles unten beschreibt den damaligen ap1-Aufbau und gilt als **Historie/Referenz**, nicht als Ist
|
||
- ✅ **Bridge VLAN-Filtering aktiviert** (`vlan-filtering=yes`); VLAN-Tabelle: VLAN1 untagged bridge+ether2, VLANs 10/20/30/40/50/90/99/100 tagged bridge+ether2.
|
||
- ✅ **VLAN-Subinterfaces:** vlan10/20/30/40/50/90/99 auf bridge; je GW `.1` (10.40.10.1 … 10.40.99.1).
|
||
- ✅ **DHCP:** dhcp-v10…dhcp-v99 je auf eigenem VLAN-Interface, pools .100-.200, GW+DNS = VLAN-GW.
|
||
- ✅ **DNS:** RouterOS-nativ, allow-remote-requests=yes. **Upstream seit 2026-06-16: DoH Cloudflare Gateway** (`use-doh-server=https://px35ynlol3.cloudflare-gateway.com/dns-query`, verify-doh-cert, `servers=1.1.1.1` als Bootstrap; FB-Upstream abgelöst). Statische Einträge für alle Infra-Hosts unter `bf.lan` (13 Einträge, Transition-IPs bis PVID-Fix).
|
||
- ⚠️ Auto-Suffix `.lan` (RouterOS-Einschränkung, kann nicht auf leer gesetzt werden) — TP5-Cleanup.
|
||
- ✅ **NAT:** srcnat masquerade out-interface=vlan100 (ap1 = Public-Edge; kein Double-NAT mehr). Fallback-Konfig für ether1 bleibt reversibel dokumentiert (`routeros/wan-cutover-runbook.md`).
|
||
- ✅ **Routing-Tabelle:** 0.0.0.0/0 via Liwest-Gateway auf vlan100; alle 7 VLAN-Subnetze als Connected-Routes aktiv.
|
||
- ✅ **Edge-Cutover vollzogen (2026-07-01):** FritzBox 6660 physisch weg (Liwest hat gegen ein Arris-Kabelmodem im Bridge-Mode getauscht — kein Zurück). WAN = `Arris → sw1 gi16 Access VLAN100 → gi15 Trunk → ap1 ether2 → vlan100 auf bridge` (**NICHT** ether1). ap1 hält Public-IP direkt (Liwest, kein CGNAT). **WAN-Input-Seal live** (TP10-seal-Regeln: est/inv/dhcp/icmp/lan/wandrop im `input`-Chain, `list_firewall_rules` 2026-07-02 verifiziert). Telefonie war auf der FB und wird nicht weitergeführt (User-Bestätigung 2026-07-02).
|
||
- **DNS-Entscheidung** (Technitium **und** externer BIND verworfen): RouterOS-DNS als Resolver, keine DHCP→DNS-Auto-Registrierung (soweit möglich). Infra-Hosts als statische `/ip dns static`-Einträge unter `bf.lan`; dynamische Clients bewusst ohne Namen. Filtering/DNSSEC via DoH-Upstream (TP3). HA: 2. Resolver auf ap2, statische Einträge beidseitig pflegen.
|
||
- Abh.: TP1 ✅. TP3-Abhängigkeit entfällt (WLAN läuft weiterhin über FB bis TP3).
|
||
- **Ermöglicht jetzt:** PVID-Fix in Omada-Profilen (MAIN→PVID10, INFRA→PVID20), untagNetworkIds-Bereinigung, DHCP-Reservierungen für NAS/macmini/pve auf neue VLAN-Subnetze migrieren.
|
||
|
||
### TP5 — Firewall & Inter-VLAN-Policy ▸ 🟢 **ETAPPE 2 AUSGEROLLT (2026-08-17): 11 Whitelist-Regeln live, Log-Regel verstummt** — 📋 `docs/tp5-deny-by-default-runbook.md`
|
||
|
||
- ✅ **ETAPPE 2 DURCH (2026-08-17) — `routeros/tp5-etappe2-whitelists.rsc`, ConfigPlan `86fbd528`, Backup `core-pre-tp5-etappe2-20260817.backup`.**
|
||
- **Basis waren 43.027 Logzeilen** aus dem Fenster 2026-08-16T17:21 → 2026-08-17T14:05 (Kollektor `10.40.20.18`),
|
||
also **~21 Stunden echter Nutzverkehr** statt der 10-Minuten-Stichprobe von Etappe 1. Die vollständige Matrix:
|
||
| Paar | Zeilen | Dienste (Ziel:Port, absteigend) |
|
||
|---|---|---|
|
||
| `vlan20 → vlan99` | **20.682** | `8728` auf branch (7468) / ap1 (7468) / ap2 (5731) = HA-`mikrotik`-Integration · `:22` je 8 = Nautobot-Netmiko |
|
||
| `vlan10 → vlan20` | **8.082** | macmini `udp/3722` **6234** (Continuity) · NAS `6690` 1578 · Nautobot `8080` 137 · AirPlay `7000` 69 · pve-mcp `3000` 22 · HA `9583` 16 · pve `:22` 12 · macmini `49152`/`udp 59107` je 8 · NAS `:22` 4 · **Ollama `11434`** 2 |
|
||
| `vlan20 → vlan10` | **7.123** | Rückrichtung Continuity (eigene Flows je Richtung) |
|
||
| `vlan20 → vlan30` | **6.238** | HA pollt ~22 Shellys auf `tcp/80` |
|
||
| `vlan30 → vlan20` | 306 | **`.30.249` → HA `8123`** (203) · macmini `49152` (1) |
|
||
| `vlan10 → vlan30` | 237 | **nur** `udp/3722` → `.30.201` = das iPhone im IOT-SSID (D2) |
|
||
| `vlan10 → vlan99` | 214 | Arbeitsplatz `.10.82` → branch/ap1/ap2 `:22`/`:80`/`:443` |
|
||
| `cf-mesh → *` | **137** | `100.96.0.1` → Nautobot `8080` (62) · NAS `6690` (46) · macmini/NAS/branch/ap1/ap2 `:22` · pve `8006` · pve-mcp `3000` |
|
||
| `vlan10 → vlan10` | 17 | same-VLAN mDNS `5353` (vom Repeater auf dem Core) |
|
||
| **`vlan40`/`vlan50`/`vlan90`** | **0** | ➡️ **D6 bestätigt: Internet-only-Pinning ist risikofrei.** `out:bridge` kommt **nicht mehr vor** (VLAN1-Rückbau hält). |
|
||
- **Entscheidungen (User 2026-08-17):** **D1 = MAIN→INFRA pauschal** (MAIN *ist* das Trusted-VLAN; 13 Einzelports
|
||
wären eine Wartungsfalle, die bei jedem neuen Dienst still bricht). **D4 = MGMT named sources** — MAIN komplett
|
||
+ HA `.20.105:8728` + Nautobot `.20.30:22` + `cf-mesh`, Rest drop. **D5** = beobachtetes `8123` + MQTT als Absicht;
|
||
**Influx `8086` NICHT** (nie beobachtet, der Weg läuft über HA).
|
||
- 🎯 **ABNAHME am Gerät bestanden:** 11 Regeln (`*1B`–`*25`) existieren, `disabled=false`, **alle vor der Log-Regel**
|
||
(`place-before`, sonst wäre das Gate unten nicht messbar), Selbstprotokoll `tp5e2: ENDE whitelist-regeln=11`.
|
||
**Und der Zähler der Log-Regel steht: 54.129 bei 14:17:06 und unverändert bei 14:18:13; die letzte Zeile im
|
||
Kollektor ist `14:17:16` — genau der Deploy-Zeitpunkt.** Die Regel ist also **verstummt**.
|
||
- ⚠️ **Aber das ist noch KEIN Freibrief für Etappe 3.** 70 Sekunden Stille sind keine Aussage — das Runbook
|
||
verlangt bewusst „einige Tage", weil Geräte existieren, die **einmal pro Woche** funken (Backup-Jobs,
|
||
Drucker-Discovery). **Gate für Etappe 3: mehrtägiges Fenster ohne neue Zeilen.**
|
||
- 📌 **Zwei Dinge müssen VOR dem Drop passieren:** (a) **D2** — iPhone `.30.201` ins MAIN-SSID umhängen
|
||
(Hands-on Christoph); solange es im IOT-SSID hängt, killt der Drop die 237 `udp/3722`-Flows. Eine Whitelist
|
||
darauf wäre instabil, weil iOS **pro SSID** eine eigene Private Address vergibt. (b) `seal-lan` verengen (D4
|
||
`input`-Teil), was zugleich die 5 toten mDNS-`input`-Regeln scharf schaltet.
|
||
- ✅ **ABNAHME DES VLAN1-RÜCKBAUS BESTANDEN (2026-08-16): `out:bridge` = 0.** 10-Minuten-Messfenster nach dem Wiederanschalten, Logdatei vorher geleert. Vorher waren `vlan20 → bridge` **76 %** des gesamten Inter-VLAN-Verkehrs. Die Rate fiel von ~166 auf ~34 Zeilen/min — der Rückbau hat das Log auf echten Nutzverkehr eingedampft. Wiederaufnahme über `routeros/tp5-etappe1-resume.rsc` (GC, Backup `core-pre-tp5-resume-20260815.backup`).
|
||
- 📊 **Beobachtete Matrix, 339 Zeilen / 10 min** — das Arbeitsmaterial für Etappe 2:
|
||
|
||
| Paar | Zeilen | was genau |
|
||
|---|---|---|
|
||
| `vlan20 → vlan99` | 126 | **HA `10.40.20.105` → `10.40.99.2:8728` + `10.40.99.11:8728`** (je 67) = der Management-Pfad |
|
||
| `vlan20 → vlan30` | 85 | HA → IoT: `.30.211:80` (44), `.30.8:10081` (22), `.30.244:8080` Nuki (22), `.30.5:631` Drucker (4) |
|
||
| `vlan10 → vlan20` | 65 | Arbeitsplatz → INFRA |
|
||
| `vlan20 → vlan10` | 61 | INFRA → MAIN |
|
||
| `vlan10 → vlan10` | 2 | **mDNS `10.40.10.183:5353 → 10.40.10.82:5353`** — s.u. |
|
||
|
||
- 🔑 **D4 ist damit belegt, nicht mehr geschätzt:** der Management-Pfad ist **HA** (`10.40.20.105`), das über seine vier `mikrotik`-Integrationen `8728` auf branch/ap1/ap2 pollt (core `.99.1` erscheint nicht, weil das `input` ist, nicht `forward`). Dazu MikroMCP vom Arbeitsplatz. **Ohne Whitelist sperrt der spätere Drop die Verwaltung des eigenen Netzes aus.**
|
||
- ⚠️ **Neuer Merkposten für Etappe 3 — same-VLAN-Verkehr erreicht die `forward`-Kette:** `vlan10 → vlan10`, unicast **mDNS** zwischen zwei MAIN-Clients, erzeugt vom mDNS-Repeater auf dem Core. Zwei Pakete in 10 Minuten, harmlos — **aber ein blanker Drop am Kettenende würde sie treffen** und damit Discovery *innerhalb* von MAIN beschädigen. Zusammen mit `accept out-interface-list=WAN` die zweite Regel, die bekannt ist und nicht aus dem Log wiederentdeckt werden muss.
|
||
- ✅ **D2 vollzogen:** iPhone ist im MAIN-SSID, `10.40.30.201` steht im ARP auf `failed`.
|
||
- ✅ **Etappe 1 ausgerollt 2026-08-14** (über Nautobot GC, manual Config Plans; Backups `core-pre-/post-tp5-etappe1-20260814.backup`). Auf dem Gerät: `forward`-Regel `action=log log-prefix="TP5-WOULD-DROP"` am Kettenende, Syslog-Action `tp5syslog` → **Kollektor `10.40.20.18:514`** (syslog-ng-Container `tp5-syslog` auf dem Docker-LXC, Logs `/opt/tp5-syslog/log/`, 10-Minuten-Cron kappt bei 500 MB — der LXC hat nur ~2,5 GB frei). `firewall` ist aus dem Memory-Ring genommen (`topics=info,!firewall`), sonst wäre der On-Box-Log tagelang unbrauchbar. **Blockiert nichts.** Artefakte: `routeros/tp5-etappe1-log-lauf.rsc`, Push-Werkzeug `nautobot/gc-manual-plan.py`. Compliance danach **16/17** (der eine Rotpunkt `ip-address` = bekannte VLAN1-Bring-up-IP `10.40.41.211` aus dem TP22-Backlog, **keine neue Drift**).
|
||
- 🔴 **Fund aus dem Log-Lauf, der Etappe 3 bestimmt: die Regel fing anfangs auch allen Internet-Verkehr** (`out:vlan100`, ~¼ der Zeilen in einer ruhigen Minute, unter Last mehr). Die Log-Regel steht deshalb jetzt auf `out-interface-list="!WAN"`. **Konsequenz für den späteren Drop: er darf NICHT bare ans Kettenende** — davor gehört `accept out-interface-list=WAN`, sonst ist das ganze Haus offline. Diese Whitelist-Zeile ist damit bekannt und muss nicht aus dem Log wiederentdeckt werden.
|
||
- 🔍 **Erste Befunde nach 60 s** (Rate nach Einengung ~166 Zeilen/min): **76 % des Inter-VLAN-Verkehrs ist `vlan20 → bridge`, also INFRA nach VLAN1** — ein Monitoring-Host `10.40.20.151` scrapet ~10 tote/alte `10.40.41.x`-Ziele, HA `.20.105` zieht auf `10.40.41.100:8006` (pve unter seiner **alten** VLAN1-Adresse, real `.20.100`), `.20.107` auf `10.40.41.10:8080`. **Das ist TP19-Material, das TP5 gerade sichtbar macht.** Weiter: `vlan20 → vlan99:8728` (MikroTik-API auf branch/ap1/ap2 = **der Management-Pfad selbst**, muss in die Whitelist, betrifft D4), `vlan20 → vlan30` (HA → Drucker `.30.5:631`, Shelly, Nuki `.30.244:8080`), `vlan10 ↔ vlan20` (Synology Drive `6690`, Apple-Continuity `udp/3722`).
|
||
- ✅ **D2 entschieden (User 2026-08-14): iPhone wird ins MAIN-SSID umgehängt.** Faktenlage war: `10.40.30.201`, dynamische Lease, Hostname `iPhone`, MAC `12:99:A6:AC:B0:CB` = iOS Private Wi-Fi Address, aktiv auf `dirtyvader-iot` mit 748 MB rx. Die statische Reservierung `10.40.10.196` „iPhone" (andere private MAC — iOS vergibt **pro SSID** eine eigene) belegt, dass es dasselbe Telefon ist. **Umhängen ist die Hands-on-Aufgabe von Christoph** (SSID am Gerät wechseln + `dirtyvader-iot` vergessen lassen); technisches Argument: eine Whitelist auf eine rotierende Private MAC wäre ohnehin instabil.
|
||
- 📋 **Session-Runbook liegt (2026-08-14): `docs/tp5-deny-by-default-runbook.md`** — Ist-Stand live erhoben, **beobachtete Inter-VLAN-Flow-Matrix** (conntrack + Counter), 6 offene Entscheidungen (D1–D6), 4 Etappen mit Absicherung, Verifikation + Rollback. **Kernansatz: Etappe 1 ist ein reiner Log-Lauf ohne Blockierung** (`action=log` ans Ende von `forward`) — die Whitelist wird aus dem Log abgeleitet, nicht am Schreibtisch geraten. Drei Funde, die vorab eine Entscheidung brauchen: ein **iPhone sitzt in VLAN30**, ein **ICMP-Dauersweep von `.10.82` auf alle Shellys**, und **vlan99 ist Mitglied der `LAN`-Liste** (→ `seal-lan` erlaubt Mgmt-Input aus jedem VLAN). **VLAN50/90 tragen null Inter-VLAN-Verkehr** → Internet-only-Pinning ist dort risikofrei.
|
||
- **Deny-by-default + least-privilege** (Ziel). MAIN→INFRA nur Whitelist-Dienste; MAIN↔MEDIA allow (+mDNS); UNTRUSTED/GUEST nur Internet; MGMT isoliert; Router-input gehärtet.
|
||
- ⚠️ **Gerätewechsel beachten (2026-08-14 nachgetragen):** der ✅-Block unten war ursprünglich **auf ap1** verifiziert (2026-07-02) — ap1 ist seit 2026-08-08 Werksreset und reiner AP. Die Regeln sind beim Core-Cutover (TP21.1) mitgewandert, waren am neuen Gerät aber **nie gegengeprüft**. Am **2026-08-14 auf `crs326-core` live nachverifiziert** (`list_firewall_rules`, chains `forward` 13 Regeln / `input` 12 Regeln): **alle unten gelisteten Regeln existieren, sind enabled, tragen ihre `TP5:`/`TP10-seal-`-Kommentare und zählen Traffic.** Merkregel: nach jedem Rollenwechsel eines Geräts gilt eine Verifikation vom Vorgänger nicht weiter.
|
||
- ✅ **Bereits live** (ap1 2026-07-02 → **re-verifiziert auf `crs326-core` 2026-08-14**):
|
||
- `forward accept vlan10↔vlan40` — TP5: MAIN↔MEDIA (AirPlay/Sonos)
|
||
- `forward accept vlan20↔vlan40` — TP5: INFRA↔MEDIA (HA↔Sonos)
|
||
- `input accept udp/5353 vlan10/vlan20/vlan30/vlan40` — mDNS-Repeater (TP7-Anschluss)
|
||
- `forward accept vlan90↔vlan40` + `input accept udp/5353 vlan90` — **GUEST→MEDIA (Sonos/Cast), permanent** (TP7.2, 2026-07-03)
|
||
- **WAN-Input-Seal komplett** (TP10-seal-est/inv/dhcp/icmp/lan/wandrop + WG-Hub UDP/51821 accept)
|
||
- ⏳ **Offen:** Deny-by-default am Ende von `forward` (**live bestätigt 2026-08-14: die `forward`-Kette endet nach `TP5: MEDIA->GUEST` ohne Drop → alles nicht explizit Erlaubte läuft durch**); UNTRUSTED/GUEST auf Internet-only pinnen; MGMT isolieren; IoT→INFRA-Whitelist bauen.
|
||
- 🔍 **Befund beim Re-Verify (2026-08-14) — die 5 `TP5: mDNS in vlanXX`-Input-Regeln sind derzeit tot:** sie stehen **hinter** `TP10-seal-lan` (`in-interface-list=LAN`, action=accept), das jeden LAN-Input schon vorher annimmt → Counter aller 5 mDNS-Regeln stehen auf **0 Pakete**, während `seal-lan` 3,5 Mio. zählt. **Kein Fehler und nichts zu tun** — sie sind die Vorbereitung auf genau den Schritt, der noch aussteht: sobald der Router-`input` gehärtet wird (`seal-lan` verengen/entfernen), werden sie scharf. **Falle für die TP5-Session: erst `seal-lan` verengen, DANN testen** — vorher beweist ein grüner mDNS-Test gar nichts, weil er über `seal-lan` läuft.
|
||
- 📌 **Ausgangslage für die Umsetzung (Live-Stand `crs326-core`, 2026-08-14):** `forward` = defconf (est/rel/untracked accept · fasttrack · drop invalid · drop WAN !dstnat) → 2× TP10-WG → 6× TP5-Holes (MAIN↔MEDIA, INFRA↔MEDIA, GUEST↔MEDIA), **kein abschließender Drop**. `input` = TP10-seal komplett (est/inv/dhcp/icmp/lan/wandrop) + WG-Listen 51821 + 5× mDNS. Der Deny-by-default-Griff ist damit **eine Regel am Ende von `forward`** plus die Whitelists davor — nicht ein Umbau der Kette. ⚠️ **Governance:** läuft über Nautobot GC (`ip-firewall-*`-Features aus TP22), **nicht** per Direkt-Write; vorher `/system backup` (TP22-Regel 3). ⚠️ **Rettungspfad:** ein zu früh gesetzter Drop killt Mgmt/DHCP/DNS quer durchs Haus — Reihenfolge Whitelists zuerst, Drop zuletzt, und `device-mode` auf core erlaubt scheduler → **Auto-Revert-Scheduler als Sicherung ist hier möglich** (anders als auf den hAPs).
|
||
- 🔊 **Im Paket enthalten (User-Vorgabe 2026-08-14): der macOS-Sonos-Client-Fix.** Ist-Stand: **iOS-App findet alles** (mDNS via Repeater ✅), **HA steuert/gruppiert sauber** (Sonos-Panel, via static hosts + `advertise_addr`, TP7.2 ✅) — **nur die macOS-Desktop-App findet die Sonos-Umgebung nicht.** Ursache ist bekannt und **keine Firewall-Frage**: die Desktop-App entdeckt per **SSDP (UDP 1900)**, und RouterOS reflektiert **nur mDNS, kein SSDP** → die Discovery quert die VLAN-Grenze MAIN(10)→MEDIA(40) nicht. Die `forward accept vlan10↔vlan40`-Regel ist bereits offen und hilft hier nicht, weil das Problem *vor* dem Verbindungsaufbau liegt. **Fix = SSDP-Reflector (TP7.1)** auf NAS/pve (nicht am Router — kein Flash) mit Bein in vlan10 + vlan40, plus `input accept udp/1900` auf den bedienten VLANs. **TP7.1 wird damit aus „vorgemerkt" in dieses Arbeitspaket gezogen** und ist mit der Deny-by-default-Arbeit gemeinsam zu testen (sonst prüft man zweimal dieselbe Strecke).
|
||
- **IoT→INFRA-Rückmeldung (deine Frage):** IoT darf **aktiv** zu INFRA-Diensten initiieren — Firewall-Allow IoT→INFRA NUR auf **MQTT (1883/8883), HA-API, InfluxDB (8086)** o.ä.; Antworten via established/related; IoT→MAIN bleibt deny. So pusht ein Sensor Daten an HA/MQTT/Influx, ohne dass IoT „frei" ist.
|
||
- Abh.: TP4 ✅ (L3-Basis, Rolle inzwischen auf `crs326-core`), **TP14.5 ✅** (Freigabe-Gate), **TP22 ✅** (GC-Deploy-Pipeline = der vorgeschriebene Weg für den Push). **Keine offenen Blocker mehr — TP5 ist der kritische Pfad.** Folge: **TP6 (CAKE)**. Hängt dran: **TP5.1** (DNS-Redirect/Torch für Low-Trust).
|
||
|
||
### 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.
|
||
|
||
### TP6 — QoS/CAKE + Call-Quality-A/B-Test ▸ DAS Ziel
|
||
- **CAKE am WAN-Upload** (~85–95 % Linerate) → Bufferbloat weg. Verifikation waveform.com → A/A+.
|
||
- ⚠️ **Vor „Erfolg":** A/B-Test, denn Kollegen-Befund sagt DE-Calls = **internat. Pfad AT↔DE**, nicht Heimnetz → ggf. **WARP** statt/zusätzlich CAKE. Nicht am einen Telefonat festmachen.
|
||
- Abh.: TP4.
|
||
|
||
### TP7 — Media-Discovery (mDNS) für VLAN 40 ▸ ✅ FERTIG (2026-07-02) — `docs/tp7-mdns.md`
|
||
- ✅ **Built-in mDNS-Repeater** aktiv — **Live-Stand `crs326-core` (verifiziert 2026-08-14):**
|
||
`mdns-repeat-ifaces=vlan10,vlan20,vlan30,vlan40,vlan90` → MAIN/INFRA/IOT/GUEST ↔ MEDIA. Reversibel (Feld leeren).
|
||
📌 **`bridge` (=VLAN1) ist nicht mehr dabei** — mit dem VLAN1-Retirement erwartbar und korrekt, war aber nie nachgezogen.
|
||
*Historische Fassung (ap1, bis 2026-08-08): `…,vlan90,bridge` — `bridge`=VLAN-1 seit TP7.2 2026-07-03.*
|
||
Realbestand: MAIN=iOS-Client + MacBook, INFRA=Home Assistant, MEDIA=10× Sonos (siehe `docs/sonos-inventar.md`).
|
||
- ✅ **Funktional durchgetestet (2026-07-02):** iOS-Sonos-App (vlan10) **und** Home Assistant (vlan20) finden die
|
||
9 online-Sonos per `_sonos._tcp.local.` (Bonjour) automatisch. Household nicht mehr gesplittet.
|
||
- ✅ **TP5-Anschluss live:** `forward accept vlan10↔vlan40` + `forward accept vlan20↔vlan40` + `input accept udp/5353`
|
||
auf vlan10/20/30/40 sind gebaut (mit „TP5:"-Kommentar), damit Discovery + Steuerung + Streaming ohne Umwege gehen.
|
||
- ⚠️ **SSDP/Cast (UDP 1900) bewusst NICHT gebaut** (bräuchte Reflector-Container auf NAS/pve; hAP hat kein USB/Flash).
|
||
Konsequenz: **macOS-Desktop-Sonos-App nutzt SSDP → quert die VLAN-Grenze NICHT** und findet die Sonos nicht.
|
||
iOS-App (mDNS) und HA-Integration decken den Nutzungsbedarf ab; Spotify Connect läuft über Cloud.
|
||
- Abh.: TP4 ✅, TP5 (Sonos-Holes) ✅ live.
|
||
|
||
### TP7.1 — SSDP-Reflector (macOS-Sonos-App über VLAN-Grenze) ▸ 🔜 **IN TP5 GEZOGEN (User-Vorgabe 2026-08-14)** — nicht mehr „vorgemerkt"
|
||
- 📌 **Status-Update 2026-08-14:** Symptom vom User erneut bestätigt — **iOS-App ✅, HA-Sonos-Panel ✅ (steuern/gruppieren), macOS-Desktop-App findet die Umgebung nicht.** Damit ist das Bild vollständig: alles, was **mDNS** spricht, funktioniert; nur der **SSDP**-Weg fehlt. Der Fix wird **Bestandteil des TP5-Pakets** (gemeinsamer Test mit Deny-by-default statt zweimal dieselbe Strecke prüfen). ⚠️ **Nicht als Firewall-Problem fehldiagnostizieren:** `forward accept vlan10↔vlan40` ist längst offen — es scheitert an der Discovery, nicht am Datenpfad.
|
||
- **Bedarf:** macOS-Desktop-Sonos-App auf VLAN 10 findet die Sonos in VLAN 40 nicht (Discovery per SSDP UDP 1900,
|
||
RouterOS reflektiert kein SSDP). iOS-App + HA decken den Alltag ab, aber User will die Desktop-App nutzen.
|
||
- **Lösung:** kleiner SSDP-Reflector-Container mit Bein je Ziel-VLAN. Auf **NAS oder pve** (nicht am hAP, 128 MB
|
||
Flash + kein USB). Kandidaten: `bkupreck/ssdp-repeater`, `scyto/multicast-relay`, oder eigenes Python-Skript.
|
||
- **Scope:** vlan10 ↔ vlan40 (MacBook → Sonos). Optional vlan20 ↔ vlan40 falls HA je SSDP-Discovery brauchen sollte
|
||
(aktuell nicht — HA nutzt zeroconf/mDNS).
|
||
- **Anschluss TP5:** `input accept udp/1900` auf den bedienten VLANs (falls Router-lokal reflektiert wird) bzw.
|
||
Container-Port-Freigaben je Bein.
|
||
- **Alternative (verworfen):** macOS-Client temporär in VLAN 40 hängen (unpraktikabel für Alltagsnutzung).
|
||
- Abh.: TP7 ✅. Kein Blocker für TP5-Deny-by-default.
|
||
|
||
### TP7.2 — HA↔Sonos static-host binding + VLAN1/GUEST-Discovery ▸ ✅ FERTIG (2026-07-03) — `docs/sonos-inventar.md`
|
||
- **Root Cause (widerlegt frühere Doku):** HA-`media_player.*`-Sonos alle `unavailable`. HA sitzt **nicht** auf
|
||
VLAN 20, sondern noch auf `10.40.41.105` (VLAN-1-Transfernetz, IP-Migration steht aus). Der mDNS-Repeater
|
||
deckte VLAN 1 **nicht** ab, und die HA-Sonos-Integration ist **SSDP-abhängig** (`manifest dependencies:[ssdp]`,
|
||
soco 0.31.1) → quert die VLAN-Grenze nicht. Die alten „HA nutzt mDNS/zeroconf, fixed 2026-07-02"-Notizen waren falsch.
|
||
- ✅ **HA-Fix (discovery-unabhängig):** `sonos: media_player: hosts:` mit allen 11 Sonos-IPs + `advertise_addr: 10.40.41.105`
|
||
in `configuration.yaml` (Backup `.bak-sonos-20260703`). `advertise_addr` fixt die UPnP-Event-Callbacks trotz
|
||
HA-Multi-Homing (`.105`/`172.16.0.18`/docker). Core-Restart → alle 6 Online-Zonen `idle/playing` (Wohnzimmer-Push
|
||
verifiziert = Callbacks OK). Terrasse `.198` offline = kein Entity (kommt beim Einschalten). Kurzes Flapping direkt
|
||
nach Restart = Settling, danach stabil.
|
||
- ✅ **Nebeneffekt:** mit `bridge` im Repeater (s.u.) meldet HA jetzt „Automatic discovery is working, hosts not needed"
|
||
— die statischen Hosts sind also Redundanz (Gürtel+Hosenträger), bleiben aber als Absicherung.
|
||
- ✅ **VLAN 1 (temp) + GUEST (perm) Discovery/Reach (User-Wunsch 2026-07-03):**
|
||
- mDNS-Repeater erweitert → `mdns-repeat-ifaces=vlan10,vlan20,vlan40,vlan30,vlan90,bridge` (VLAN-1-untagged=`bridge`).
|
||
- Firewall: `input accept udp/5353 vlan90` + `forward accept vlan90↔vlan40` (ganzes MEDIA, beide Richtungen; User-Wahl).
|
||
VLAN 1/`bridge` brauchte nichts (schon via `TP10-seal-lan` + permissiver Forward).
|
||
- **Bewusst in Kauf:** flacher Repeater → Guests sehen auch MAIN/INFRA/IOT-mDNS-Announcements (Discovery-Leak;
|
||
echte Verbindungen regelt TP5-Deny-by-default).
|
||
- **Offen/später:** HA→VLAN 20 (IP-Migration nach Omada-PVID-Fix) → dann nur `advertise_addr` auf neue IP; macOS-Desktop-App
|
||
weiter via SSDP-Reflector TP7.1. Abh.: TP7 ✅, TP5-Holes ✅.
|
||
|
||
### 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.)
|
||
|
||
### TP9 — Gateway-/Router-HA ▸ ❌ OBSOLET (User-Entscheid 2026-08-08)
|
||
- ❌ **Verworfen (User-Begründung 2026-08-08, „ganz klar nein"):** am `crs326-core` führt ohnehin **nie ein Weg vorbei** — er ist der unumgängliche L3-Durchleitungspunkt. Ein zweites Gerät / VRRP **beseitigt diesen SPOF nicht**, sondern baut nur **zusätzliche Sollbruchstellen** ein (2× Config-Sync für DHCP/DNS/Firewall/NAT, Split-Brain-Risiko, VRRP-Eigenfehler) → netto ein Zuverlässigkeits-**Verlust**, kein -Gewinn. Die Frage ist nicht „Aufwand vs. Nutzen", sondern „mehr Fehlerquellen einbauen?" → nein. DR-Weg = Config-Backup-Restore (+ ggf. AP-Reprovisionierung). VRRP-Skizze unten = nur noch historische Recherche.
|
||
- **„Was, wenn ap1 ausfällt?"** → **VRRP** löst Gateway-Failover je VLAN ~gratis (kreuzweise Master/Backup).
|
||
⚠️ **Haken (nicht Last):** DHCP/Firewall/NAT/DNS müssen auf **BEIDEN** APs **identisch** gepflegt sein, sonst „Gateway up, Internet tot".
|
||
**Empfehlung:** VRRP nur für **MAIN/INFRA**, sonst ap2 als **Kalt-Ersatz** + Backup. DHCP/DNS schon redundant (Split + 2 Resolver).
|
||
- Abh.: TP4. (Research erledigt, s. TP-R + Config-Skizze im Report.)
|
||
|
||
### TP10 — Multi-Site VPN ▸ ✅ KERN DURCH (2026-06-27) — beide WG live auf ap1-Hub (`docs/tp10-vpn-migration.md`)
|
||
> **Details/Cutover/Gotchas/Eckdaten → `docs/tp10-vpn-migration.md` (Single Source of Truth).** Research: `docs/research/vpn-comparison.md`.
|
||
- **✅ KERN DURCH (2026-06-27) + EDGE-CUTOVER (2026-07-01):** beide AVM-Tunnel → **2× WireGuard mit Hub auf ap1** migriert. Live: `peer fm`
|
||
(`10.101.0.0/24`, bidirektional, myfritz-Endpoint) **und** `peer dw` (`10.95.10.0/24`, CGNAT-Dial-in) mit frischem
|
||
Handshake + Traffic. **Public-Edge direkt** — ap1 hört UDP/51821 auf `vlan100` (Edge-Cutover 2026-07-01), keine
|
||
FB-Portfreigabe mehr, kein Double-NAT. FM-IPsec gekillt, Gelis alter FB↔FB-WG sauber geswappt.
|
||
- **✅ DW/Geli on-site verifiziert (2026-06-27):** Geli auf `10.95.10.0/24` renumbert, FB-WG single `10.95.10.1/24`,
|
||
Keepalive 25, Endpoint `bf4…:51821`. End-to-End von macmini/Linz → Gelis 24/7-APs `10.95.10.246/.247` sauber
|
||
(echte LAN-IPs, **kein `10.255.255.x`**-NAT-Leak).
|
||
- **💡 Root Cause (FM-PoC bewiesen):** FB masqueradet WG, wenn die Interface-`Address` eine **Transfernetz-IP** ist →
|
||
muss die **FB-LAN-IP** sein (AVM Proxy-ARP). War der Schlüssel zum sauberen LAN-LAN.
|
||
- **Hub:** `wg-hub` (UDP 51821, Key `P/bzt…`, MTU 1412, keine IF-IP). Endpoint = DDNS **`bf4.emsenhuber.net:51821`**
|
||
(Cloudflare, DNS-only → Public-IP). Apply gebündelt in `routeros/tp10-cutover-apply.rsc`.
|
||
- ✅ **Permanenter Edge-Cutover durch (2026-07-01)** — Details in TP4 (WAN via sw1 vlan100, ap1 = Public-Edge,
|
||
WAN-Input-Seal live). BF-FB-eigenen WG-Server 51820 entfällt (FB physisch weg).
|
||
- **Offen:** DDNS-Auto-Updater für `bf4.emsenhuber.net` auf NAS/pve, damit der A-Record der Public-IP folgt
|
||
(falls Liwest sie tauscht). Aktuell manuell in Cloudflare gepflegt.
|
||
|
||
### 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.
|
||
|
||
### TP13 — „Botschafts-WLANs" ▸ 🔜 VORBEREITET (2026-08-08), fun/low-prio
|
||
- **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) bzw. in ein isoliertes Dummy-VLAN → reine Beacon-SSID (kein DHCP/Uplink). Captive-Portal-Variante: RouterOS-**Hotspot** auf eigenem isoliertem VLAN (Guest-Ableger) mit `walled-garden` auf die lokale Info-Seite (HTML als hotspot-Ordner am Gerät oder via NAS-nginx).
|
||
- **Umsetzungs-Skizze:** (1) SSID-Namen + Info-Text final; (2) Beacon-SSIDs in `routeros/.secrets/ap{1,2}-prov-base.rsc` ergänzen (identisch auf beiden APs, via Nautobot-GC generierbar); (3) optional Hotspot-VLAN + walled-garden + Info-HTML; (4) beide APs deployen.
|
||
- ⚠️ **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); ideal nach TP21/TP22 (dann via Golden Config statt Direkt-Edit).
|
||
|
||
### TP14 — Host/Container-IP-Migration VLAN1→VLAN20 (Docker-Cutover NAS+pve) ▸ ✅ DURCH (2026-07-13; live re-verifiziert 2026-08-08) — `docs/nas-vlan20/RUNBOOK.md`, Handoff `docs/nas-vlan20/handoff/`
|
||
- ✅ **ABGESCHLOSSEN — Migration komplett** (Live-Check 2026-08-08 vom core: NAS `.20.10`, pve `.20.100`, Docker-LXC `.20.126`, platform-pg `.20.20`, Nautobot `.20.30` alle 0% Loss). Alle Hosts + Container auf VLAN20. **TP14.4** (CF-Access-Token-Rotation) = kleiner, nicht-blockierender Standalone-Follow-up (CF/TP11-Umfeld); **TP14.5** war nie ein eigener Change (nur ein Reihenfolge-Gate) → erfüllt, TP5 damit entblockt.
|
||
- ✅ **NAS (DS923, ep14) migriert (2026-07-09/10):** Docker von `default_external` (macvlan .41) auf **ein** `vlan20`-Macvlan (10.40.20.0/24, gw .1, parent `ovs_eth0`); DSM-Cutover `.20.10`; Portainer-Endpoint `.20.10:9001`. **Root-Cause der Dauerfehler** = Portainer **Config-Only-Macvlan-Falle** (`Driver:null`, kein Container-Attach) + Macvlan-Parent-Exklusivität (`default_external` muss weg für `vlan20`) + `default_internal` (172.18) weg. Container laufen auf `.20.x`.
|
||
- ✅ **CF-Ingress v116 (2026-07-10):** 6 NAS-Origins .41→.20 (SSoT `docs/cf-tunnel-mapping.md` §8); `vw` 200 via Tunnel = pve→VLAN20-Routing steht (502 direkt nach Ingress-PUT = transient).
|
||
- ⚠️ **Abh./Reihenfolge:** verzahnt mit Omada-PVID-Fix/IP-Migration (Reihenfolge #3); Sessions = Sub-TPs **TP14.1–14.5**, sequenziell A→B→C→(D jederzeit)→E, **keine parallelen Branches** (geteilte Live-Infra). Anschlussstatements: `docs/nas-vlan20/handoff/README.md`.
|
||
- ✅ **TP14.1 (Session A) durch 2026-07-10:** alle ep14-Container auf vlan20 + pve-mcp neu; nur Omada-Inform-Adresse offen (Controller-UI-Task, s.u.).
|
||
- ✅ **TP14.2 (Session B) durch 2026-07-10:** pve-LXC (400/`docker`) auf VLAN20 (.20.126, ipvlan `parent=veth20`); omada-mcp/adguard→.20.x; CF-Connector jetzt VLAN20 = **#1033 gelöst**. Nächste Session = **TP14.3 (Session C, dormante Stacks + Referenz-Sweep ap1-DNS)**.
|
||
- ✅ **Netz-Abgleich 2026-07-11 (live via MikroMCP/pve-mcp):** **NAS `.20.10`, Mac mini `.20.167`, pve-LXC `.20.126`** alle reachable auf VLAN20 (+ Container `.20.x` populiert; `iobroker .107`/`ccu .232`/`z2m .106`/`vw .127` jetzt auch VLAN20). Sonst in VLAN1 (bridge) nur noch: sw1 `.11`/sw2 `.12`/ap2-Mgmt `.2` (Switch-/AP-Mgmt, interim bis MGMT-VLAN99) + Streu-Clients übers cudy-Alt-WLAN (MacBook `.182`, iPhone `.186`, SwitchBot `.184`, Sonoff) + die 16 VLAN1-Shellys (TP17). `defconf`/pool-v1-DHCP auf `bridge` läuft noch (VLAN1 aktiv).
|
||
- ✅ **pve-Host-Mgmt → VLAN20 (2026-07-13):** letzter verbliebener Host-Umzug. `vmbr0` bleibt VLAN1 `.41.100` (ohne Default-Route, interim), neues `vmbr0.20` (bereits vorbereitet, aber mit kaputter `address 10.40.20.0/24` vorgefunden) korrigiert auf `10.40.20.100/24` → `ifreload -a` live (ifupdown2, kein Reboot, LXC 400 durchgehend unbeeinflusst) → Default-GW auf `10.40.20.1` geflippt. SSH-Key-Auth bestätigt auf `.20.100`. Nachgezogen: ap1-DNS (`pve.bf.lan`→`.20.100`; dabei Fund+Fix eines Alt-Bugs: `pve-mcp.bf.lan` zeigte noch auf `.41.173` statt `.20.173`), CF-Tunnel `bf-pve` Ingress (`pve`+`j44d6tua`-SSH-Hostname .41.100→.20.100, PUT via `CF_API_TOKEN`, Smoke 200/200), CLAUDE.md, `docs/ip-plan.md`. `~/.claude.json` war schon sauber.
|
||
|
||
### TP14.1 — Session A: NAS fertigstellen ▸ ✅ DURCH (2026-07-10); Omada-Inform/sw2 VERTAGT
|
||
- ✅ **Alle ep14-Container auf vlan20 redeployed + verifiziert running/.20.x** (via Portainer-Stack-Redeploy, Env preserved, Volumes intakt): oc-stack(112 → prometheus `.151`/node-exporter `.154`/grafana `.109`), default(72 → hms-mqtt `.124`), nginx(101 → dashboard-web `.148`), oc-central(160 → qdrant `.159`), oc-charlie(158 → `.162`+cf), oc-johnny2(150 → `.161`+cf), gitea(111 → `.157`, DB `.20.23:3306` erreichbar ✓), drawio(107 → `.139`, intern; CF-CNAME war eh gelöscht).
|
||
- ✅ **pve-mcp NEU** als Stack (id 202, vlan20-only `.20.173`), verbunden mit Proxmox `.41.100` (v9.0.11) — ⚠️ **StreamableHTTP am Root-Pfad `/`, NICHT `/sse`** (mcp-pve v0.4.8, `MCP_TRANSPORT=http`). `~/.claude.json` `mcpServers.pve-mcp` NEU angelegt `{type:http, url:http://10.40.20.173:3000/}` (war vorher gar nicht drin) → wirkt nach Claude-Code-Restart.
|
||
- ✅ **Tunnel-Smoke** (CF-Ingress v116 zeigte schon auf `.20`): gitea 200, grafana 302, vw 200 — Origins existieren jetzt real.
|
||
- ⚠️ **alertmanager `.153`**: korrekt an vlan20, aber **crash-loop wegen PRE-EXISTING Config-Bug** (`${TELEGRAM_CHAT_ID}`-Literal in `/etc/alertmanager/alertmanager.yml` → int64-Parse-Fehler; Alertmanager macht kein Env-Substitution). NICHT migrationsbedingt, braucht echte chat_id. Out-of-scope.
|
||
- ⚠️ **openclaw-DB `10.40.41.122:3306` down** (shared MariaDB, pre-existing; Bots kamen trotzdem hoch). `DB_HOST`-Env unverändert gelassen. `OLLAMA_BASE_URL=.41.167`=Mac-mini bleibt korrekt `.41` (migriert nicht → **kein Blanket-Env-.41→.20!**).
|
||
- ⚪ **OBSOLET (2026-07-16) — ~~omada-controller Inform-Adresse + sw2 re-adopt~~:** ursprünglich vertagt (2026-07-10, Controller-Login schlug fehl). Gegenstandslos seit TP2.1: der Controller-Login-Ausfall eskalierte zum Werks-Reset von sw2, User hat daraufhin entschieden, sw2 **dauerhaft standalone ohne Controller** zu betreiben — und den Omada-Controller-Container samt omada-mcp am 2026-07-16 **komplett gelöscht** (overkill für 1 Switch auf der Abschussliste, s. TP15/CRS326). Kein Re-Adopt mehr vorgesehen.
|
||
- 🐞 **Gotcha gefunden:** Portainer-Stack 111 (gitea) hatte den `vlan20`-Networks-Block **auskommentiert** (Vorsession-Artefakt) → Container landete auf `gitea_default`/172.18. Fix = Redeploy mit Disk-File `docs/nas-vlan20/stacks/111-gitea.yml` als Override.
|
||
|
||
### TP14.2 — Session B: pve-Docker-LXC (.126) → VLAN20 ▸ ✅ DURCH (2026-07-10) (ipvlan)
|
||
- ✅ ep2-Container auf `vlan20`: **omada-mcp `.20.176`** (OMADA_BASE_URL→`.20.175`), **adguard_bf1 `.20.16`**, **adguard_fm2 `.20.17`** — alle running/reachable (health 200, adguard 302). Transf. Files `docs/nas-vlan20/stacks/{195-adguard,200-omada-mcp}.yml`.
|
||
- ✅ LXC 400 (`docker`) net0 → `tag=20, ip=10.40.20.126/24, gw=10.40.20.1` (⚠️ **Retag brauchte Christoph** — Token `claude@pam!claude` hat kein `VM.Config.Network`; UI-Edit, dann Reboot via API mit `VM.PowerMgmt`). Portainer wandert auf `https://10.40.20.126:9443`.
|
||
- 🐞 **Gotcha: in-Container-Iface heißt jetzt `veth20`, NICHT `eth0`** (UI setzte Name analog net1=veth16) → Docker `vlan20`=ipvlan **`parent=veth20`** (nicht eth0 wie im Runbook). cloudflared(host)/portainer(bridge) unberührt.
|
||
- ✅ **CF-Connector `db713b30` jetzt in VLAN20** (Tunnel `bf.emsenhuber.net` healthy/8 conns) = **löst TP11-Track-B/C** (#1033-Zielbild). Ingress `portainer` .41.126→.20.126. Smoke: portainer/gitea/vw 200, grafana 302.
|
||
- ✅ Refs nachgezogen: `mcp/portainer/.env` (PORTAINER_URL), `~/.claude.json` (omada-mcp `.20.176`), CLAUDE.md, `docs/ip-plan.md`, `docs/cf-tunnel-mapping.md`. Next = **TP14.3 (Session C, dormante Stacks + Referenz-Sweep ap1-DNS)**.
|
||
- ✅ **Live-Smoke re-verifiziert 2026-07-10:** alle 6 VLAN20-IPs ping OK + dienstseitig grün — Portainer `.20.126:9443` HTTP 200 (LXC 400 running, net0 `veth20 tag=20 gw/ns=.20.1`), omada-mcp `.20.176`→Controller `.20.175` v6.2.10.17 (HTTPS :8043 200), pve-mcp `.20.173` liefert Proxmox-Config, adguard `.20.16`/`.20.17` HTTP :80 302→login (nicht HTTPS/:3000).
|
||
|
||
### TP14.2a — pve-mcp Single-Session-Fix + VLAN20-Host-DNS ▸ ✅ (2026-07-10)
|
||
- **pve-mcp „Failed to connect":** Ursache = **mcp-pve v0.4.8** kann im HTTP-Transport nur **eine** MCP-Session (ein globaler `StreamableHTTPServerTransport`, `sessionIdGenerator` gesetzt) → erster Client nach Boot belegt den Slot, jeder weitere Init (neue Claude-Code-Session, `claude mcp list`-Healthcheck, Reconnect) = `400 "Server already initialized"`. **omada-mcp NICHT betroffen** (frische Session-ID pro Init → Per-Session-Transport). **Fix = Upgrade auf 0.6.1** (Per-Session-Map, `serverFactory()` je Session, gleiche Env-Vars = Drop-in); Stack 202 neu deployed, Container `.20.173` = 0.6.1, `Connected to Proxmox VE 9.0.11`, `tools/list` liefert `pve_*`, **Claude Code ✔ Connected**. 3× init hintereinander = 3× 200 mit verschiedenen session-ids (verifiziert).
|
||
- **Kollateral-Fund — VLAN20-Host-DNS kaputt (beide Docker-Hosts):** nach dem VLAN20-Umzug zeigten **NAS** *und* **pve-LXC** `/etc/resolv.conf` noch auf totes `.41.254` → `docker pull` ghcr.io scheitert (`EAI_AGAIN` / 5s-Resolver-Timeout; Egress zu ghcr-IP `140.82.x:443` = OK 31 ms, also **nur Resolver tot**, nicht Egress). Fixes: **LXC** `.20.126` → `pct set 400 --nameserver 10.40.20.1` (Christoph). **NAS** → DSM-„Allgemein"-DNS war `.20.1`, ABER die **Netzwerkschnittstelle zog DNS per DHCP** und überschrieb `resolv.conf`; Fix = Schnittstelle „DNS manuell" `10.40.20.1` (Christoph) → NAS pullt wieder direkt. **Merkregel Synology:** GUI-DNS ≠ was `dockerd` liest (Quelle `/etc/resolv.conf`, per DHCP überschreibbar). **Workaround solange NAS-DNS tot:** `docker save`(LXC, hat DNS) → **gzip** (191-MB-tar reißt am Portainer-Agent-Socket-Proxy „context canceled"; ~70 MB gz geht) → Portainer `POST /endpoints/14/docker/images/load` → Stack-Redeploy `pullImage:false`. Gotcha: laufende Container frieren den `127.0.0.11`-Upstream zum Erstellzeitpunkt ein (Recreate nötig; für pve-mcp egal — Proxmox per IP `.41.100`). Memory `ref_pve_mcp_singlesession_and_vlan20_dns`.
|
||
|
||
### TP14.3 — Session C: Dormante Stacks vlan20-tauglich + Referenz-Sweep ▸ ✅ Referenz-Sweep durch (2026-07-16); dormante Stacks weiter bewusst nicht deployt
|
||
- ✅ **Dormante Stacks bereitgestellt (2026-07-11):** `transform.py` auf core(43)/openclaw(92)/openclaw2(97)/oc20260307(119)/openspeedtest(74)/speedtest_tracker(80)/technikscheiss(42) → **`.new.yml` + `.orig.yml`** in `docs/nas-vlan20/stacks/` (gitignored). **Nicht deployt** (User: „im Bedarfsfall später", Container-Zukunft ungewiss). 42/43 waren `default_internal` → jetzt vlan20-only (DHCP-.20.x). ⚠️ **Deploy-Caveats:** externe Refs bewusst NICHT umgeschrieben (`DB_HOST=.41.122` [pre-existing tote openclaw-DB, in 80+119], `OLLAMA_BASE_URL=.41.129`, `REDIS_URL=.41.111` in 119); **Kollision** `43-core` will `.20.23` = gitea-DB-IP (nicht gleichzeitig deploybar).
|
||
- ✅ **Referenz-Sweep `.41→.20` (2026-07-16, im Rahmen der TP19-Backup-Vorbereitung live gefunden + gefixt):** ap1 `/ip dns static` hatte noch `nas.bf.lan→.41.10` und `docker.bf.lan→.41.126` **stale** — korrigiert auf `.20.10`/`.20.126` (MikroMCP `manage_dns_entry`, dry-run+apply). Zusätzlich per User-Entscheid **Omada-Controller + omada-mcp komplett gelöscht** (overkill für 1 Switch auf der Abschussliste) → DNS-Einträge `omada.bf.lan`/`omada-mcp.bf.lan` entfernt statt migriert. `fritzbox.bf.lan` (totes Gerät, physisch weg seit 2026-07-01) ebenfalls entfernt. `docs/ip-plan.md` + CLAUDE.md nachgezogen.
|
||
- ✅ **ERLEDIGT/GEGENSTANDSLOS (live geprüft 2026-08-16):** ~~`~/.claude.json` (omada-mcp-Eintrag verwaist), CF-Ingress-Rest (`omada`/`omada-mcp`-Hostnames, ungeprüft)~~
|
||
- **`~/.claude.json`:** `omada-mcp` ist **nicht mehr als MCP-Server registriert** (`mcpServers` enthält ihn nicht). Er steht nur noch in `disabledMcpServers` einiger Projekt-Scopes — ein reiner Merkposten „bewusst aus", keine Verbindungsversuche, kein Handlungsbedarf.
|
||
- **CF-Ingress:** alle 9 Tunnel durchgesehen (`cfd_tunnel` + `/configurations`) — **kein einziger `omada`-Hostname mehr**. Sauber.
|
||
- ↪️ **Shelly-Geräte-Übersiedelung ausgegliedert → TP17** (die ~26 IoT-Shellys sind eine eigenständige WLAN-Migration, nicht Teil des Docker-Ref-Sweeps).
|
||
|
||
### TP14.4 — Session D: CF-Access-Profil für Claude ▸ 🔜 TODO (nicht cutoff-kritisch)
|
||
- 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`.
|
||
|
||
### TP14.5 — Session E: Freigabe-Gate → TP5-Firewall ▸ ✅ ERFÜLLT (2026-08-08) — kein eigener Change
|
||
- Gate „TP14.1–14.3 durch (alle Origins/Connectoren in VLAN20)" ist erfüllt → **TP5 (Deny-by-default) ist entblockt.** Reines Reihenfolge-Gate, kein eigener Change.
|
||
|
||
### TP15 — HW-Refresh: Switching + Router ▸ ✅ **ABGESCHLOSSEN (2026-08-08)** — Bring-up beider CRS326 + Branch-Tausch (2026-07-23) **und** Core-Tausch/L3-Umzug (2026-08-08, Durchführung s. TP21.1) sind durch — `docs/hw-refresh-requirements.md`, Memory `project_mikrotik_commit_nautobot_gc`
|
||
> 🔌 **Scope-Änderung 2026-08-16 (User-Entscheid): die DC-USV ist aus diesem TP herausgelöst und heißt jetzt **TP24**.** Sie war der letzte offene Rest hier, hat mit Switching/Routing sachlich nichts zu tun und trägt eigene Entscheidungen (Elektrik, Batterie, Standort). TP15 ist damit inhaltlich zu.
|
||
> *Vorherige Header-Fassung (Stand 2026-08-05, überholt): „🟢 CRS326-Bring-up + Branch-Tausch DURCH (2026-07-23); Core-Tausch/L3-Umzug **vorbereitet, Cutover-Config materialisiert (2026-08-05)**, Cutover = nächstes Wartungsfenster."*
|
||
- ✅ **BRING-UP BEIDER CRS326 + BRANCH-TAUSCH gegen sw2 — DURCH (2026-07-23, Claude via REST unter Governance-Ausnahme #2).** Ablauf/As-built:
|
||
- **Zugriffsweg (Henne-Ei gelöst):** Erst-Reihenfolge war **core zuerst** (User-Korrektur — core hängt an sw1 und ist der L2-Pfad, über den branch überhaupt erreichbar wird; branch war isoliert). Zugriff auf die Werks-`192.168.88.1` über **temporäre ap1-Zweit-IP `192.168.88.2/24` + srcnat-Masquerade `192.168.88.0/24`** (beide `TP15-temp`, nach Bring-up wieder entfernt — Rückweg nötig, weil die Werks-Box keine Route zu VLAN10 hat). Config dann komplett per **REST** (`/system/script` PUT+run), kein Winbox-Paste. **Winbox-MAC-Connect scheiterte reproduzierbar** („macconnection sync timeout" über WLAN/quer durch den Fabric — braucht selben Draht).
|
||
- **Identitäten am Gerät verifiziert (nicht nur Doku):** `core` = sw-id **4W04-URHT**, MAC `04:F4:1C:B4:17:76`, Serial `HKA0AREXJFM`, PW `X9…`; `branch` = sw-id **RGZJ-UK0T**, MAC `04:F4:1C:B4:15:58`, Serial `HKA0AJJA52F`, PW `PHR…` (ap2 hängt an branch **ether24** — bridge-host bestätigt = definitiv branch). **PWs in `~/.secrets/credentials.env`.**
|
||
- **branch = produktiv, volle SOLL-Portbelegung** (User-manuell erhoben, maßgeblich): ether1 Uplink-Trunk→sw1 #8 (native VLAN1 + tagged 10/20/30/40/50/90/99, **kein 100**), ether2+ether8 = **NAS 2×tagged-VLAN20** (zwei unabhängige Links), ether3 Drucker/VLAN10, ether4 Dock/VLAN10, ether5+ether6 Sonos/VLAN40, ether7 Mac mini/VLAN20, ether24 ap2-Trunk; ether9–23+sfp disabled. vlan-filtering=yes. Mgmt **`10.40.99.13` (VLAN99)** erreichbar über sw1 #8 (+ VLAN1-Temp `.41.213` während Bring-up). **Post-Swap-Abnahme grün:** NAS `.20.10`, Mac mini `.20.167` (VLAN20), Dock `.10.194` (VLAN10), Sonos `.40.191`/`.40.192` (VLAN40).
|
||
- **core = grundkonfiguriert, NICHT produktiv** (bleibt an sw1 #12): identity/vlan-filtering/volle VLAN-Tabelle, ether1 Uplink, ether2 Temp-Downlink (war Config-Pfad für branch), Mgmt **`10.40.99.11`** (VLAN99, erreichbar erst wenn sw1 #12 99T trägt) + VLAN1-Temp `.41.211`. Port-Layout ab ether3 tentativ (final in Core-Swap-Session).
|
||
- **Beide in MikroMCP `routers.yaml`** (crs326-core/-branch, ENV `ROUTER_CRS326_*` in `~/.claude.json` — **live erst nach MCP-Neustart**, diese Session lief alles per REST-curl). **Nautobot** modelliert + GraphQL-verifiziert (`nautobot/ingest-crs326-ports.py`): branch Active + volle Ports + primary_ip4 `.99.13`; core Planned + tentatives Layout; **sw1 verifizierte 16-Port-Belegung** (löst „UNVERIFIZIERT"); **sw2 → Decommissioning**.
|
||
- 🐞 **Gotchas festgehalten:** (1) **Kabel ether3↔ether5 waren beim Umstecken vertauscht** → ein AZ-Sonos landete als Access-VLAN10 in `10.40.10.190` **und** blutete via SonosNet nach VLAN40 (= Dual-Homing-Muster, `project_dual_homing_slowness_incident`) → Kabeltausch gefixt, beide AZ-Sonos jetzt sauber VLAN40 (`.191`/`.192` bound). (2) RouterOS-Script-`policy`-Feld per REST wählerisch → **weglassen** (admin-Default = volle Policy). (3) Disable-Regex mit `^…$`-Ankern griff nicht → `[find name!="ether1" and …]` nutzen. (4) REST-`PUT`-Antwort mit mehrzeiligem `source` ist kein sauberes JSON → ID separat via `?.proplist=.id` holen. (5) Claude-Code-Auto-Mode-Classifier blockt Device-Config-*Writes* per Bash (Reads ok) → `autoMode.allow`-Regel in `.claude/settings.local.json` nötig (kann Claude sich nicht selbst setzen).
|
||
- ✅ **ERLEDIGT 2026-08-08 (Durchführung + Recovery s. TP21.1).** ~~🔜 Als Nächstes (eigene Session, Übergabe): Core-Tausch = L3-Umzug~~ (Routing/DHCP/DNS/CF-Mesh von ap1 → crs326-core) — **Vollausfall-Fenster**, s. `docs/tp15-core-swap-session-handoff-prompt.md`. Danach WLAN-Neuprovisionierung (TP3, CAPsMAN-Abbau). ~~Finaler Mgmt-Renumber dann: branch `.99.13`→`.99.12`, core bleibt `.99.11`.~~ ⚠️ **Anders gekommen (Ist seit 2026-08-08, live bestätigt): core `.99.1` · branch `.99.2` · ap1 `.99.11` · ap2 `.99.12`.**
|
||
- ✅ **Core-Swap VORBEREITET (2026-07-23, reine Prep-Session, kein Netz-Eingriff):** ap1s Live-L3-Config vollständig gelesen (MikroMCP) und als **staged Config** materialisiert → `routeros/tp15-core-l3-staged.rsc` (alles Betriebsumlenkende `disabled=yes`, im Cutover in einem Rutsch `enable`; ~50 Reservierungen + WG-Privkey bewusst erst im Fenster maschinell von ap1 geholt statt abgetippt). Runbook/Rollback/Verifikation im Plan. **3 Fenster-Start-Entscheide festgelegt:** (1) **WG-Hub (TP10 FM/DW-VPN) migriert MIT** — war im Handoff-Prompt übersehen, hängt an ap1s Public-Edge und kann dort nicht bleiben; (2) Governance = **frische Direkt-Ausnahme #3** (REST/MikroMCP), danach intended→Nautobot; (3) Rettungspfad = **iPhone-Hotspot**.
|
||
- ✅ **Nautobot-Modell + Golden-Config-Template für L3-Cutover vervollständigt (2026-08-05):** `crs326-core` jetzt Rolle *Router*, alle VLAN-SVIs (`vlan10/20/30/40/50/90/99/100`) + Gateway-IPs (`.1`) modelliert; `nautobot/mikrotik_routeros.j2` (Gitea `bf-golden-config`) erzeugt für `crs326-core` die vollständige staged L3-Konfig (Interface-Lists, GW-IPs, WAN-DHCP, DHCP-Server/Pools, DNS, NAT, Firewall, WG-Hub) und für alle anderen MikroTik-Geräte nur die Identität. Git-Sync + Generate Intended Config erfolgreich getestet; intended config für `crs326-core` liegt in Nautobot vor.
|
||
- ✅ **ap1-Cutover-Daten exportiert + in Cutover-Config eingebaut (2026-08-05):** 54 statische DHCP-Leases aus ap1 (`dhcp-v10`/`v20`/`v30`/`v40`) nach `routeros/ap1-leases-to-core.rsc` überführt; WG-Hub-Privkey von ap1 geholt und in die lokale Cutover-Config `routeros/tp15-core-cutover-intended.rsc` eingesetzt (der **WG-Privkey landet NICHT im Git-Template** — Secret).
|
||
- 🐞 **Prep-Gotchas:** (a) **MikroMCP kann core noch nicht schreiben** — `ROUTER_CRS326_CORE_*` im MCP-Prozess nicht geladen (jeder Zugriff „Missing environment variable") → vor dem Fenster MCP neu starten oder REST-curl gegen `http://10.40.41.211/rest`. (b) Mgmt-`.99.11` tot (sw1 #12 trägt kein 99T), nur VLAN1-Temp `.41.211` erreichbar. (c) **WG-Hub:** Privkey von ap1 mitnehmen (sonst FM/DW-Reconfig nötig). (d) core-vlan99 wird GW `.1`; Bring-up-`.11` dadurch redundant (Fenster-Reconcile). (e) VLAN1 raus: Hybrid-VLAN1-Drops sw1 GE3/7/10 beim Umstecken einem echten VLAN zuordnen oder stilllegen.
|
||
- ✅ **WG-Endpoint-Frage geklärt (2026-07-23):** Spokes adressieren den Hub über `bf4.emsenhuber.net:51821` = CF-A-Record (proxied=false, TTL 120, aktuell `90.146.35.38`). **Kein Updater auf ap1** → nichts zu migrieren; `bf4` folgt der IP manuell (offener TP10-Follow-up). Zieht core am WAN eine neue IP (Lease sticky, eher nicht), via `CF_API_TOKEN` nachziehen: `bf4`-Record + Access-Policy `bf4-home-ip` (`90.146.35.38/32`). **Chance:** core ist nicht `device-mode=home` → scheduler/fetch gehen → `bf4`-DDNS-Auto-Updater dort bauen (schließt TP10-Follow-up).
|
||
- 📋 **Session-Handover** für die Cutover-Session: `docs/tp15-core-swap-session-handover.md` (Einstieg + Pre-Window-Checkliste + Kurz-Runbook; Original-Auftrag bleibt `docs/tp15-core-swap-session-handoff-prompt.md`).
|
||
- 📦 **2× CRS326-24G-2S+RM werden morgen (2026-07-17) geliefert, Produktivsetzung spätestens Montag 2026-07-20 (User-Entscheid 2026-07-16).** Sequenzierung ggü. Nautobot geklärt: **TP20+TP21 werden bis dahin fast-getrackt** (TP18/Komodo als Blocker entfernt, s. TP20) — Ziel ist, dass Nautobot **vor** der CRS326-Produktivsetzung steht und die Switches **direkt als Nautobot-verwaltete Geräte adoptiert** werden, statt erst von Hand konfiguriert und später importiert. sw1/sw2-VLAN99-Umzug (TP19.1) läuft parallel dazu on-demand, unabhängig davon.
|
||
- **🧭 Grundsatzentscheid (2026-07-14, korrigiert 2026-07-15): reines MikroTik-Ecosystem — Routing + Switching + WLAN.** **Omada bekommt KEINE Rolle** (weder Switching noch WLAN — der ursprüngliche „Omada=WLAN"-Satz war ein Fehlschluss beim Dokumentieren, User-Korrektur 2026-07-15: „WLAN war NIE von Omada die Rede"). Begründung Switching: Projektziel #1 **CAKE** nur RouterOS/OpenWrt/OPNsense (Omada-Gateway kann kein CAKE) → Switching = MikroTik CRS. WLAN bleibt auf hAP ax² (~~/CAPsMAN~~ — **CAPsMAN am 2026-08-08 abgeschafft**, Standalone aus der Golden Config; die Hardware-Aussage gilt), kein EAP-Kauf, Coverage-Fix bleibt Platzierungsfrage (TP3.3). Verworfene Vollvarianten (Omada-only, MikroTik-only) samt Begründung + Ansible/Nautobot-Recherche → Memory. **Anlass der Korrektur:** Omada-Controller↔sw2-Link beim VLAN20-Umzug (TP14.1) zerbrochen, versehentlicher Werks-Reset bei Rettungsversuch, fehlerhafter Wiederherstellungsversuch → sw2 wird standalone neu eingerichtet, s. **TP2.1**.
|
||
- **🛒 Switches: 2× CRS326-24G-2S+RM bestellt (2026-07-14 — CSS326-Fehlbestellung storniert → CRS).** 24×1G + 2×SFP+, lüfterlos, DC-input (USV-tauglich). Lösen ALLNET-Core (sw1) + Omada-ES208G (sw2, s. TP2.1 — Solo/Interim bis CRS-Tausch) + Cudy ab.
|
||
- ✅ **CRS = RouterOS-fähig → in-model:** MikroMCP-Write + Nautobot Golden Config (TP21) managen auch die **Switches**, nicht nur den Router → config-as-code deckt den **ganzen Kabel-Fabric**. (SwOS-Boot bliebe als Fallback möglich, aber nicht genutzt.)
|
||
- ⚠️ **kein PoE** (Sonoff/PoE-Verbraucher via Injektor, falls nötig).
|
||
- **📶 WLAN bleibt hAP ax²** — kein Hardware-/Ecosystem-Wechsel. ⚠️ **Überholt am 2026-07-22/2026-08-08: ~~/CAPsMAN~~** — CAPsMAN ist abgeschafft, beide APs laufen seit dem Rebuild als **Standalone-APs aus der Golden Config** (s. TP3). Die Hardware-Aussage gilt unverändert. Coverage-Schwachstellen (P750W-Fall, Terrasse/Kanten) bleiben Platzierungs-/Roaming-Thema von **TP3.3**, nicht durch neue Hardware gelöst.
|
||
- **🧭 Router-HW final (User-Entscheid 2026-07-22): kein RB5009.** Kein Zukauf einer dedizierten Router-HW.
|
||
- **🔄 KORREKTUR (User-Entscheid 2026-07-22, später am selben Tag): der CRS326-Core WIRD der neue L3-Router.** Die frühere Fassung dieser Zeile („Router bleibt dauerhaft ap1/ap2, L3/CAKE/Firewall bleiben auf ap1") ist damit **überholt**. **Routing, DNS und DHCP wandern vollständig von ap1 auf `crs326-core`**; ap1/ap2 werden zu **reinen Access Points**. Auch der CF-Mesh-Endpoint terminiert dort (s. TP16.1, war schon vorher auf CRS326 retargetet — passt jetzt konsistent zusammen). Damit entfallen die `device-mode=home`-Einschränkungen des hAP (kein scheduler/fetch) für die Router-Rolle. **Reihenfolge (User): erst Switches aufsetzen und in Betrieb nehmen, danach WLAN-Neuprovisionierung der APs.** Betroffen/nachzuziehen: TP4 (Router-Rolle), TP5/TP6 (Firewall + CAKE landen auf dem CRS326), TP21 (Scope-Grenze).
|
||
- **📍 CRS326 Live-Stand (2026-07-22, via MNDP von ap1):** **beide Geräte sind bereits am Netz und laufen** — RouterOS **7.19.5**, Werkszustand. `crs326-core` = MAC `04:F4:1C:B4:17:76` (software-id `4W04-URHT`), `crs326-branch` = MAC `04:F4:1C:B4:15:58` (`RGZJ-UK0T`). ⚠️ **Beide auf Werks-IP `192.168.88.1` im selben L2-Segment = IP-Konflikt** → beim Bring-up nur eines nach dem anderen adressieren, Unterscheidung ausschließlich per MAC. Die frühere Notiz „Uplink-Port bislang ungenutzt/down" ist überholt. **Standorte: `crs326-core` = „Technik UG" (virtueller Technikbereich im UG/Diele, KEIN Keller), `crs326-branch` = „Technik OG".**
|
||
- **🔌 PoE-Anschluss der APs (User-Vorgabe 2026-07-22):** Verkabelung/Portbelegung bleibt sonst **unverändert**; ap1/ap2 sollen künftig aber am **PoE-Port** hängen. PoE selbst ist noch kein Thema, die Config soll es aber schon vorsehen.
|
||
- ✅ **Port = `ether1`.** RouterOS nummeriert Interfaces ab **1** (`ether1`…`ether5`), nie `ether0` — die Unix-Konvention `eth0` gilt hier nicht. Auf dem hAP ax² ist `ether1` der PoE-Port (live bestätigt: `/interface/ethernet/poe` listet ausschließlich `ether1`).
|
||
- ⚠️ **Aber: passives PoE 18–28 V, NICHT 802.3af/at.** Ein normaler 802.3af/at-Switch oder -Injektor speist den hAP ax² **nicht**. Es braucht einen **passiven PoE-Injektor** (MikroTik-Standard). Dazu passend: **der CRS326 hat gar kein PoE** (bereits dokumentiert) → Strom kommt ohnehin aus einem Inline-Injektor zwischen Switchport und AP, nicht aus dem Switch.
|
||
- ⚠️ **Config-Konsequenz:** ap1s Trunk liegt heute auf **`ether2`** → wandert bei der Neuprovisionierung auf **`ether1`**. Und `ether1` steht aktuell auf **`poe-out=auto-on`** (der hAP kann über denselben Port auch Strom *abgeben*) — beim Umbau auf „ether1 = versorgter Uplink" muss `poe-out` auf diesem Port **`off`** gesetzt werden, sonst speisen Injektor und AP gegeneinander.
|
||
- **🔋 DC-USV → ausgelagert nach **TP24** (2026-08-16).** Inhalt unverändert gültig (MeanWell LRS-150-48 + DDR-120-48 + LiFePO4 20 Ah, ~€190, 48-V-Bus; die CRS326 haben passenden DC-Input) — steht ab jetzt dort, samt der offenen Entscheidungen (Mac mini/Inverter, Bus-Standort nach dem Core-Umzug, Batteriegröße, Shutdown-Signalisierung).
|
||
- ✅ **Standort-/Ablösungs-Mapping final (User 2026-07-22) — sauberes 1:1:**
|
||
| Bereich | heute | wird abgelöst durch |
|
||
|---|---|---|
|
||
| **Technik UG** (virtueller Bereich in der Diele, **kein Keller**) | sw1 (ALLNET, 16 Ports) | **crs326-core** (= neuer L3-Router) |
|
||
| **Technik OG** | sw2 (ES208G, 8 Ports) + ap2 + cudy2 | **crs326-branch** |
|
||
| **Wohnzimmer Sideboard** | ap1 | — (bleibt, wird reiner AP) |
|
||
Kapazität unkritisch: 16+8 belegte Ports heute gegen 2× 24 GbE + 2× SFP+ künftig. Vollständig in Nautobot gepflegt (alle 8 Devices haben einen Bereich).
|
||
- **📻 cudy-Hardware (User 2026-07-22):** beide sind **Cudy WR3600E V1.0**, Firmware `2.3.15-20250905-191956`. `cudy1` = Technik UG, am Core `#11`, aktiv als Übergangs-WLAN (`elektrosmog.c`, `10.40.10.246`) — **und Christophs aktueller WLAN-Pfad**. `cudy2` = Technik OG, außer Betrieb (Nautobot-Status `Decommissioning`), wird nicht reaktiviert.
|
||
- ⚠️ **Etappe 1 (Erstzugriff auf die CRS326) ist NICHT kritisch** (User 2026-07-22): Werkszustand, Gerät steht griffbereit neben ihm → der IP-Konflikt auf `192.168.88.1` wird physisch/seriell aufgelöst, kein Lockout-Szenario.
|
||
- ✅ **Portplan-Widerspruch AUFGELÖST (User 2026-07-22): am Core ist `#15 = ap1` und `#11 = cudy1`.** Damit gilt die TP4-Variante (`gi16` Arris/VLAN100 → `gi15` Trunk → ap1 `ether2`); **`switch/cli/03-trunk-ap-ports.cli` (gi1 = ap1 / gi2 = ap2) ist STALE** — die Datei bezeichnet sich selbst als „provisorisch, 2026-06-09" und wurde vom Edge-Cutover am 2026-07-01 überholt. Nicht mehr als Quelle verwenden.
|
||
- **Zielport nach dem Tausch: ap1 wandert auf `crs326-core` Port 4** (User-Vorgabe). Gleichzeitig wandert ap1s Uplink geräteseitig von `ether2` auf `ether1` (PoE-Port, s.o.).
|
||
- ⚠️ **Nach wie vor NICHT vom Gerät gelesen:** die restliche sw1-Belegung. `switch/state-backups/sw1-running-config-20260716-*.txt` sind 214-Byte-Fehlschläge (`Incorrect User Name!!`, toter `claudecode`-Login), `switch/cli/running-PRE.txt` ist Pre-TP1. `gi16` (Arris) und `gi8` (Trunk → sw2) stehen in Nautobot daher **explizit als „UNVERIFIZIERT"** markiert.
|
||
- 🔴 **Betriebliches Kernrisiko (Analyse 2026-07-22): der Core-Tausch ist KEIN Switch-Tausch, sondern ein Vollausfall.** `crs326-core` ersetzt sw1 **und** wird gleichzeitig L3-Router — und an sw1 hängt auf `#15` ap1, also Gateway, DHCP, DNS und der WAN-Trunk fürs gesamte Netz. Core-Tausch und L3-Umzug sind damit **faktisch dasselbe Ereignis** und brauchen ein geplantes Ausfallfenster. **→ Reihenfolge-Entscheid (User 2026-07-22): `crs326-branch` zuerst (gegen sw2, Technik OG), `crs326-core` in einer eigenen, späteren Session.**
|
||
- 🛟 **Rettungspfade liegen günstig auf verschiedenen Switches:** Christophs Notebook hängt per **WLAN über cudy1 → Core `#11`**; der kabelgebundene Plan B (Dock/Monitor Arbeitszimmer) hängt am **sw2/Branch (P4)**. Beim **Branch**-Tausch stirbt also der Kabelweg, das WLAN überlebt. (Beim Core-Tausch stirbt beides — s. Kernrisiko oben.)
|
||
- **Hinweis:** die A/B/C/D-Switch-Varianten in `hw-refresh-requirements.md` sind durch die CRS326-Beschaffung überholt (Doc = Recherche-Archiv + USV/Energie-Referenz).
|
||
- Abh.: TP14 ✅ (IP-Migration). Verzahnt: **TP20** (Platform-DB), **TP21** (Nautobot GC), **TP2.1** (sw2-Standalone-Recovery).
|
||
|
||
### TP16 — CF-Tunnel: Round-Robin killen + reziprokes HA ▸ ✅ KERN UMGESETZT (2026-07-10) — ⚠️ **HA aktuell degradiert (Live-Befund 2026-08-16)** — `docs/cf-tunnel-mapping.md §10`, #1033
|
||
- 🟠 **BEFUND 2026-08-16 (beim Doku-Aufräumen live über die CF-API erhoben, kein Eingriff): das reziproke HA läuft nur noch auf einem von drei Tunneln.**
|
||
- `bf-mm` = **2 Connectoren** (je 4 conns) ✅ · `bf-nas` = **1 Connector** (3 conns) 🟠 · `bf-pve` = **1 Connector** (4 conns) 🟠.
|
||
- **Bedeutung:** die Dienste hinter `bf-nas` (gitea, grafana, pve-mcp, **vw**, ds-bf, nautobot) und `bf-pve` (pve, ccu, iobroker, z2m25, portainer, **hass**, ha-mcp) hängen jeweils an **einem einzigen** cloudflared-Prozess. Fällt dessen Host aus, sind sie weg — genau der Zustand, den TP16 beseitigt hat. **Kein `530`/Round-Robin-Problem** (das bleibt strukturell gelöst), sondern **Redundanzverlust**.
|
||
- **Bekanntes Muster:** identisch zum Incident vom 2026-07-16 (macmini-Connectoren flappten unter QUIC → Fix `TUNNEL_TRANSPORT_PROTOCOL=http2`). Diesmal sind die *macmini*-Connectoren oben (bf-mm hat 2), es fehlt je **ein** Gegenstück auf NAS/pve. **Nächster Schritt (eigene Session):** auf NAS und pve nachsehen, welcher der beiden cloudflared-Container nicht läuft, und ob es der `http2`-Konventionsfall ist.
|
||
- 🧹 **Nebenbefund beim selben Sweep — Alt-Tunnel mit VLAN1-Origins (alle `down`, 0 Connectoren, daher aktuell harmlos):** `openclaw` (→ `10.40.41.147/.148/.139`), `coolify` (→ `10.40.41.133`), `johnny2`, `TeilzeitCharlie`. ⚠️ **`openclaw` beansprucht `n8n.emsenhuber.net`, das produktiv auf `bf-mm` läuft** — käme der Tunnel je wieder hoch, entstünde exakt das alte Round-Robin-Muster auf diesem Hostname. **Empfehlung: die vier toten Tunnel löschen** (user-gated, Löschen ist nicht umkehrbar) — gehört fachlich zu **TP19** (VLAN1-Retirement: `.41.133` war eines der „unidentifizierten VLAN1-Geräte" aus TP19 B1.2 — hiermit als coolify-Origin identifiziert).
|
||
> **✅ Umgesetzt (2026-07-10, eigene Session):** reziprokes **3-Tunnel-HA** live (bf-nas `70d6a4cf` / bf-pve `f7fdf3a6` / bf-mm `7a322261`), 6 Connectoren (2/Host, je Fremdhost), 19 FQDNs Loop-Smoke **0×530**, HA per Host-Ausfall-Sim bewiesen. Round-Robin-#1033 **strukturell weg**. As-Built = `docs/cf-tunnel-mapping.md §10`. **Schritt 5 Access-Strang: ~~`vw` bypass→geschützt via WARP~~ — 🔴 GESTRICHEN (User-Constraint 2026-08-14, s. TP16.2). Verbleibend offen: `hass`/`ha-mcp` 400/403; `gateway-dw` (WG→404) klären.**
|
||
- **Symptom (User):** FQDNs über CF werden **sporadisch / „sehr unsicher"** aufgelöst = #1033-Muster zurück („jeden 3. Schuss eine Niete"). User hat alle 3 cloudflared-Images + Container aktualisiert/neu gestartet.
|
||
- **✅ Root-Cause endgültig (User-Diagnose bestätigt): macvlan/ipvlan-Host-Isolation.** Ein cloudflared-Connector ist **blind für macvlan/ipvlan-Container auf seinem EIGENEN Host** (Linux-Kernel-Regel), erreicht aber Fremdhost-L2 + co-lokierte Bridge-Container. Mehrere Connectoren auf EINEM Tunnel = geteilter Ingress + CF-**Round-Robin** → jede Origin, die auf dem Host *eines* Connectors liegt, fällt bei ~**1/N** aus. **Strukturell**, nicht durch „Origins fixen" heilbar. Bsp: `omada .20.175`/`pve-mcp .20.173`/`gitea .20.157`/`grafana .20.109` = NAS-macvlan → vom NAS-Connector NICHT erreichbar.
|
||
- **Invariante:** innerhalb EINES Tunnels ist **kein Route→Connector-Pinning** möglich (alle Connectoren teilen Ingress, CF round-robined). „Ausgewählte Routen für ausgewählte Connectoren" = **getrennte Tunnel**.
|
||
- **Ziel-Design (HA): reziproke Per-Host-Tunnel** — jeder Host-Dienst wird von den Connectoren der ANDEREN Hosts bedient (nie vom eigenen):
|
||
|
||
| Tunnel (= Dienste eines Hosts) | Connectoren auf | HA |
|
||
|---|---|---|
|
||
| pve-Dienste | NAS + macmini | 1 abdrehbar |
|
||
| NAS-Dienste (omada/pve-mcp/gitea/grafana/…) | pve + macmini | 1 abdrehbar |
|
||
| macmini-Dienste (`.20.167`) | pve + NAS | 1 abdrehbar |
|
||
|
||
3 Tunnel, jeder Host fährt 2 cloudflared → Host-Ausfall ⇒ jeder Tunnel ≥1 Connector = **voll HA**. Voraussetzung: jede Origin L2-erreichbar.
|
||
- **Ist-Inventory (live 2026-07-10, s. `cf-tunnel-mapping.md §9`):** Ingress v119, 24 Hostnames, 2 live Connectoren. **DOWN/stale:** `pbs .20.135`, `nginx-bf .41.123` (noch VLAN1!), `hermes`+`hermes-geli .20.167`. **Zu klären (Host/Netz):** `vw .20.127`/`ccu .20.232`/`iobroker .20.107`/`z2m25 .20.106` — ggf. `vw`/`ccu` auf VLAN20-macvlan heben. `gateway-dw` (192.168.178.1) = WG-Sonderfall.
|
||
- **CF-Access-Strang (verzahnt, s. TP11 Track-B):** `hass`-**400 in der HA-iPhone-App = CF-Access davor** (Companion-App kann Access-Login nicht) → Fix **ohne Passthrough**: iPhone in **WARP** enrollen (Device-Identity erfüllt Access; „Warp Login App" existiert bereits `allow:christoph`). ~~⚠️ **`vw` = aktuell `bypass` (öffentlich!)** → von bypass auf geschützt heben.~~ 🔴 **Überholt (2026-08-14): `vw` BLEIBT bypass — harter User-Constraint, Härtung stattdessen über TP16.2.** „Passthrough-Hosts sind die kritischen" (User).
|
||
- **Umsetzungs-Reihenfolge (für die eigene Session):** (1) **Reachability-Matrix je Host** (pve/NAS/macmini → jede Origin, read-only) BEVOR gruppiert wird; (2) **Interim-Sofortfix:** bf-Tunnel auf **pve-only** (pve erreicht alles außer gateway-dw) → 0×1033, reversibel; (3) reziprokes 3-Tunnel-HA bauen (CNAMEs re-pointen, 6 Connectoren, Token je Tunnel; NAS/macmini-Alt-Token entfernen); (4) tote Origins bereinigen; (5) Access-Strang (WARP + vw); (6) Loop-Gegentest.
|
||
- Abh.: TP14.1/14.2 ✅. Verwandt: **TP11** (CF-Tunnel-Track-B/C + Access), #1033. SSoT: `docs/cf-tunnel-mapping.md`. Memory `project_cf_tunnel_1033`.
|
||
- ✅ **Incident 2026-07-16 (User unterwegs, WARP „spinnt", keine BF-IPs mehr) ▸ Public-FQDN-Teil gefixt:** macmini-Connectoren (`cloudflared-bfnas`/`-bfpve`) flappten live unter QUIC/UDP (Docker-Desktop-Bridge-NAT) → `bf-nas`/`bf-pve` von 2 auf 1 Connector degradiert (HA faktisch weg, nicht down). Fix: beide auf `TUNNEL_TRANSPORT_PROTOCOL=http2` umgestellt (rollend, 0 Downtime), wieder voll HA. Konvention: macmini-Connectoren künftig immer `http2`. **ICMP-Befund (getrennt, strukturell):** TCP über die WARP-Route ging überall, ICMP nicht (fm 36 %/bf 100 %/dw 100 % Loss) — cloudflared ist QUIC-Proxy, kein WireGuard. **Kurz als „bf-pve-Route wegen USV" notiert (Commit `1c1a676`) → REVIDIERT** (Begründung invertiert: bf-pve-Connectoren laufen auf NAS+macmini, nicht pve). Details: `docs/cf-tunnel-mapping.md §13`. **→ Richtungswechsel für Private Access = TP16.1.**
|
||
|
||
### TP16.1 — Private Access via native Cloudflare Mesh (WireGuard) auf `crs326-core` ▸ ✅ **ABGESCHLOSSEN (2026-08-17)** — `docs/tp16.1-warp-mesh-native-crs326.md`
|
||
- ✅ **Kernergebnis: ICMP ist repariert.** Privater Zugang unterwegs läuft über **natives WireGuard auf `crs326-core`** statt cloudflared-QUIC — **0 % Ping-Loss auf alle BF-VLANs, vorher 100 %**. Genau das Symptom aus dem Incident 2026-07-16, das dieses TP ausgelöst hat. Öffentliche FQDNs unberührt auf dem 3-Tunnel-HA (TP16). Compliance **68/68**.
|
||
- ✅ **§4.0 erledigt 2026-08-17: Mesh-Node angelegt.** `bf-core-mesh` = **`d1da7c8a-2736-4cbb-8af1-32db5393fb9c`**, Register-Token in `mcp/cloudflare/.env` (`CF_MESH_REGISTER_TOKEN`, gitignored). ➡️ **Die seit 2026-07-17 offene Free-Plan-Frage ist beantwortet: der Free-ZT-Plan erlaubt Cloudflare Mesh — der LXC-Fallback ist vom Tisch.**
|
||
- 🔑 **Der Weg dahin war ein Token-Problem, kein Plan-Problem (kostete 2 Anläufe).** Der alte User-Token hatte **zwei** fehlende Permissions (§4.0 *und* §4.1 — `devices/settings` war schon lesend `403`). Ersetzt durch einen **account-owned** Token (`9984078812bc…`, ⏰ **gültig bis 2027-01-09**). Zwei Fallen, beide sehen aus wie „Token kaputt": (1) Account-Tokens verifizieren an `/accounts/{id}/tokens/verify` — am alten `/user/tokens/verify` melden sie `1000 "Invalid API Token"`, **während alle echten Endpoints 200 liefern**; (2) Dashboard-Fehler `"Account tag in access policy must match tag in request uri"` = eine **Zone**-Permission (`DNS`) steckt in der Policy-Zeile mit **Account**-Ressourcen → braucht eine eigene Zeile. Verifiziertes Soll-Set + Permission-IDs in `docs/tp16.1-…md` §4.0. **Merke: Dashboard sagt „Edit", API sagt „Write".**
|
||
- ✅ **§4.1–§4.4 durchgezogen 2026-08-17 (User-Freigabe „jetzt durchziehen").** Prereqs: `use_zt_virtual_ip=true`, Device-Profil „Cloudflare Mesh" (`4d3c0f57…`), Split-Tunnel auf **beiden** Profilen korrigiert (`100.64.0.0/10` → `/11` + `100.112.0.0/12`). Gerät: `cf-mesh` auf `crs326-core`, Mesh-IP **`100.96.0.6/32`**, Peer `162.159.193.2:2408`, **Handshake steht**, Route `100.96.0.0/12 → cf-mesh` aktiv; Backup `pre-tp16.1-mesh-20260817.backup` vorher (Auflage #4 ✅). CF meldet Node **healthy**. **§4.4: Weg A hat funktioniert — der befürchtete vnet-Gotcha trat NICHT ein**, `10.40.0.0/16` zeigt jetzt auf `bf-core-mesh` statt `bf-pve` (Rollback = 1 PATCH zurück, `bf-pve` unangetastet).
|
||
- ⚠️ **Zwei Werkzeug-Fallen, real getroffen (gehören in jede künftige WG-Arbeit):** (1) **MikroMCPs `manage_wireguard_interface` kann grundsätzlich keinen privaten Schlüssel annehmen** — RouterOS erzeugt ihn selbst; bei CF Mesh kommt er aber von CF → Key per SSH mit Interpolation aus der gitignoreten `.env` setzen, nicht über das Tool. (2) **`manage_wireguard_peer` schreibt `endpoint: "IP:Port"` komplett in `endpoint-address` und lässt `endpoint-port=0`** → **kein Handshake**, sieht aus wie ein Firewall-Problem, ist ein Parameter-Bug. Nach jedem Peer-Add `print detail` gegenlesen. Auch `persistent-keepalive` fehlt dem Tool.
|
||
- ✅ **§4.5 ABNAHME BESTANDEN 2026-08-17** (MacBook am Hotspot, WARP connected): **Ping 0 % Loss** auf `10.40.10.1` / `10.40.20.105` / `10.40.99.12` / `10.40.20.10` / `10.40.99.1` (47–63 ms) — **vorher 100 %**. TCP mit echtem Datenfluss (pve 8006 → 200, Nautobot → 302, `ssh macmini` → ok). FQDN-Smoke gitea/hass/pve/nautobot/vw → 200/200/302/302/200 ⇒ **cloudflared-Public-Teil unberührt.**
|
||
- ✅ **Auflage Ausnahme #4 erfüllt:** Ist-Stand als intended config zurück nach Nautobot → zuerst **65/68** (drei `extra`-Drifts = die Mesh-Zeilen), Zeilen **byte-genau aus dem Backup** ins Jinja-Template, Push nach `bf-golden-config`, Repo-Sync → **68/68, keine Drifts**. Privkey bleibt draußen (`<<REDACTED>>`-Maske wie bei `wg-hub`). ⚠️ **Push-Gotcha:** Nautobot schreibt Backups+intended in **dasselbe** Repo → `git pull --rebase` vor jedem Push, sonst `rejected (fetch first)`.
|
||
- ✅ **Mgmt-ACL via GC ausgerollt 2026-08-17 (Nachlauf, alle 4 Geräte) — `72/72 compliant`.** Neue Compliance-Feature **`ip-service`** (`match_config=/ip service`, `config_ordered=false`) → 17→18 Regeln, 68→**72 Checks**. Sollzustand einheitlich im Template: `ssh`/`www`/`winbox`/`api` = `address=10.40.0.0/16,100.96.0.0/12`, `ftp`/`telnet`/`api-ssl` = `disabled=yes`. Ablauf regelkonform: Backups auf allen Zielen → `--job mgmt-acl --apply --no-deploy` → **gestaffelter** Deploy (ap2 zuerst, am Gerät gegengeprüft, dann ap1/branch/core) → Geräte-Gegenprobe → Compliance.
|
||
- 🔎 **Der Befund war das Gegenteil der Erwartung:** ich hatte „branch/ap1/ap2 sperren den Mesh aus" befürchtet — tatsächlich hatten sie **gar keine** Address-Beschränkung (ssh/www/winbox/api/ftp/telnet **komplett offen**), und die dynamischen Einträge zeigten `REMOTE 100.96.0.1`, waren also längst per Mesh erreichbar. **`winbox` war auf ALLEN vier unbeschränkt**, auch am Core. Aus dem Erreichbarkeits-Fix wurde damit eine Härtung.
|
||
- ⚠️ **Scope-Erweiterung, bewusst und meldepflichtig:** `ftp`/`telnet`/`api-ssl` wurden auf branch/ap1/ap2 **abgeschaltet** (Klartext bzw. ungenutzt; der Core hatte das bereits). Begründung: die Alternative wäre gewesen, „telnet aktiv" als Sollzustand in die SoT zu schreiben. Nichts hier nutzt telnet/ftp — der ALLNET-Telnet-Runner ist Archiv, das Gerät ausgebaut.
|
||
- 📌 **Schreibweise (Falle):** `/ip service set ssh …` mit dem **Dienstnamen**, NICHT `[find name=ssh]` — letzteres trifft auch den dynamischen Verbindungs-Eintrag und quittiert mit `failure: this is configured elsewhere`.
|
||
- 🔴🔴 **DIE FALLE DIESES TPs — `/ip service` sperrte das Router-Mgmt aus dem Mesh aus** (Core, vor dem Rollout oben): Direkt nach dem WARP-Connect war `crs326-core` mgmt-tot: MikroMCP `Connection lost before handshake`, SSH `kex_exchange_identification: Connection reset`, REST **502** — **bei gleichzeitig verlustfreiem Ping auf dieselbe IP**, und alle Hosts *hinter* dem Core normal. Ursache: `/ip service ssh,www address=10.40.0.0/16`, der Mesh-Client kommt aus `100.96.0.0/12`. ICMP kennt keine Service-ACL. **Und `nc -z` meldet „offen", weil der CF-Gateway-Proxy den TCP-Handshake terminiert — ein TCP-Connect ist über WARP KEIN Reachability-Beweis.** Fix: `address=10.40.0.0/16,100.96.0.0/12`. **Merkregel: wer per Mesh ans Netz kommt, ist noch lange nicht am Router.** ⚠️ **Für `crs326-branch`/`ap1`/`ap2` noch OFFEN** — deren eigene `/ip service`-ACLs sind ungeprüft. Entscheidender Diagnose-Schritt war der **Banner-Grab vom macmini** (`nc 10.40.99.1 22` → `SSH-2.0-ROSSSH`): von innen gesund ⇒ Pfad/ACL, nicht Gerät. Fehlspuren, die man sich sparen kann: MTU (die großen Pings scheitern am **WARP-Client**-`utun` MTU 1380, nicht an `cf-mesh`) und SSH-Session-Erschöpfung.
|
||
- ✅ **Schalter „Allow all Cloudflare One traffic to reach enrolled devices" — recherchiert 2026-08-17, ENTSCHIEDEN: bleibt AUS.** Laut CF-Settings-Referenz ist es ein **globales** Device-Client-Setting („Global device client settings"), alle Pläne, alle OS, Client-Mode „Traffic and DNS". **Funktion: es lässt Traffic aus Mesh/WAN *zu den eingebuchten Geräten hin* — also Zugriff auf Device-IPs.** Das ist die **Client↔Client**-Richtung und für unseren Fall (Gerät → Mesh-Node → `10.40.0.0/16`) nicht nötig; der Mesh läuft bewiesenermaßen ohne. **Kein API-Feld** (in Spec, `devices/settings`-PATCH *und* Profil-GET gegengeprüft), und die CF-Docs nennen **keinen** Menüpfad. ⚠️ **Die Docs widersprechen sich:** die Mesh-Get-Started-Seite nennt es eine *Profil*-Einstellung, die Settings-Referenz eine *globale*. Nach User-Vorgabe („im Zweifel ohne Schalter") **nicht gesetzt** — nichts gebaut, nichts geklickt. Erst relevant, wenn ein Zugriff **auf ein Endgerät** (statt auf das Netz) gebraucht wird.
|
||
- 📌 **Bleibt gültig:** die HA-Degradierung der öffentlichen Tunnel (TP16, `bf-pve` fährt nur einen Connector) wird davon **nicht** geheilt — eigener offener Punkt. Und für **TP5** vormerken: bei deny-by-default braucht der Mesh explizit `forward accept 100.96.0.0/12 ↔ 10.40.0.0/16`.
|
||
- ✅ **Gate erfüllt (2026-08-16):** die Bedingung „gated bis TP21 den CRS326 abdeckt" ist eingelöst — `crs326-core` ist seit 2026-08-08 der produktive L3-Router und seit 2026-08-13 in Nautobot adoptiert (68/68 compliant). Runbook §3 neu gemessen, §4.3 von Platzhalter auf **echte Werte** gezogen.
|
||
- 🧭 **Erwartung geraderücken (wichtig, weil leicht zu verwechseln): das Mesh ersetzt die CF-Tunnel NICHT.** TP16.1 löst ausschließlich den **privaten** Zugang (unterwegs → `10.40.0.0/16` per IP, **inklusive ICMP**) und tauscht dort den cloudflared-QUIC-Proxy gegen natives WireGuard auf dem Core. Die **öffentlichen FQDNs bleiben** auf dem 3-Tunnel-HA aus TP16. Beide Stränge laufen nebeneinander — die HA-Degradierung aus TP16 (2026-08-16) wird davon **nicht** geheilt und bleibt ein eigener offener Punkt.
|
||
- 📌 **Live-Befunde 2026-08-16 (read-only erhoben, kein Eingriff):**
|
||
- `warp_connector` = `[]`, aber der **GET antwortet** (kein 403) → die Free-Plan-Frage entscheidet sich erst am `POST` (§4.0). `CF_API_TOKEN` ist `active`; ob er die separate Permission **„Cloudflare One Connector: WARP"** trägt, zeigt genau dieser POST — dort schlug es am 2026-07-17 mit `10000` fehl.
|
||
- `use_zt_virtual_ip: false` → Unique-Device-IP muss weiterhin eingeschaltet werden. Gateway-Proxy TCP+UDP sind an.
|
||
- **Nur EIN Device-Profil** (Default). Der „auf beiden Profilen"-Hinweis im Runbook meint also: Default jetzt, Mesh-Profil sobald es existiert — es gibt kein zweites, auf dem man etwas übersehen könnte.
|
||
- Split-Tunnel-Exclude enthält unverändert `100.64.0.0/10` (verschluckt die Mesh-Overlay-Range) → der §4.1.4-Schritt bleibt nötig.
|
||
- Die vnet-Route `10.40.0.0/16` (`5546dcb6…`) zeigt weiter auf `bf-pve` — der Fallback steht. ⚠️ **Aber `bf-pve` fährt derzeit nur einen Connector**, der private Pfad hängt also an einem einzelnen cloudflared-Prozess.
|
||
- ✅ **Die letzte inhaltliche Unbekannte ist weg:** „Rückweg-Routing TBD" hat sich erledigt, weil der Core L3-Gateway **aller** VLANs ist — es braucht keine Zusatzroute. Und `wg-hub` (TP10) liegt auf **demselben** Gerät, ist also direktes Vorbild statt fernes Muster.
|
||
- ✅ **GOVERNANCE-AUSNAHME #4 (User, 2026-08-16): die WG-Zeilen für den Mesh-Bring-up auf `crs326-core` dürfen DIREKT gesetzt werden** (MikroMCP `plan_changes` dryRun → `apply_plan`). **Begründung — es ist kein Bequemlichkeits-, sondern ein struktureller Grund:** TP22-Regel 1 schließt jede Sektion, die `<<REDACTED>>` enthält, generell vom GC-Push aus, und `/interface wireguard` ist genau so eine Sektion. Ein privater Schlüssel ist über Golden Config also **gar nicht deploybar** — die frühere Zeile „CRS326-Zeilen laufen regulär über Nautobot GC" trägt nicht mehr. **Auflage (wie Ausnahme #2):** Ist-Stand danach als intended config zurück nach Nautobot; vorher `/system backup` (Regel 3). **Scope-Grenze:** nur der Mesh-Bring-up auf `crs326-core` — nicht spätere WG-Änderungen, nicht andere Geräte.
|
||
- 🔑 **Damit die Ausnahme ein einmaliger Bootstrap bleibt — Secret-Handling-Design (Runbook §4.3):** ein privater Schlüssel ist **Geräte-Identität**, keine Konfiguration (wie ein SSH-Hostkey). Regel: *der private Teil entsteht am Gerät und verlässt es nie; nur der öffentliche geht in die SoT und wird in die **Peer**-Configs gerendert.* RouterOS kann das nativ (`/interface wireguard add` erzeugt den Privkey selbst). Compliance bleibt grün, weil die `ConfigReplace`-Maske aus TP22 Schritt 0 byte-identisch zu der im Template ist. ⚠️ Vorbehalt: bei CF Mesh erzeugt **CF** das Schlüsselpaar — dann fällt die On-Device-Erzeugung weg, das Prinzip („nie in Git, nie in der intended config") hält trotzdem. **Stufe 2** (`nautobot-secrets-providers` + Vault, Wert erst bei der Plan-Erzeugung einsetzen) lohnt bei 4 Geräten und einem Key nicht — eigener TP nach TP18/TP20.1.
|
||
- 🧹 **Sofort fälliger Modellierungs-Nachzug, unabhängig vom Mesh:** die WG-Peers `fm`/`dw` stehen mit hartkodierten `public-key="…"` im Jinja-Template. **Public Keys sind Daten, keine Templatezeilen** — gehören nach Nautobot und von dort gerendert.
|
||
- ⚠️ **Für TP5 vormerken:** sobald deny-by-default greift, braucht der Mesh-Verkehr explizit `forward accept 100.96.0.0/12 ↔ 10.40.0.0/16` — heute passiert er nur, weil die `forward`-Kette ohne Drop endet.
|
||
- ⏭️ **Was die Scharfschalt-Session macht:** `POST warp_connector` (Plan-Gate) → account-weite Prereqs (Unique Device IP, Split-Tunnel auf beiden Profilen) → `wgcf-connector`-Token → 4 WG-Zeilen auf dem Core → Route `5546dcb6…` umhängen (vnet-Gotcha, Weg A/B) → Ping-Abnahme. **Trifft alle Live-WARP-Geräte mit einem kurzen Reconnect** → Zeitpunkt user-gated.
|
||
- ✅ **Update (User-Entscheid 2026-07-22):** Ziel-Device für den WG-Mesh-Node ist jetzt der **CRS326 Core-Switch statt ap1** — konsistent mit dem TP15-Endstand (kein RB5009) — ⚠️ **die damalige Klammer „Router bleibt ap1/ap2 rein für L3/WLAN" ist seit dem Core-Cutover 2026-08-08 überholt: L3 liegt auf `crs326-core`, ap1/ap2 sind reine APs.** Der Retarget auf den Core war damit im Ergebnis richtig, nur anders begründet als hier notiert und TP21s "ganzer Kabel-Fabric via RouterOS"-Modell (CRS326 ist ohnehin RouterOS-fähig und wird Nautobot-verwaltet). **Reine Ziel-Doku-Änderung** — das Scharfschalten bleibt weiterhin eine eigene, spätere Session und bleibt gated, bis TP21 den CRS326 als Device abdeckt. **Keine neue Governance-Ausnahme:** die bestehende ap1-Ausnahme (s. Ist-Stand-Zeile 31) gilt explizit **nicht** automatisch für den CRS326 — CRS326-Konfiguration soll regulär über Nautobot GC laufen, sobald TP21 so weit ist. Die CRS326 selbst sind aktuell noch Werkszustand (physisch bereits mit dem aktuellen Core verkabelt, aber die betreffende Uplink-Port bislang ungenutzt/down) — konkrete Management-IP/Interface-Zuordnung für den CRS326 als L3/WG-Endpoint ist noch **nicht** getroffen (TBD nach TP15-Bring-up).
|
||
- **Trennung:** Public FQDNs bleiben auf cloudflared-3-Tunnel-HA (TP16); **Private Access** (unterwegs → `10.40.0.0/16` per IP inkl. ICMP) wandert vom cloudflared-QUIC-Proxy auf einen **nativen WireGuard-Mesh-Node auf dem CRS326 Core-Switch**.
|
||
- **Warum CRS326-nativ:** Cloudflare Mesh spricht WireGuard, RouterOS kann natives WireGuard (TP10-Hub auf ap1 *ist* einer, Muster überträgt sich) → Mesh-Node = WG-Peer zu CF-PoP, **kein Container/TUN/LXC/neue HW**. Verlagert die Rolle vom Router (ap1, der weiterhin Public-Edge + WLAN-Anker bleibt) auf den Core-Switch, der als zentraler Kabel-Fabric-Knoten ohnehin alle VLANs sieht. RouterOS-Container-Weg bleibt tot (kein `/dev/net/tun`-Passthrough auf JEDER Router/Switch-HW) — daher weiterhin natives WireGuard, kein Container-Ansatz.
|
||
- **Verworfen:** WG-Roadwarrior (User will keine Extra-App/Profil je Gerät), alle Helper-Host-ZT-Anbieter (SPOF-Verletzung).
|
||
- **Warum heute nur Konzept:** TCP-Pfad funktioniert (nur ICMP-Komfort fehlt), und die CF-Prerequisites sind **account-weit** (Unique-Device-IP, Split-Tunnel-Exclude, Device-Profile) → treffen Live-WARP-Geräte (1× kurzer Reconnect) → nicht unter Zeitdruck. Zusätzlich jetzt gated durch den Retarget: CRS326-Bring-up (Management-IP, VLAN-Filtering) muss erst stehen.
|
||
- **Nächste Session (nach CRS326-Bring-up):** Plan-Probe `POST warp_connector` (Free-Plan-Gate; sonst LXC-Fallback) → account-weite Prereqs → `wgcf-connector`-Token→WG-Config → 4 WG-Zeilen auf dem CRS326 → Subnetz-Route + vnet-Route `5546dcb6…` von bf-pve umhängen (Rollback trivial) → Verifikation (Ping verlustfrei). Team-Domain `emsenhuber.cloudflareaccess.com`. Governance „Config nur via Nautobot" → CRS326-Zeilen regulär via TP21/GC, sobald das Device dort adoptiert ist.
|
||
- ✅ **Recherche-Härtung 2026-07-17 (Primärquellen animmouse + offizielle CF-Docs + OpenAPI-Spec, alles verifiziert, gilt unabhängig vom Zielgerät):** (1) Produkt heißt seit 2026-04-14 offiziell **Cloudflare Mesh** (API-Pfade bleiben `warp_connector`, im Spec bestätigt inkl. Token- und sogar HA-Endpoints); (2) ICMP-Proxy ist **bereits AN** (User-Korrektur: fm-Ping `10.101.0.0/24` beweist es — kein To-Do; mein „fehlt" war ein Fehlschluss aus dem API-Spec, das Flag ist Dashboard-only); (3) Split-Tunnel-Exclude auf **beiden** Device-Profilen (Default + Mesh); (4) **vnet-Gotcha** beim Route-Umzug („virtual networks only for cloudflared") → Weg A PATCH, Weg B DELETE+POST dokumentiert; (5) **v4-only-Entscheid** (Mesh-IPv6-site-to-site laut Guide broken, NAT66-Gefrickel nicht nötig); (6) keepalive 1m statt 25s ok. Alles in `docs/tp16.1-warp-mesh-native-crs326.md` §2/§4 eingearbeitet (Config-Block dort als Platzhalter markiert, IP/Interface TBD).
|
||
- Abh.: TP16 ✅ (Public-Teil), TP10 ✅ (WG-Grundmuster, jetzt als Vorbild statt Direktziel), **TP15** (CRS326-Bring-up), **TP21** (Nautobot-Adoption des CRS326, Voraussetzung fürs Scharfschalten). SSoT: `docs/tp16.1-warp-mesh-native-crs326.md`, `docs/cf-tunnel-mapping.md §14`.
|
||
|
||
### 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).
|
||
|
||
### TP17 — Shelly-Übersiedelung VLAN1 → VLAN30 (IOT) + `shelly-mcp` ▸ ✅ **KOMPLETT (User-Bestätigt 2026-08-13): alle Shellys auf VLAN30** — Geräte-PW (TP17.2) weiterhin bewusst zurückgestellt — `mcp/shelly/`, Runbook `docs/tp17-shelly-go-runbook.md`
|
||
- ✅ **Abschluss 2026-08-13 (User-Bestätigt):** auch die zuletzt offenen saisonalen Shellys (s1/s2/s3/s12) sind inzwischen umgeklemmt — **alle Shellys auf `dirtyvader-iot`/VLAN30**, kein VLAN1-Shelly-Rest mehr. Migration-Teil von TP17 damit vollständig abgeschlossen.
|
||
- ✅ **GO durchgezogen 2026-07-13 (16 Shellys VLAN1→VLAN30, 0 Fehler):** Pilot s26 + Welle A (s4–s9) + Welle B (s10/11/13/15/17/19/20/21/25) → alle auf `dirtyvader-iot`/`10.40.30.<octet>` verifiziert (SSID+IP+rssi). Mit den 6 Vorab-Migrierten (s14/16/18/22/23/24) = **22/26 auf VLAN30**; VLAN1-Sweep `.180-250` = **0 Shellys**. Restliche 4 saisonal ausgesteckte (s1/s2/s3/s12) inzwischen ebenfalls migriert (s.o.).
|
||
- 🔧 **Anker-Verfahren (User-Idee, statt sta1-Backup):** je Gerät **vor** dem sta-Write die geräteeigene **AP-Funktion** aktiviert (`WiFi.SetConfig ap.enable` — Firmware verlangt WPA2, kein offenes AP → PSK=IOT-PSK, live/kein Reboot) = Notanker, falls VLAN30-Join scheitert (Gerät bleibt über `Shelly*-<mac>`-AP erreichbar, **kein physischer Reset**). Nach Verify alle 22 AP-Anker wieder `deanchor`t. Runner: `mcp/shelly/migrate.py` (`migrate`/`deanchor`/`auth`/`table`, Dry-Run default, stoppt bei erstem Fehler, reused `discover.py`).
|
||
- ✅ **HA-Cross-Check nach Batch:** einzige `unavailable` Shelly-Entities = **s12** (saisonal aus) — alle 22 migrierten reconnecten via mDNS/zeroconf (TP7-Repeater vlan30↔vlan20-HA) auf neuer `.30.x`-IP, **Entity-IDs unverändert** (keyt per MAC). Inventar `inventory/bf.csv` .41→.30 nachgezogen (22 Zeilen, Section→IOT).
|
||
- ⚠️ **Coverage-Flag:** `s4 kueche_mikrowelle` verbindet mit **rssi −93** (Metallgehäuse), hat aber verifiziert — grenzwertig, im Auge behalten. s7 Tiefkühl −85. Rest gut (−26…−81).
|
||
- ✅ **Eco-Mode-Policy (2026-07-13, PROVISORISCH):** eco senkt CPU-Takt + WiFi-TX-Leistung → **eco AN für RSSI ≥ −80** (Energie-Win, TX irrelevant), **eco AUS für < −80** (Uplink-Headroom): s4/−91, s7/−88, s17/−81, s18/−79…−82, s19/−86 → 17× ON / 5× OFF, live via `Sys.SetConfig device.eco_mode` (kein Reboot). s4 (Küchen-Sockel/Metall, −91, fix) bewusst eco-OFF = schwächster Link. ⏳ **2. Eval nötig nach TP3.3** (WLAN-Ausrichtung/Aufbau ändert RSSI → Grenzfälle neu bewerten; User 2026-07-13).
|
||
- ✅ **HA-Referenz http vs https geklärt (2026-07-13):** HA speichert `configuration_url` für **alle 22 Shellys bereits `http://10.40.30.x:80`** (Integration korrekt + neue IPs übernommen). Das „https" ist **client-seitig** (Mixed-Content-Upgrade, wenn HA selbst über https/Tunnel geöffnet) — **kein HA-Fix möglich/nötig, Shelly-SSL bewusst NICHT** (CPU/Energie, IoT-Netz). ⚠️ Rand-Fund: 1 HA-Shelly-Device zeigt auf `10.95.10.206` (Fremd-Subnetz, nicht BF) → separat prüfen.
|
||
- ⏳ **Rest (nicht mehr Migration, s. TP17.2/TP19):** (1) einheitliches Geräte-PW → **zurückgestellt als [[#TP17.2]]** (Kosmetik). (2) Nicht-Shelly-Mover + cudy-Teardown + VLAN1-Client-Retirement → läuft in **TP19**. (3) DNS/ip-plan Restfeinschliff (mit TP19).
|
||
|
||
#### TP17.2 — einheitliches Geräte-Passwort (Shelly `SetAuth`) ▸ ⏸️ ZURÜCKGESTELLT (Kosmetik, User 2026-07-13)
|
||
- **Was:** je Gerät `Shelly.SetAuth` (User `admin`, realm-individueller `ha1` = sha256("admin:<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.
|
||
- **Ziel:** ~26 Shellys (aktuell untagged VLAN1 `10.40.41.2xx`, weil auf **alt-WLAN cudy**, s. TP3.1/`project_vlan1_dhcp_incident`) auf SSID **`dirtyvader-iot`** (VLAN30, `w2-iot`, WPA2/WPA3-mixed, PSK `74c9L283$669`) umklemmen → DHCP `dhcp-v30`/pool-v30 (live). **Kein netzseitiger Move möglich** (anderes WLAN) → per-Gerät WiFi-Reconfig.
|
||
- **User-Entscheide (2026-07-11):** (1) **volles `shelly-mcp`** bauen (reusable, nicht nur Skript); (2) **Pilot 2–3, dann Rest**; (3) **DHCP-Reservierungen je MAC** in VLAN30 (stabile IPs für HA/ioBroker/DNS).
|
||
- ✅ **Recon durch (`mcp/shelly/discover.py`, read-only /shelly-Sweep):** 16 live, **alle Gen3/Gen4** (uniforme RPC-API `WiFi.SetConfig`, auth=off — kein Gen1-Sonderfall). 10 „offline" = **weihnachten_\*** (s1/s2/s3, saisonal ausgesteckt Juli) + s12/s14/s16/s18/s22/s23 (aus/DHCP-drift). ⚠️ **Inventar-Fix:** s6 (kueche_kuehlschrank, `.213`) MAC falsch erfasst (`0c:72:74:36:90:9e`) → real **`d0:cf:13:d8:18:fc`**. s24 hat gar keine MAC.
|
||
- **Mechanismus je Gerät:** Gen2+ RPC `WiFi.SetConfig {sta:{ssid,pass,enable}}` → Reboot → landet `.30.x`. ⚠️ **Risiken:** falsches PSK → AP-Mode (physischer Reset); Gerät kurz offline; HA/ioBroker-Refs brechen bis re-pointed; WPA3-mixed ggf. zickig auf alter FW; ap1 2,4-GHz-Master `wifi2` `running:false` → Coverage v.a. via ap2 prüfen.
|
||
- ✅ **Live-Abgleich 2026-07-11 (go-ready):** (a) `shelly-mcp` (`server.py`) fertig — discover/get/set_sta/verify/reservation_plan, PSK in `.env` gesetzt (noch nicht als MCP registriert, optional). (b) **Alle VLAN30-DHCP-Reservierungen liegen** (`.30.2xx`, Oktett erhalten, außerhalb Pool `.100–.200`); **s6-Reservierung `.30.213` MAC gefixt** (falsch `0C:72…9E` → real `D0:CF:13:D8:18:FC`). (c) **IOT-SSID live verifiziert:** ap1 `w2-iot` `running:true`, 8 Clients −26…−68 dBm (ap1-`wifi2`-„running:false" ist kosmetisch). (d) **Migration bereits ~5/26 durch:** s14/16/18/22/23 seit ~2,5 d stabil auf reservierten `.30.221/.223/.225/.202/.203` (+ `.30.204` unbekannt, evtl. s24) → **Pilot faktisch bestanden**.
|
||
- ✅ **HA-Cross-Check 2026-07-11 (alle IPv4-Geräte in HA):** Shellys deckungsgleich; **`.30.204` = Shelly „Bad/Spiegelschrank" (Plus RGBW PM, `14:33:5c:d8:2d:7c`) = vmtl. s24** → 6 statt 5 schon migriert. **Netzweite Aufstellung + VLAN1-Leerstand-Analyse** im Runbook: nach TP17 + pve-Host→VLAN20 + Christophs Endgeräte→VLAN10 ist VLAN1 **endgeräte-frei**; es bleiben nur Switch-/AP-Mgmt (sw1/sw2/ap2 → VLAN99-Cutover, eigener Schritt) + **1 unidentifiziertes Gerät `.41.246`** (morgen klären). **Nicht-Shelly-VLAN30-Mover (User-bestätigt):** ✅ SwitchBot floor-lamp `.41.184` + ✅ Twinkly-Girlande `.30.228` (beide 2026-07-16 übersiedelt, s. TP19) + Creality Ender (fehlt noch, off). **Withings schon übersiedelt; Tasmota existiert nicht mehr** (kein aktives Gerät → stale HA-Eintrag). EOS-Smartwatches/eBook-Reader später + von Christoph selbst (eBook eher VLAN50).
|
||
- **Scope-Erweiterung (User 2026-07-11):** je Gerät **3 Änderungen** — WLAN→`dirtyvader-iot` + IP (`.41.2xx`→`.30.2xx`) **+ einheitliches Geräte-Passwort** (`Shelly.SetAuth`, User `admin`, realm-individueller ha1 → Tool `set_auth` in `server.py` nachrüsten). **PW entschieden: eigenes Shelly-Admin-PW** (getrennt vom WLAN-PSK) → `SHELLY_DEVICE_PW` in `.env` (Christoph liefert Wert). **HA-Entities unverändert** (keyt per MAC). **HA-Entities bleiben unverändert** (HA keyt per MAC). **Projektion TP17.1 (experimentell, nachrangig):** Gen4 (~11 St.) auf **Thread/Matter** flashen (Firmware-Verfügbarkeit + Thread-Border-Router offen) — Konflikt mit „Entities unverändert" (Matter = neue Entities) → erst WiFi-Migration stabilisieren.
|
||
- ✅ **Reservierungs-/Pool-Konvention (User 2026-07-11):** alle Shellys bekommen **statische IP** (`10.40.30.<octet>`, gw/dns `.30.1`) **+ in-pool DHCP-Reservierung** als Backup. `pool-v30` auf `.100-.250` erweitert (Reservierungen jetzt in-pool); `set_sta` auf `static=true` umgestellt; s24-Inventar + `.30.204`-Reservierung angelegt. **Vollständiger HA-MAC-Scan:** 2 verpasste Media-Geräte **Apple TV 4K + Philips TV** (aus, → VLAN40) — **vor cudy-Abschuss** VLAN verifizieren; **Apple TV = vmtl. Thread-Border-Router** (TP17.1). **`.41.246/.247 = cudy1/cudy2`** (Teardown-Ziele). Tasmota bestätigt tot.
|
||
- **Offene Schritte (morgen, „nur noch go", Runbook `docs/tp17-shelly-go-runbook.md`):** die **16 verbliebenen VLAN1-Shellys** (s4–s11, s13, s15, s17, s19–s21, s25, s26 auf `10.40.41.2xx`) per `WiFi.SetConfig`→`dirtyvader-iot` umklemmen (Batch, je Gerät `.30.x` verifizieren) → Geräte-PW setzen → HA/ioBroker-Re-Point → SwitchBot/Tasmota/3. Nicht-Shelly → saisonale s1/s2/s3/s12 beim nächsten Einstecken → cudy-Alt-WLAN abbauen → DNS/Inventar/`ip-plan` nachziehen.
|
||
- Abh.: SSID/VLAN30 (TP3/TP4 ✅), DHCP-v30 ✅. Verwandt: `project_vlan1_dhcp_incident` (cudy-Rest-Leak), TP5 (IOT-Firewall danach). Memory `project_shelly_migration_tp17`.
|
||
|
||
### 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.
|
||
|
||
### TP19 — cudy-Teardown + VLAN1-Client-Retirement ▸ ⏳ WEIT FORTGESCHRITTEN — **VLAN1 ist client-frei, es geht nur noch um Aufräumen** (Live-Sweep 2026-08-16) — `docs/tp19-vlan1-cudy-teardown-runbook.md`
|
||
- ✅ **Live-Nachprüfung 2026-08-16 (MikroMCP + CF-API, reine Reads):**
|
||
- **`cudy1` ist tot, nicht nur „offline gemeldet":** `core ether11` steht auf `running=false`, **letzter Link-Down 2026-08-08 19:33**, seither kein Link. Die Formulierung „aktiver VLAN1-Leak" ist damit endgültig hinfällig — der **Dual-DHCP-Race hat keine Quelle mehr**. Offen bleibt nur der *physische* Ausbau + Inventar/Doku.
|
||
- **`crs326-core` hat keine VLAN1-IP mehr:** `/ip/address` listet nur noch die 7 SVIs + die WAN-DHCP-Adresse — die **Bring-up-Altlast `10.40.41.211` ist weg**. Damit fällt einer der 5 Compliance-Drifts aus TP22 raus, *sobald* wieder **Backup → Intended → Compliance** gelaufen ist (die Compliance vergleicht gegen das letzte Backup, nicht gegen das Gerät — s. TP22-Falle).
|
||
- ✅ **`crs326-branch`-Interim ERLEDIGT (2026-08-16):** `10.40.10.2` + SVI `vlan10` über einen GC-ConfigPlan entfernt (s. TP22). Mgmt läuft über `.99.2`; `/interface bridge vlan` blieb byte-identisch, es gibt also weder einen Traffic- noch einen Drift-Effekt.
|
||
- **`.41.133` identifiziert** (war TP19 B1.2 „unidentifiziertes VLAN1-Gerät"): es ist das **coolify-Origin** aus dem gleichnamigen, seit Monaten toten CF-Tunnel. Ebenso `.41.147/.148/.139` aus dem toten `openclaw`-Tunnel. Keine aktiven Geräte — **Karteileichen in der Cloudflare-Config**, nicht im Netz. Aufräumen = die 4 toten Tunnel löschen (user-gated, s. TP16-Nebenbefund).
|
||
- ✅ **VLAN1-Adressen abgeräumt (2026-08-15) — der Weg dorthin** — `docs/vlan1-rueckbau-howto-manuelle-schritte.md`:
|
||
- **pve `10.40.41.100` weg** (`/etc/network/interfaces`: `vmbr0` von `inet static` auf `inet manual`, Adresszeile raus; angewendet per `ip addr del` **ohne** `ifreload -a`, damit die Bridge nicht durchgetreten wird). Nachher nur noch `vmbr0.20`, keine `41.0/24`-Route, alle 9 Gäste weiter `running`, Storage aktiv. Backup `/root/interfaces.bak-tp19-20260815-183045`.
|
||
- **Core `10.40.41.211` weg** über Nautobot GC (`routeros/tp19-core-vlan1-address-remove.rsc`). Mgmt `.99.1` + `10.40.10.1` intakt. Compliance damals 17/17 grün — der TP22-Backlog-Punkt „`crs326-core 10.40.41.211`" entfällt. *(Zahl inzwischen überholt: nach TP16.1 sind es 72/72 Checks.)*
|
||
- **HA zeigt auf `10.40.20.100`** (User), **ioBroker** korrigiert (User).
|
||
- **Prometheus bereinigt.** Der pauschale `41`→`20`-Ersatz war eine Falle: nur `grafana` (`.20.109`) und `n8n` (`.20.167:5678`) liefern echte Metriken. `gitea` hat `/metrics` gar nicht aktiviert, `vaultwarden` gibt 404, `portainer /api/status` liefert JSON statt Prometheus-Format, `node`/`alertmanager`/`qdrant` sind exited, `pihole` ist abgewählt → **8 Jobs + `alerting:`-Block auskommentiert**, 3 aktive Ziele, alle `up`.
|
||
- 🔴 **NAS-Falle:** `prometheus.yml` gehört `65534:65534`, das Verzeichnis `adm.christoph` → `cat > datei` scheitert still („Permission denied"), während ein `cp` daneben klappt. **Schreiben per `sudo tee` + `md5sum`-Gegenprobe**, nie der Shell-Erfolgsmeldung trauen.
|
||
- ⏳ **OFFEN: HA-Portainer-Integration bleibt auf `setup_retry` — `docker system df` auf nas-bf ist zu langsam.** Aus dem HA-Debug-Log: `PortainerTimeoutError … GET /api/endpoints/14/docker/system/df` → `ConfigEntryNotReady`. Die Integration ruft `system df` für **jede** Umgebung bei **jedem** Update auf.
|
||
- **Container-Manager-Neustart am 2026-08-15 durchgeführt** (`/usr/syno/bin/synopkg stop|start ContainerManager` — Binary **nicht** im sudo-PATH; DSM meldet den Status danach weiterhin falsch als `stop`). **Alle 14 Container aus der Baseline zurück**, zusätzlich kam `hms-mqtt` hoch (Restart-Policy `always`, lief vorher nicht).
|
||
- ✅ **`hms-mqtt` stillgelegt (2026-08-16, User: „wird bald platt gemacht").** Es war bereits beendet; entscheidend war die **Restart-Policy `always` → `no`** (`docker update --restart=no`), sonst wäre es beim nächsten Daemon-Neustart wiedergekommen. Ein bloßes `docker stop` hätte hier nicht gehalten.
|
||
- ✅ Der **Hänger** ist damit weg: `system df` beendet sich wieder (vorher rc=124 nach Ausgabe der Tabelle). ❌ **Aber es bleibt viel zu langsam und schwankt: 33 s → 92 s → 3× >120 s.**
|
||
- 🔑 **Wo die Zeit hingeht (gemessen):** `images -q` 84 ms · `ps -aq` 95 ms · `volume ls -q` 65 ms · **`system df` 33–92+ s**. Also **vollständig in der Größenberechnung** (du-artiger Durchlauf der overlay2-/Volume-Verzeichnisse auf NAS-Platten) — ein struktureller Plattformnachteil, kein Defekt. Die Mengen sind harmlos (25 Images/13 GB, 10 Volumes/79 MB).
|
||
- **Aussichtsreichster Weg: eigener Portainer-Benutzer für HA ohne Zugriff auf ep14** → die Integration sieht die langsame Umgebung gar nicht. User-gated (Benutzer + Token anlegen). Alternativen: nichts tun (stört nichts) · Images aufräumen (6,98 GB reclaimable, Erfolg **offen**) · ep14 aus Portainer nehmen (schlechter Tausch).
|
||
- ⚠️ **Zwei widerlegte Zwischenthesen, nicht wieder aufgreifen:** die tote Umgebung `odroid-m1` war es **nicht** (entfernt, Symptom blieb, alle übrigen Endpoints ≤0,16 s); und es ist **kein** Größenproblem der Images.
|
||
- ✅ **Restliste aus dem TP5-Log-Lauf — ABGEARBEITET (Abnahme 2026-08-16: `out:bridge` = 0 über 10 min, Rate von ~166 auf ~34 Zeilen/min gefallen; im 43k-Zeilen-Log vom 08-17 kommt `out:bridge` nicht mehr vor).** Wert dieses Eintrags = die Diagnosemethode, nicht der Stand. Der Log-Lauf hatte gezeigt, dass **76 % allen Inter-VLAN-Verkehrs** aus VLAN20 nach VLAN1 (`out:bridge`) ging, obwohl dort **nichts mehr antwortete** (alle Ziele im ARP `failed`/`incomplete`). Verursacher waren Konfigurationen, die nie nachgezogen wurden:
|
||
- **`prometheus` (`10.40.20.151`, NAS)** scrapet 10 tote Ziele: `10.40.41.109:3000` · `.126:9443` · `.127:80` · `.147:5678` · `.149:3000` · `.152:3001` · `.153:9093` · `.154:9100` · `.159:6333` · `.23:80`.
|
||
- **`10.40.20.105`** zieht auf `10.40.41.100:8006` = **pve unter seiner alten VLAN1-Adresse** (real `10.40.20.100`).
|
||
- **`10.40.20.107`** auf `10.40.41.10:8080` (NAS alt).
|
||
- 📌 **Umzugsregel: das letzte Oktett bleibt gleich, nur `41`→`20`** — belegt für grafana (`.109`), vaultwarden (`.127`), Portainer (`.126`). Für `.23/.147/.149/.152/.153/.154/.159` existiert **kein** laufendes VLAN20-Gegenstück (anderswo oder tot; `alertmanager` ist seit TP14.1 als kaputt notiert) → diese Ziele gehören geprüft und dann aus Prometheus entfernt, nicht umgeschrieben.
|
||
- ⚠️ **Kein Firewall-/Portproblem** (2026-08-14 geprüft, nachdem beim Umstellen ein Timeout auftrat): `pveproxy` lauscht auf `*:8006`, `pve-firewall` ist *disabled*, keine iptables-Regel, kein `/etc/default/pveproxy`. `https://10.40.20.100:8006` antwortet aus VLAN10 **und** VLAN20 mit HTTP 200 in ~0,06 s. Wer hier einen Timeout sieht, sucht an der falschen Stelle — **und `timeout` gibt es auf macOS nicht**, ein `timeout bash -c '… /dev/tcp/…'`-Test meldet deshalb falsch-negativ.
|
||
- ⚠️ **Eskaliert 2026-07-15 (historisch — durch den WLAN-Rebuild 2026-08-08 gegenstandslos):** der unter TP3.1 dokumentierte VLAN1-Leak trat damals auch auf ap1/`dirtyvader-main` auf — die ap-seitige Interim-Härtung (TP3.1) milderte das Symptom, **die endgültige Lösung ist hier, TP19**: VLAN1 physisch weg = kein Leck mehr möglich.
|
||
- 🟢 **cudy-Stand (User 2026-07-16): cudy1 (`.41.246`) auf `10.40.10.246` umgehängt** — bewusst **kein Abbau-Ziel mehr**, dient als Standalone-WLAN-Sender während der Umstellungsphase (nicht Teil des Teardowns, extern vom User selbst umkonfiguriert). **cudy2 (`.41.247`) wird nicht mehr reaktiviert** — faktisch tot, ARP-Sweep bestätigt keine Präsenz mehr auf VLAN1. B2.2 („cudy1/cudy2 stromlos/Reset/ausbauen") ist damit **erledigt/gegenstandslos** (cudy2 aus, cudy1 schon migriert statt abgebaut).
|
||
- 🟢 **Live-Sweep 2026-07-16 (ap1, vor geplantem Teardown):** VLAN1 ist bereits viel weiter zurückgebaut als dokumentiert:
|
||
- `defconf`/pool-v1-DHCP-Server ist bereits **`disabled=yes`** (Export bestätigt) — B2.4 („defconf zurückziehen") ist **de facto schon erledigt**, Ursprung/Zeitpunkt dieser Änderung nicht aus dieser Session bekannt (nicht in dieser Doku protokolliert).
|
||
- ARP auf `bridge` (VLAN1): nur noch **2 „reachable"-Hosts** — `sw1` (`.41.11`, by design, bleibt bis MGMT-VLAN99) und **`pve`-Interim-Fallback (`.41.100`)** (B1.5-Aufräumziel, noch offen — Host-seitige Änderung auf pve, nicht Router). Alle anderen ~20 ARP-Einträge sind **stale/„failed"** (Cache-Reste längst migrierter Hosts wie macmini/.20.167, NAS/.20.10, grafana/.20.109 etc.), keine aktive Kommunikation mehr.
|
||
- **B1.1 MacBook (Claude-Sandbox-Client) bereits sicher migriert:** aktive DHCP-Leases nur noch auf `dhcp-v20` (`10.40.20.101`) und `dhcp-v10` (`10.40.10.187`), keine `defconf`-Lease mehr. ⚠️ Dual-Homed über 2 VLANs gleichzeitig (`project_dual_homing_slowness_incident`-Muster) — funktional ok, aber im Auge behalten.
|
||
- **B1.2 unidentifizierte Geräte `.41.133`/`.41.198`:** kein ARP-Eintrag mehr vorhanden — entweder migriert oder abgeklungen, gelten für den Teardown als **nicht mehr blockierend**.
|
||
- ⚠️ **B1.3 (Media→VLAN40) und B1.4 (saisonale Shellys) nicht in diesem Sweep verifiziert** — weiterhin offen, kurz vor dem finalen Cutover gegenchecken.
|
||
- **Backup-Stand vor Cutover (2026-07-16):** nur **ap1 gesichert** (Binary `bf-ap1-pre-vlan1-teardown-20260716.backup` auf dem Router + lokaler Export `routeros/state-backups/ap1-export-20260716-pre-vlan1-teardown.rsc`). **ap2 nicht gesichert, aber unkritisch:** bewusst ausgesteckt (User-bestätigt 2026-07-16, kein Ausfall) — kein Backup nötig, solange es aus bleibt. **sw1 nicht per Telnet gesichert** (`claudecode`-Login 2× deterministisch abgelehnt), aber **kein Blocker**: User macht sw1-Änderungen ohnehin direkt im UI/CLI selbst (effizienter als über den Claude-Runner, gemeinsame Entscheidung) — Telnet-Automation für sw1 ist hier kein Muss.
|
||
- **Ziel (Kapstein der Segmentierung, s. Zeile 27):** altes **cudy-WLAN weg** + **VLAN1 als Client-Netz stilllegen** (`defconf`/pool-v1-Client-DHCP zurückziehen, ✅ bereits disabled). **Nicht** VLAN1 komplett: Switch-/AP-Mgmt (sw1 `.11`/sw2 `.12`/ap2 `.2`) bleiben **by design** in VLAN1 (statisch, kein DHCP nötig) bis zum separaten **MGMT-VLAN99-Cutover** (eigener TP). ~~cudy1/cudy2 = `.41.246`/`.247` (Teardown-Ziele)~~ — cudy1 migriert auf `.10.246` (Reuse statt Abbau), cudy2 tot/nicht reaktiviert (s.o.).
|
||
- 🎯 **User-Gate (Update 2026-07-14): Shelly ist wieder da (kein Blocker mehr) — SwitchBot ist KEIN Prereq mehr, funktioniert laut User erst NACH VLAN1-Retirement (Reihenfolge ggü. 2026-07-13 umgedreht) → wandert in die Teardown-Nachlese.** TP19 damit direkt startbereit. Twinkly nebenher (saisonal).
|
||
- **Verlorene Shelly — IDENTIFIZIERT via HA 2026-07-13** (User-Hinweis „du siehst ihn im HA"): HA-Device `shellyplugsg3-e4b063e41ab8`, **Modell = Shelly Plug S Gen3**, **MAC `e4:b0:63:e4:1a:b8`**, HA-device_id `7a21e8f3349e6660f8b35974fc989a7b`. **NICHT im 26er-Inventar** (Spare/Küchen-Steckdose, die Christoph beim Einrichten verbockt hat; er nannte sie „küche s20", aber s20=`98:a3:16:7c:5f:ec` läuft sauber auf `.30.206` — Verwechslung). **KEIN AP-Mode, nicht tot:** assoziiert am **Altnetz `elektrosmog.c`** (cudy → untagged VLAN1-L2), aber mit **bogus-IP `10.95.10.206`** (Fremd-Subnetz, User-Fehler) → unrouting-bar, daher weder in VLAN1/30-Sweep noch normal per IP erreichbar, aber **per MAC in HA/WiFi-Table sichtbar**. Der `.219/s12`-Verdacht war Sackgasse (s12 nur saisonal aus).
|
||
- **Update 2026-07-14: Shelly wieder da** (User-Meldung) — Live-Status (noch bogus-IP `10.95.10.206` oder inzwischen normal erreichbar?) **zu Sessionbeginn per HA/ARP verifizieren**; Recovery-Plan unten ggf. obsolet, falls sich das Gerät selbst erholt hat.
|
||
- **Recovery-Plan (falls beim Verify noch nötig):** ap1 bekommt **temporäre Zweit-IP `10.95.10.1/24` auf der Bridge** → `10.95.10.206` per L2 erreichbar → **ein** `WiFi.SetConfig {sta: ssid=dirtyvader-iot, pass=IOT-PSK, static, ip=10.40.30.<frei>}` + `Shelly.Reboot` → Gerät kommt auf VLAN30 hoch → temp-IP entfernen. Danach `.30.x`-Reservierung + Inventar (MAC `e4:b0:63:e4:1a:b8`) + eco-Policy. Umgeht die „blutige Nase" (IP am Gerät ändern während man drauf hängt = Verbindungsverlust) — vom Router aus in einem Rutsch. Christophs manueller Direkt-Versuch (AP-IP auf 10.40.30 „verdrehen") war genau deshalb gescheitert.
|
||
- ✅ **SwitchBot floor-lamp** `.41.184` (`b8:f8:62:09:f2:04`) → **erfolgreich auf VLAN30 übersiedelt (2026-07-16, Christoph via App/BLE)**, Res. `.30.227`.
|
||
- **Prereqs-Status (live nachgezogen 2026-07-16, s. Live-Sweep oben):**
|
||
1. ✅ **Christophs Endgeräte → VLAN10/20 erledigt:** MacBook-Air (`c0:c7:db:de:71:be`, Claude-Sandbox-Client) hat aktive Leases nur noch auf `dhcp-v10`/`dhcp-v20`, keine `defconf`-Lease mehr. iPhone `.41.186` nicht im aktuellen Sweep erneut geprüft (zuletzt off/asleep) — kurz vor Cutover gegenchecken.
|
||
2. ✅ **2 unidentifizierte VLAN1-Geräte (`.41.133`/`.41.198`) aus dem ARP verschwunden** — kein aktueller Eintrag mehr, gelten als nicht mehr blockierend (entweder migriert oder abgeklungen).
|
||
3. ⏳ **Media → VLAN40 weiterhin offen:** Apple TV 4K + Philips TV nicht in diesem Sweep verifiziert.
|
||
4. ⏳ **Saisonale Shellys s1/s2/s3/s12 weiterhin offen** — nicht blockierend, kann übersprungen werden (Re-Onboarding-Aufwand akzeptiert).
|
||
5. ⏳ **pve-Interim-IP `.41.100` weiterhin aktiv/reachable** — Host-seitiger Cleanup auf pve selbst noch offen (nicht Router-Config).
|
||
- **Teardown-Sequenz (angepasst an den Live-Stand):** VLAN1-Client-Sweep ist **schon fast leer** (nur sw1-Mgmt + pve-Interim reachable) → `defconf`/pool-v1 ist **bereits disabled** → cudy-Abbau **entfällt** (cudy1 umgenutzt statt abgebaut, cudy2 tot) → ✅ **SwitchBot + Twinkly erledigt (2026-07-16)** → **verbleibt:** Media-Check (B1.3), pve-`.41.100` abräumen (B1.5), Interim-Krücken bewerten (ap2 `frame-types=admit-only-vlan-tagged`, `st-main rrm/wnm`), Inventar/`ip-plan`/DNS `.41→Ziel` final.
|
||
- Abh.: **TP14 ✅** (Hosts raus aus VLAN1), **TP17 ✅** (Shellys raus). Verwandt: `project_vlan1_dhcp_incident` (cudy-Dual-DHCP-Leak), TP5 (Deny-by-default danach sauberer). SSoT hier + `docs/tp19-vlan1-cudy-teardown-runbook.md`. Folge: **TP19.1**.
|
||
|
||
#### TP19.1 — VLAN99-MGMT-Cutover (sw1/sw2/ap2-Mgmt VLAN1 → VLAN99) ▸ ✅ ERLEDIGT (2026-08-14 nachgezogen) — alle lebenden Geräte auf VLAN99, die beiden Rest-Punkte gegenstandslos
|
||
- ✅ **Abschluss-Nachtrag 2026-08-14 (Status-Korrektur, kein neuer Change):** der Header stand noch auf „ap2 vertagt, sw1 offen" (Stand 2026-07-16) — beides ist durch spätere TPs eingelöst bzw. gegenstandslos geworden, ohne dass es hier nachgetragen wurde. Ist-Stand: **core `.99.1` · branch `.99.2` · ap1 `.99.11` · ap2 `.99.12`** — jedes lebende Netzgerät hat sein Mgmt auf VLAN99. **sw1/sw2 existieren nicht mehr** (physisch ausgebaut, in Nautobot per TP22 Schritt 5 auf *Decommissioned*). Damit ist TP19.1 vollständig; offen bleibt nur der VLAN1-**Client**-Teil, und der gehört zu TP19 (Hauptteil), nicht hierher.
|
||
- **Scope:** die einzigen Dinge, die TP19s Hauptteil bewusst in VLAN1 belässt — sw1 (`.41.11`), sw2, ap2-Mgmt (`.41.2`) — auf VLAN 99 (MGMT, `10.40.99.0/24`) umziehen. Erst danach ist VLAN1 wirklich **komplett** weg, nicht nur als Client-Netz.
|
||
- **User-Entscheid (2026-07-16):** kein eigenständiges TP-Nummer — bewusst als **Unterpunkt von TP19** geführt („VLAN1 killen"), nicht als TP22 o.ä.
|
||
- ✅ **ap1-Teil erledigt (2026-07-16):** ap1 brauchte keinen funktionalen Umzug (vlan99-Interface/GW `.99.1` läuft schon seit TP4) — nur der kosmetische DNS-Static-Nachtrag `ap1.bf.lan` `10.40.41.1`→`10.40.99.1` war offen, per MikroMCP erledigt (dry-run→apply, `manage_dns_entry`).
|
||
- ✅ **sw2-Teil erledigt (2026-07-16, Christoph selbst über die Klickanleitung):** sw2 jetzt auf **`10.40.99.12`** (statisch, planmäßiger Zielwert aus `ip-plan.md`) — per Ping verifiziert. Zwischenzeitlich war das Gerät kurz auf einer *dynamischen* `10.40.99.200`-Lease aufgetaucht (unklare Ursache, s. Memory `project_tp20_tp21_fasttrack_20260716`), jetzt aber sauber auf der geplanten statischen Adresse. `CLAUDE.md`/`ip-plan.md` nachgezogen.
|
||
- ✅ **ap2-Teil erledigt (2026-08-08, im TP3-Rebuild) — die Vertagung wurde wie geplant eingelöst.** ap2-Mgmt liegt auf **`10.40.99.12`** (VLAN99), gesetzt bei der Standalone-Neuprovisionierung, nicht isoliert von Hand; `primary_ip4` in Nautobot per TP22 Schritt 5 nachgezogen. Der `ap2.bf.lan`-DNS-Static wurde im TP22-Pilot-Deploy (2026-08-13, GC-ConfigPlan) von `10.40.41.2` auf `.99.12` gezogen. Ursprüngliche Vertagungs-Begründung zur Historie:
|
||
- 🔜 **~~ap2-Teil bewusst vertagt~~ (User-Entscheid 2026-07-16): erst NACH Nautobot (TP21).** Nautobot übernimmt dann in einem Rutsch ap1 + ap2 + die neuen CRS326-Switches (TP15) als config-as-code-Fleet — der ap2-Mgmt-VLAN-Umzug wird also nicht mehr isoliert von Hand gemacht, sondern Teil der Nautobot-Erstadoption. `ap2.bf.lan`-DNS-Static bleibt bewusst auf `10.40.41.2` bis dahin.
|
||
- 🔒 **TP19.1 war die letzte Ausnahme vom ap1/ap2-Config-Freeze — der jetzt (2026-07-16) zur generellen Regel ausgeweitet wurde** (s. Governance-Entscheid oben): **jede** Gerätekonfiguration künftig ausschließlich über Nautobot, keine direkten Änderungen mehr an einzelnen im Netz verstreuten Geräten. Der ap1-DNS-Fix oben war die letzte direkte MikroMCP-Write-Aktion unter der alten (engeren) Regel.
|
||
- ⚪ **sw1-Teil GEGENSTANDSLOS (2026-08-14 festgestellt):** Christoph hat sich für „auf CRS326 warten" entschieden — sw1 wurde am **2026-08-08 durch `crs326-core` ersetzt und physisch ausgebaut** (Nautobot: *Decommissioned*, TP22 Schritt 5). Ein Mgmt-VLAN-Umzug für ein nicht mehr existierendes Gerät entfällt ersatzlos. **`switch/ui-guides/02-vlan99-mgmt-cutover.md` ist damit historisch** (nie ausgeführt, nicht mehr ausführbar — der Telnet-Runner `switch/` insgesamt nur noch Archiv). Ursprünglicher Stand zur Historie: Klickanleitung fertig, Ausführung on-demand (User-Entscheid 2026-07-16), nicht blockierend.
|
||
- **Bereits vorbereitet:** `docs/ip-plan.md` Phase 2 hat schon einen Entwurf (ap2→`10.40.99.2`, sw1→`10.40.99.11`, „Lockout-Risiko, sorgsam", sw1 zuletzt).
|
||
- **Abh.:** TP19-Hauptteil (VLAN1-Client-Retirement) — logisch danach, da VLAN99 als eigenes Mgmt-Netz erst dann wirklich nötig wird, wenn VLAN1 sonst leer ist. sw1-Teil braucht sw1-Telnet-Zugriff (User macht sw1-Changes direkt, s. Feedback-Memory) — Lockout-Risiko am größten bei sw1 (einziger Netzpfad zu sw2 hängt am Uplink).
|
||
|
||
### TP20 — Platform-Datenbank (Postgres Precious-Tier + MariaDB Tier-2) ▸ ✅ **Plattform live (2026-07-16)** — Nautobot-DB angelegt, vw-Migration (TP20.1) offen — Memory `project_mikrotik_commit_nautobot_gc`
|
||
- ✅ **Platform-Postgres live (2026-07-16):** LXC 105 auf pve, `platform-pg.bf.lan` / `10.40.20.20`, Ubuntu 24.04 (native PG16-Paket, kein PGDG-Repo nötig — bewusste Abweichung von der sonstigen Debian/community-scripts-Konvention der übrigen pve-LXCs, aus PG16-Verfügbarkeitsgründen). Cluster mit `--locale en_US.UTF-8 -e UTF8` neu initialisiert (Erstinstallation lief in `C`/`SQL_ASCII`, für Nautobot ungeeignet, korrigiert). `wal_level=replica` gesetzt; **`archive_mode` bewusst noch NICHT an** — ohne pgBackRest/Garage-S3 (TP18) zum Prunen würde archivierte WAL unbegrenzt wachsen und die kleine 8GB-Disk füllen; wird nachgezogen sobald TP18 steht. Rolle+DB `nautobot` angelegt, `pg_hba.conf` erlaubt `scram-sha-256` aus `10.40.20.0/24`. End-to-End-Verbindungstest (Netzwerk, nicht nur localhost) erfolgreich. Creds in `postgres/.secrets` (gitignored, `chmod 600`).
|
||
- **Auslöser:** Mehrere Dienste brauchen zentrale DB (Nautobot-SoT [TP21], Vaultwarden, HA-Recorder). Grundsatzentscheid statt Nautobot-Insellösung — „wir skalieren schneller als wir schauen können" (User).
|
||
- ⚠️ **Abh.-Korrektur (User 2026-07-16): TP18 (Garage-S3) ist KEINE Vorbedingung mehr — „hat mit dem Netz nichts zu tun", transitiv aus der TP21-Kette entfernt.** pgBackRest→Garage-S3 (s.u.) wird **nachgezogen sobald Garage existiert**, blockiert aber nicht mehr den Start. `wal_level=replica`/`archive_mode` können mit einem Platzhalter/lokalen Archive-Ziel hochgezogen werden, produktives Off-Site-PITR kommt später.
|
||
- ⚠️ **Komodo-Abh. (s. TP2/Memory `project_komodo_tp_pending`) vorerst zurückgestellt:** Komodo selbst existiert noch nicht als laufendes System — kann also nicht „darüber" deployt werden. **Entscheidung (Claude, 2026-07-16, transparent statt stillschweigend): Postgres-LXC + Nautobot-Stack werden jetzt direkt gebaut (LXC/Docker-Compose), Komodo adoptiert sie später** — gleiches Muster wie bei den CRS326 (Hardware/Stack zuerst lauffähig, Management-Layer zieht nach). Sag Bescheid, falls das nicht gewünscht ist.
|
||
- 🔍 **Ressourcen-Check 2026-07-16 (live geprüft, SSH):**
|
||
- **pve** (10.40.20.100): 4 vCPU, **15 GB RAM total, ~12 GB belegt, nur ~2-3 GB frei, 3 GB bereits im Swap** — eng! Größter Verbraucher: HAOS-VM (`haos`, vmid 100) mit ~8,2 GB aktiv von 10 GB Limit. Disk unkritisch (94 GB Root, 85 GB frei).
|
||
- **Mac mini** (10.40.20.167): 10 CPU, 24 GB RAM, **nur ~1,9 GB "wired" (nicht reklamierbar)** — deutlich mehr echter Headroom als pve trotz "23G used"-Anzeige (macOS-Cache-Artefakt). Docker läuft bereits dort (n8n, n8n-redis, cloudflared×2, gitea-mcp, portainer_agent).
|
||
- NAS nicht geprüft (kein funktionierender SSH-Zugriff von hier aus mit den vorhandenen Keys/User) — für diese beiden Stacks laut TP20/TP21-Plan ohnehin nicht Zielhost.
|
||
- **✅ Entschieden (2026-07-16): Postgres-LXC auf pve, Nautobot-App-Stack auf NAS** (nicht Mac mini) — NAS hat mehr Headroom (~12 GB verfügbar) und hostet bereits **Gitea** (Nautobots Git-Backend für Golden-Config-Templates), kürzere Wege als Mac mini. Deploy-Weg: **Portainer-Stack auf ep14**, analog dem bestehenden Muster (`docs/nas-vlan20/stacks/*.yml`), Basis = offizielles `nautobot-docker-compose` (github.com/nautobot/nautobot-docker-compose), nicht von Null gebaut. Wird als **separate Session** angestoßen (parallel zum Postgres-LXC-Aufbau auf pve).
|
||
- **Nachtrag (2026-07-16, nach Aufräumen): pve hat sich entspannt** — nach Abschalten mehrerer mittelfristig eh stillzulegender Services (User) jetzt **6,7 GB frei, 0 Swap** (vorher 2-3 GB frei, 3 GB Swap). Postgres-LXC passt entspannt.
|
||
- **RAM-Upgrade-Idee (32GB-Stick) zurückgestellt (User 2026-07-16):** Intel N100 (pve-CPU) ist offiziell auf max. 16 GB spezifiziert + Single-Channel; ein dokumentierter Fall mit demselben Corsair-Modul auf vergleichbarer N100-Hardware endete in Memtest86-Fehlern, stabil erst nach Rückbau auf 8GB. Empfehlung: 16GB als Decke für diese Kiste behandeln statt auf einen Settings-Fix zu hoffen. **User rechnet ohnehin mittelfristig mit einem HW-Tausch für pve** — gehört ggf. in TP15s HW-Refresh-Scope, noch nicht formal aufgenommen.
|
||
- **✅ 2-Tier (User 2026-07-14):**
|
||
- **Tier-1 „Platform-Postgres" (precious):** EIN Postgres-Cluster, getrennte DBs für **Nautobot** (hier provisioniert) **+ Vaultwarden** (Onboarding = **TP20.1**). **PG 16** (Nautobot-Matrix-safe; **Nautobot unterstützt kein MariaDB**, nur PG/MySQL-8 → Postgres ist gesetzt, nicht optional).
|
||
- **Tier-2 (Bestand):** **HA-Recorder bleibt MariaDB** (Write-Churn, andere Zuverlässigkeitsklasse, single-site). *(Vaultwarden liegt heute ebenfalls auf MariaDB → wandert per TP20.1 nach Tier-1.)* Engine-Split fällt sauber entlang der Tier-Grenze.
|
||
- **✅ Single-Site-first (User 2026-07-14):** jetzt nur BF-Primary („gehostet wird vorerst auf der bf-site", 2026-07-16 reconfirmed). Nimmt das **2-Site-Quorum/Split-Brain**-Problem (bräuchte 3. Witness) vom Tisch. **ABER replication-ready ab Tag 1:** `wal_level=replica`, `archive_mode=on` (Ziel vorerst lokal/Platzhalter, s.o.) — späterer Standby = `pg_basebackup`, **kein** Primary-Umbau/Restart. pgBackRest→Garage-S3 folgt nach TP18, nicht mehr Blocker.
|
||
- **Substrat:** Postgres in **LXC auf pve** (DB-Klasse, nicht Docker).
|
||
- **Scope TP20 = Plattform:** Cluster hoch, Tiering, Backup/PITR, **Nautobot-DB** anlegen. **vw-Migration + Cross-Site-HA = TP20.1** (ausgelagert).
|
||
- **Offene Sub-Steps:** PG-Version final (16 vs 17); Rollen/DB-Anlage Nautobot; pgBackRest-Bucket in Garage folgt **nach** TP18 (nicht mehr Blocker, s.o.).
|
||
- ⚠️ **Komodo-Abh. (User 2026-07-16) vorerst zurückgestellt, s.o.:** ursprünglich als Blocker gedacht (TP20 + neue Softwarepakete über Komodo statt direkt/Portainer), aber Komodo existiert noch nicht lauffähig und hat keine eigene TP-Nummer (nur unter TP2/TP11 erwähnt) → **entkoppelt, um die Montag-Deadline zu halten.** Komodo-TP-Nummer weiterhin zu klären, aber nicht mehr auf dem kritischen Pfad für TP20-Start.
|
||
- Abh.: **keine harten Blocker mehr** (TP18 entfernt, Komodo entkoppelt). **Blockt weiterhin TP21 + TP20.1.**
|
||
|
||
#### 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.
|
||
|
||
### TP21 — Nautobot Golden Config (config-as-code Control-Plane) ▸ 🟢 **Plattform + Datenmodell + Templates live** (App 2026-07-22, Basisdaten + Git-Backend + L3-Core-Template 2026-08-05, ap1/ap2 As-built 2026-08-08); **Device-Adoption/Compliance-Push ausgelagert → TP22** — Memory `project_mikrotik_commit_nautobot_gc`
|
||
- **Ziel:** modellierter Control-Plane über den MikroTik-**RouterOS**-Kern: GUI-SoT + **Config-Compliance/Drift** + intended-config + Push. **Ergänzt** MikroMCP (interaktiv/Debug), **ersetzt es nicht** (deklarativ/DR/Compliance). Aus User-Recherche 2026-07-14: MikroTik in Golden Config **erstklassig** (`mikrotik_routeros` + `_api`, Nornir/NAPALM, backup+deploy).
|
||
- **Scope-Grenze (Fassung 2026-08-16, nachgezogen):** RouterOS in-model = **`crs326-core` (L3-Router) + `crs326-branch` (L2) + ap1/ap2 (reine APs)** — alle 4 Geräte sind seit TP22 adoptiert, Golden Config deckt damit den **ganzen Fabric inkl. WLAN**. Es bleibt **nichts** außerhalb: der frühere Vorbehalt „außerhalb bleibt Omada-WLAN" ist gegenstandslos, seit der Omada-Stack gelöscht (2026-07-16) und CAPsMAN abgeschafft (2026-08-08) ist.
|
||
> *Vorherige Fassung (überholt): „RouterOS in-model = Router (ap1/ap2, dauerhaft — kein RB5009) + beide CRS326-Switches (RouterOS-Boot) → Golden Config deckt den ganzen Kabel-Fabric. Außerhalb bleibt nur Omada-WLAN (eigener Controller, spielt aber laut TP15-Korrektur ohnehin keine Rolle mehr)."*
|
||
- 🔒 **Wird zum alleinigen Config-Weg für Netzgeräte (Governance-Entscheid 2026-07-16, s. oben):** ab hier keine ad-hoc MikroMCP-Writes/Switch-UI-Klicks mehr auf Dauer — Nautobot managed den Fleet.
|
||
- ✅ **Nautobot-Stack live (2026-07-16), auf NAS statt Mac mini** (Ressourcen-Check hatte Mac mini vorgeschlagen, dann auf NAS umentschieden — mehr Headroom + Gitea-Co-Location, s. TP20-Log): Portainer-Stack `nautobot` (Id 203, ep14), 4 Container — `nautobot` (App/API, `10.40.20.30:8080`), `nautobot-worker` (Celery), `nautobot-scheduler` (Celery Beat), `nautobot-redis`. Bild `ghcr.io/nautobot/nautobot:3.1.7` (offizielles Image direkt, **nicht** das `nautobot-docker-compose`-Repo — das ist ein `invoke`/Poetry-getriebenes Dev-Tooling-Repo ohne eigenständige `docker-compose.yml`, für einen Portainer-String-Stack ungeeignet; bewusste Abweichung, dokumentiert statt stillschweigend). DB = Platform-Postgres (`10.40.20.20`, TP20). Compose-Datei `docs/nas-vlan20/stacks/210-nautobot.yml` (gitignored, wie alle NAS-Stack-Files).
|
||
- 🐛 **Gotcha beim ersten Deploy:** alle 3 Nautobot-Container liefen initial gleichzeitig `migrate` (Standard-Entrypoint-Verhalten) → Race-Condition, `IntegrityError` auf `pg_type`. Fix: `nautobot`-Service kriegt einen `healthcheck` (`curl .../health/`), `nautobot-worker`/`nautobot-scheduler` starten erst bei `depends_on: nautobot: condition: service_healthy` — serialisiert die Migration sauber auf einen Container. DB dafür einmal `DROP`+`CREATE` (sauberer Neustart, kein Datenverlust — war eh leer).
|
||
- ✅ **End-to-End verifiziert:** `/api/status/` mit Token 200, Nautobot-Version 3.1.7, alle 4 Container laufen. Superuser `admin` angelegt, Creds im Stack-File (gitignored) + `postgres/.secrets` (DB-Seite).
|
||
- ⚠️ **Bekannt offen, nicht blockierend:** kein HTTPS/Reverse-Proxy vor Nautobot (Django-Security-Warnings beim Start, erwartet für internen HTTP-only-Betrieb auf VLAN20 — analog anderen internen Diensten); Celery-Worker-Registrierung beim allerersten Start nicht sofort sichtbar (`celery-workers-running:0` initial), unkritisch, braucht kurz zum Einpendeln.
|
||
- **PoC-Pfad (angepasst an die Montag-Deadline):** ~~Nautobot-Stack hoch~~ ✅ → **ap1 + ap2 in einem Rutsch adoptieren** (ap2 bekommt dabei gleich seinen VLAN99-Mgmt-Umzug aus TP19.1, s.o. — nicht isoliert vorher) → sobald CRS326 verkabelt sind, **direkt als Nautobot-verwaltete Geräte adoptieren statt erst manuell konfigurieren** → Compliance/Drift + Templates/intended für VLAN-/Firewall-Standards danach.
|
||
- ✅ **Basisdaten-Ingest durchgeführt (2026-07-22)** — Ist-Zustand, nicht Zielzustand (User-Entscheid: „wir gehen vom status quo aus"). Quelle = ap1 live via MikroMCP. Skript-Muster idempotent (get-or-create + Delta-PATCH).
|
||
- **Locations:** neuer LocationType `Bereich` unter `Site`; `BF → Technik UG` (crs326-core, crs326-branch, ap2) und `BF → Wohnzimmer Sideboard` (ap1).
|
||
- **Devices:** ap1 = Rolle *Router* (Ist **am 2026-07-22** — ⚠️ seit der Adoption 2026-08-13 ist ap1 in Nautobot *Wireless AP* und `crs326-core` der *Router*, s. TP22), ap2 = neue Rolle *Wireless AP* + Status **Offline**, beide CRS326 **Platform RouterOS nachgetragen** (fehlte → hätte jeden GC-Job auf ihnen verhindert) + Werks-MAC/software-id in `comments`. Neu als Übergangs-Devices **ohne Platform** (nie GC-fähig, bewusst): `sw1` (ALLNET), `sw2` (ES208G), `cudy1`.
|
||
- **IPAM:** VLAN-Group `BF` + **9 VLANs** (1 *Deprecated*, 10/20/30/40/50/90/99/100 aktiv) + **8 Prefixes**, jeweils an ihr VLAN gebunden. VLAN100/WAN bewusst ohne Prefix (öffentliches Liwest-/24, gehört uns nicht).
|
||
- **ap1-Interfaces (26):** ether1-5, bridge, lo, wg-hub, vlan10-100, wifi1/wifi2, 7 VAPs — inkl. MACs, `ether2` als Trunk (untagged VLAN1 + tagged 10-100), VAPs als Access-Ports auf ihrem VLAN. 9 Gateway-IPs an ihren Interfaces. Platzhalter-Interface `mgmt` auf ap1 gelöscht (existiert real nicht).
|
||
- **WLAN:** logischer Controller `bf-wlan` (**kein** CAPsMAN — `controller_device` bewusst leer, die Control-Plane *ist* Nautobot GC) + Gruppe `BF-WLAN-APs` (ap1+ap2) + **6 WirelessNetworks mit VLAN-Bindung** + 2 RadioProfiles (2,4 GHz ch1 / 5 GHz ch36, Domain AT).
|
||
- 🐞 **API-Gotcha:** `tagged_vlans` wird vom REST-Serializer in Detail-/List-Views als `null` zurückgegeben, **obwohl korrekt gespeichert** — Verifikation nur über **GraphQL** verlässlich. Kostet sonst eine Stunde Fehlersuche an einem Nicht-Problem. Ebenso: Relationen kommen per Default ohne `display` (`?depth=1` nötig), und `VLANGroup`/`Prefix`/`VLAN` brauchen passende `content_types` am LocationType, sonst 400.
|
||
- ✅ **CRS326-Core L3-Device-Modell + Ports angelegt (2026-08-05):** `crs326-core` jetzt Rolle *Router*, alle VLAN-SVIs (`vlan10/20/30/40/50/90/99/100`) + Gateway-IPs `.1` (außer vlan100) in Nautobot; Portbelegung via `nautobot/ingest-crs326-ports.py` aktualisiert. `crs326-branch` bleibt *Switch* mit Mgmt-IP `.99.13` (Zielrenumber `.12` im Cutover-Fenster).
|
||
- ⚠️ **Offen/nachzutragen:** exaktes Modell von sw1 + cudy1 (aktuell `… (Modell TBD)`); Standort von sw1/sw2/cudy1 (hängen an `BF` statt an einem Bereich); ~~ap2s `primary_ip4` zeigt noch auf das tote `10.40.41.2`~~ → ✅ **erledigt (TP22 Schritt 5): `10.40.99.12`.**
|
||
- ✅ **Git-Backend an Gitea angebunden (2026-08-05):** Repository `bf-golden-config` (`jinja_templates/mikrotik_routeros.j2`) sync-t in Nautobot; Generate Intended Config für `crs326-core` erfolgreich, intended config in GC-Tabelle vorhanden.
|
||
- ✅ **Lokale Cutover-Config materialisiert:** `routeros/tp15-core-cutover-intended.rsc` enthält die aus Nautobot gerenderte Config plus die 54 ap1-Leases und den WG-Hub-Privkey (lokales Fenster-Artefakt, **nicht** im Golden-Config-Repo).
|
||
- **↪️ Adoption + Compliance-Push → ausgelagert nach TP22** (eigener TP, User-Entscheid 2026-08-08): ap1/ap2/crs326-Adoption, RouterOS-Nornir-Dispatcher, `enable_deploy`, WG-Privkey/PSK-Secret-Handling. TP21 selbst = Plattform + Datenmodell + Templates (steht). Datenmodell-Nachträge (branch/core-Ports final, sw1 außer Betrieb, cudy1) laufen in TP22 mit.
|
||
- Abh.: **TP20** (Postgres muss stehen), Gitea ✅, RouterOS-Fleet (core/branch/ap1/ap2).
|
||
|
||
### TP21.1 — Core-Cutover-Recovery (ap1 → crs326-core als L3-Router) ▸ ✅ NETZ WIEDER LIVE (2026-08-08); Aufräum-Todos offen
|
||
> **Kern-Erkenntnis (wichtig gegen Doku-Verwirrung):** **`crs326-core` IST jetzt der produktive L3-Router.** Der Core-Cutover (TP15) wurde faktisch vollzogen — ap1 wurde plattgemacht/getrennt, core hat Routing/DHCP/DNS/NAT/WG-Hub übernommen. core-Mgmt = **`10.40.99.1`** (vlan99-SVI) bzw. same-subnet-Fallback **`10.40.10.1`** (RouterOS-Version 7.19.5 identifiziert das Gerät zweifelsfrei als CRS326, nicht als hAP/ap1). Die CLAUDE.md-Zeile „core grundkonfiguriert, NICHT produktiv" ist damit **überholt**.
|
||
- **Verlauf:** Ausgangssymptom war ein L3-Ausfall-Eindruck (kein DHCP, „kein Routing nach .20.x"). Ursache = **unvollständiger Cutover**: core hatte L3-SVIs + Firewall, aber es fehlten DHCP-Server, WAN-Egress, WG-Hub und der DNS-Resolver-Upstream. ap1 (bisher alleiniges L3-Gerät) war bereits Werksreset + getrennt.
|
||
- ✅ **DHCP wiederhergestellt** aus letztem ap1-Backup (`routeros/ap1-pre-core-cutover-20260806-073616.rsc`): 7 Server (`dhcp-v10…v99`) + 8 Networks + **54 statische Reservierungen** + Option `dns 1.1.1.1`. Reproduzierbar in `routeros/tp21-core-dhcp-from-ap1.rsc`. Legacy VLAN1 (pool-v1/defconf) + tote omada-inform-Option bewusst weggelassen.
|
||
- ✅ **WAN/Internet:** dhcp-client auf `vlan100` → Liwest-Public-IP `90.146.33.177` gebunden (Arris hängt physisch an core.vlan100), NAT-Masquerade `out-interface-list=WAN`, Default-Route korrekt; die self-pointing Blackhole-Route `0.0.0.0/0 via 10.40.99.1` entfernt. **disabled-Falle beachtet:** die ap1-Masquerade-Regeln `out-interface=bridge`/`=ether1` sind `disabled=yes` und wurden NICHT übernommen.
|
||
- ✅ **WG-Hub (TP10)** neu aufgebaut: `wg-hub` (listen 51821, Privkey aus `routeros/ap1-wg-hub.privkey`, Hub-Pubkey unverändert) + Peers `fm`/`dw` + Routen. **Beide Tunnel handshaken** (dw + fm live). Reproduzierbar (Privkey redacted) in `routeros/tp21-core-wan-wg-restore.rsc`.
|
||
- ✅ **DNS gefixt:** core hatte `allow-remote-requests=no` + leeren Upstream → Client-DNS tot UND Hub konnte myfritz (FM-Endpoint) nicht auflösen. Fix = `allow-remote-requests=yes` + `servers=1.1.1.1` (**plain**, weil core `certs=0` → `verify-doh-cert` unmöglich). Das entsperrte auch FM.
|
||
- ✅ **Identity** auf `crs326-core` gesetzt (war fälschlich „ap1" — genau diese Altlast stiftete Verwirrung). `mcp/mikromcp/config/routers.yaml` auf Zielschema: core `.99.1`, branch `.99.2`, ap1 `.99.11`, ap2 `.99.12` (wirkt nach MCP-Neustart; danach core via routerId `crs326-core`).
|
||
- ✅ **disabled/invalid-Falle bereinigt (User-Hinweis „keine disabled-Falle?"):** (a) die 2 TP10-WG-Forward-Regeln (`allow from/to WG spokes`) waren `I`=invalid, weil aus dem ap1-Backup mit der **stale Interface-ID `*1D`** übernommen → auf `in/out-interface=wg-hub` (per Name) korrigiert; (b) 2 **inaktive WG-Route-Leichen** (`gateway=""`, aus einem früheren Cutover-Versuch vor Existenz von wg-hub) entfernt, nur die aktiven `gateway=wg-hub` bleiben. **Finaler Sweep sauber:** filter-invalid=0, nat-invalid=0, routes-inactive=0, if-disabled=2 (nur ungenutzte `sfp-sfpplus1/2`, gewollt).
|
||
- ✅ **Backups:** `core-pre-dhcp-restore-20260808.backup` (vor Eingriff) + `core-post-tp21-recovery-20260808.backup` (nach allen Fixes neu gezogen) auf dem Gerät.
|
||
- ℹ️ **branch** ist gesund (L2, forwardet), Mgmt `10.40.99.2` (~~+ temp `10.40.10.2`~~ — die Temp-IP ist am 2026-08-16 entfernt worden) — via core-MNDP bestätigt. Das in Winbox-MAC gesehene „0.0.0.0" ist der bekannte Discovery-Artefakt (Gerät hat auf dem Discovery-VLAN keine IP), kein echtes Problem.
|
||
- 🔜 **TODO (Aufräum-Liste, spätere Session — danach WLAN-Neuprovisionierung):**
|
||
1. **DoH-Cloudflare-Gateway auf core wiederherstellen** (aktuell nur plain 1.1.1.1, keine Filterung/Account-Bindung): CA-Bundle importieren → `use-doh-server=https://px35ynlol3.cloudflare-gateway.com/dns-query verify-doh-cert=yes` (Referenz-Config liegt auf **ap1**).
|
||
2. **Intended config nach Nautobot zurückschreiben** (die Direkt-Writes liefen unter der CRS326-Cutover-Governance-Ausnahme).
|
||
3. **branch `192.168.88.1`-Rest verifizieren** (Bootstrap Rev 4 entfernt es in Zeile 70; via MCP noch nicht gegengeprüft, weil Registry-Umstellung MCP-Neustart braucht).
|
||
4. ✅ **core `ether4` GEKLÄRT (2026-08-13) — es ist das Wohnzimmer-Sideboard (Smart-Managed-Switch, nur VLAN40-Multimedia), und der Port ist der falsche.** Symptom war „TV meldet, LAN funktioniert nicht".
|
||
- **Ursache = VLAN-Mismatch, kein Kabeldefekt:** `ether4` hat `pvid=40` (untagged **rein** → VLAN40 ✓), ist in VLAN40 aber **tagged**-Member (untagged sind `ether2`/`ether3`/`ether5`) → alles **raus** ist 802.1Q-getaggt und der untagged Switch/TV verwirft es. Einseitige Kommunikation.
|
||
- **Belege:** TX 3,4 GB / 16 M Pakete gegen RX 452 KB / 1.338 Pakete, 0 stabil gelernte MACs; TV-Lease `10.40.40.11` (`70:AF:24:B8:C9:86`) **bound, last-seen 1h54m**, gleichzeitig ARP-Status **`failed`** — ein Gerät, das nachweislich sendet, aber nicht antwortet. Der bound-Lease ist kein Gegenbeweis: beim Einschalten macht der TV einen INIT-REBOOT-`REQUEST` auf seine alte IP, RouterOS quittiert mit ACK und markiert bound — **das ACK muss den Client nie erreichen**.
|
||
- **Herkunft:** `ether4` war als **ap1-Uplink-Trunk vorbereitet** („ap1 wandert #15→#4"); ap1 blieb auf `ether15`, in den übrigen Trunk-Port wanderte das Sideboard-Kabel.
|
||
- ✅ **BEHOBEN 2026-08-13 — am Port, nicht am Kabel (User-Vorgabe): „Patchfeld 1–10 ist durchnummeriert und komplett gepatcht, die Nummerierung wird nicht wegen einer Config geändert."** Richtig so — die Portnummer ist physische Infrastruktur. Also `ether4` sauber auf **untagged VLAN40** gezogen statt das Kabel zu verschieben.
|
||
- **Ausgeführt via Nautobot-GC-ConfigPlan** (`plan_type=manual`, 6 Zeilen, change_control_id `TP21.1-4 …`), nicht per Direkt-Write — Governance gewahrt. Vorher `/system backup` = `core-pre-ether4-vlan40-20260813.backup` (Regel 3). `ether4` aus den Tagged-Listen von VLAN 10/20/30/40/50/90 entfernt + als untagged-Member zu VLAN40 ergänzt. **`pvid=40` stand bereits** — das war nie das Fehlende. **Verifiziert:** `vlan40 untagged=ether2,ether3,ether4,ether5`, `tagged=ether1,ether8,ether15`; vlan99 (Mgmt) und vlan100 (WAN) unangetastet. Damit ist auch der Flood-Leak aus IoT/INFRA/MAIN zum Wohnzimmer-Switch weg.
|
||
- ✅ **End-to-End-Beweis ERBRACHT (2026-08-14, live via MikroMCP auf `crs326-core`)** — der TV war am 08-13 tatsächlich nur im Standby. Alle vier Kriterien grün: `ping 10.40.40.11` = **5/5, 0 % Loss** (avg 563 µs); ARP `complete=true`/`status=delay` auf `vlan40` (vorher `failed`); `/interface/bridge/host` lernt `70:AF:24:B8:C9:86` auf **`ether4`, VID 40**; `ether4` `rx-unicast=6.909` / 3,0 MB RX (am 08-13 noch 1.338 Pakete / 452 KB → der Downstream lebt jetzt). DHCP-Lease `tv` weiterhin bound auf `dhcp-v40`. **Damit ist TP21.1 Punkt 4 vollständig abgeschlossen** und die Diagnose „tagged Egress auf einem untagged Port" ist end-to-end bestätigt (SSoT-Merkregel: `ref_tagged_egress_oneway_port`).
|
||
- 🔴 **INCIDENT + Lehre (2026-08-13): Der erste Deploy lief gegen das FALSCHE GERÄT (ap1 statt core).** Ich hatte 4 Device-UUIDs mit einer Sammelabfrage geholt und die **Reihenfolge angenommen**; die Nautobot-REST-API sortiert aber **alphabetisch** → `ap1, ap2, crs326-branch, crs326-core`. Der ConfigPlan trug damit ap1.
|
||
- **Schaden: keiner.** RouterOS wies jedes `set` ab (`invalid value for argument interface`), weil `ether8/13/15` auf einem 5-Port-hAP nicht existieren; die Ablehnung ist **pro Kommando atomar** → kein Teilzustand. ap1 nachgeprüft: VLAN-Tabelle vollständig, 25 WLAN-Clients, Mgmt `.99.11`. **Das war Glück, kein Können** — bei einem auf beiden Geräten *gültigen* Kommando (z.B. `tagged=ether1`) hätte es ap1s VLAN-Tabelle zerlegt.
|
||
- **Regel daraus: Device-UUIDs IMMER einzeln per Name auflösen, nie aus einer Sammelabfrage positional zuordnen** — und vor dem Deploy `plan.device.display` gegen den Zielnamen assert'en (im Skript jetzt so gemacht).
|
||
- **Bestätigt zum zweiten Mal:** der Deploy-**Job** meldete `SUCCESS` und der **Plan** `Completed`, obwohl auf dem Gerät nichts ankam. **Weder Job- noch Plan-Status sind ein Wirksamkeitsnachweis — nur die Gegenprüfung am Gerät zählt.** Der Fehl-Plan wurde gelöscht (irreführender Datensatz).
|
||
- ✅ **Lücke geschlossen (2026-08-13, User: „compliance rules! die Änderung machen wir"):** `/interface bridge port` + `/interface bridge vlan` sind jetzt für **alle drei Geräteklassen** im Template und als ComplianceFeatures scharf — s. TP22.
|
||
5. **`ap1`/`ap2` Neuprovisionierung** (WLAN-Rebuild, eigene Session) — ap1 ist Werksreset; danach greifen die `.99.11`/`.99.12`-Registry-Einträge.
|
||
|
||
### TP22 — Device-Adoption + Golden-Config Compliance-Push (RouterOS-Fleet) ▸ ✅ **DURCH (2026-08-13)**, Compliance-Backlog **abgearbeitet 2026-08-16 → 68/68, 0 Drifts** — alle 5 Schritte erledigt (Schritt 4 per Entscheid „keine Secret-Injection"); aus TP21 ausgelagert 2026-08-08
|
||
- **Ziel:** die 4 Live-Geräte (crs326-core, crs326-branch, ap1, ap2) real unter **Nautobot Golden Config** nehmen — Backup → Compliance/Drift → intended → **Push (`enable_deploy`)**. Damit greift der Governance-Entscheid „Config exklusiv über Nautobot" operativ. Macht die aktuellen `routeros/.secrets/*.rsc`-Handoffs mittelfristig überflüssig.
|
||
- **Stand aus TP21:** Plattform + Datenmodell + Git-Template + intended-config für core stehen; ap1/ap2 als reine APs zurückgeschrieben (`nautobot/ingest-ap-rebuild.py`, 2026-08-08). `enable_plan`/`enable_deploy` in `nautobot_config.py` noch **bewusst aus** (pull/read-only).
|
||
- ✅ **Schritt 0 DURCH (2026-08-13) — Backup-Scrubbing + Repo-Neuanlage.** Vorgezogen aus Schritt 4, weil ohne Scrubbing jedes weitere Backup Secrets geleakt hätte.
|
||
- 🔴 **Root-Cause-Fund:** Es gab **keine** ConfigReplace/ConfigRemove-Regeln → der Backup-Job vom 2026-07-22 hatte den ap1-`/export` ungefiltert nach Gitea geschrieben. `backups/ap1.cfg` enthielt im Klartext den **damals wie heute live genutzten WG-Hub-private-key** (bei der Core-Recovery unverändert auf `crs326-core` übernommen, damit FM/DW-Spokes matchen) **und 6 WLAN-PSKs**.
|
||
- ✅ **5 ConfigReplace-Regeln** (Platform RouterOS) via `nautobot/ingest-gc-scrubbing.py` (Dry-Run-Default, Regex-Selbsttest bei jedem Lauf): `10-wifi-passphrase`, `20-wireguard-private-key`, `30-preshared-key`, `40-password`, `50-secret` → Maske **`"<<REDACTED>>"`**. Gegen den echten Export kalibriert: RouterOS quotet nur bei Bedarf (4 von 6 PSKs standen **unquotiert**), deshalb Alternation `("(?:[^"\\]|\\.)*"|\S+)` mit der **quotierten Variante zuerst** (`\S+` ist greedy und würde bei einem PSK mit Leerzeichen den Rest exponieren). Replace normalisiert immer auf die quotierte Form → Maske ist formunabhängig byte-identisch (Voraussetzung für das Template in Schritt 1). Negativtest: `public-key=` wird **nicht** maskiert (sonst bräche der WG-Peer-Block).
|
||
- 🐞 **Blocker nebenbei gefunden + gefixt: Nautobot hatte das ALTE Router-Passwort.** Der erste Backup-Lauf meldete Job-`SUCCESS`, schrieb aber nichts — `backup_last_attempt_date` sprang, `backup_last_success_date` nicht (**GC meldet Job-Erfolg auch bei Geräte-Fehlern; nur das Success-Datum je Gerät zählt**). Ursache: `NAUTOBOT_ROUTEROS_PASSWORD` im Stack war 12 Zeichen aus der Zeit vor der PW-Vereinheitlichung (2026-08-08, 32 Zeichen, identisch auf allen 4 MikroTik). Fix = Stack-Env nachgezogen + Stack 203 redeployed; Datei zusätzlich auf `chmod 600` (Backup `.bak-20260813`).
|
||
- ✅ **Gitea-Repo `admin/bf-golden-config` gelöscht + neu angelegt** (User-Entscheid: Repo neu, **nicht** rotieren — History-Rewrite verworfen, weil Gitea unerreichbare Blobs bis zum server-seitigen `gc` behält). Struktur + Template + README wiederhergestellt. **Vollscan aller Blobs der neuen History: 0 unmaskierte Secrets** (die 6 Regex-Treffer sind 5× README-Doku der Feldnamen + 1× der Template-Platzhalter). Nautobot-GitRepository re-synct, End-to-End-Backup ins frische Repo verifiziert (112 Z., 6/6 PSKs maskiert).
|
||
- 📌 **Risiko-Akzeptanz (User 2026-08-13): keine Rotation.** Faktenlage: Repo `private=true`, anonymer Zugriff 404. Aber Gitea hängt auf CF-`bypass` am Internet und `ha-xstate` ist ein **Service-Account mit Gitea-Admin** (kann jedes private Repo lesen) → Lesbarkeit für 2 Accounts, nicht fürs Internet. **Trigger für nachträgliche Rotation:** ändert sich die Gitea-Exposition oder der `ha-xstate`-Account → WG-Key rotieren (FM/DW-Klickanleitung `routeros/fritzbox-wg-lanlan-klickanleitung.md`).
|
||
- ⚠️ **DR-Konsequenz:** ein maskiertes Backup ist **kein Wiederherstellungs-Artefakt**. Restore hängt weiter an `~/.secrets/`, `routeros/.secrets/*` und `routeros/ap1-wg-hub.privkey` (alle gitignored).
|
||
- ✅ **Schritt 1 DURCH (2026-08-13) — AP-Zweig im Golden-Config-Template.**
|
||
- **Datenmodell = ConfigContext** (`nautobot/ingest-ap-configcontext.py`). Verworfen: Wireless-`RadioProfile` (haengt über `ControllerManagedDeviceGroup` an einem *Controller* — den gibt es seit der CAPsMAN-Abschaffung bewusst nicht mehr; ein Fake-Controller wäre Modellschuld), CustomFields (skalieren nicht), Ableitung aus VAP-Descriptions (SSID nur als Freitext → stille Brüche). Angelegt: ConfigContext **`ap-common`** (Scope Role *Wireless AP* + Platform RouterOS, weight 1000) mit `zones`/`radios`/Site-Konstanten + **`local_config_context_data`** je AP mit nur den 2 Kanalnummern. **Frequenz wird im Template gerechnet** (`5000+5*ch` / `2407+5*ch`) statt gespeichert.
|
||
- **Cross-Check im Skript:** die `zones`-Tabelle wird gegen die 11 real modellierten VAP-Interfaces (Name-Präfix + `untagged_vlan`) validiert, Divergenz = Abbruch → ConfigContext und DCIM können nicht auseinanderlaufen.
|
||
- **Template:** neuer Zweig `{% elif obj.role.name == "Wireless AP" %}` (rollen-, nicht namensbasiert). Scope bewusst **nur die compliance-verwalteten Sektionen** (channel/datapath/security/configuration/bridge-vlan/vlan99/ip-address/route) — **nicht** die ganze Config: defconf-Boilerplate (ipv4/ipv6-Firewall, `/disk`, `/tool mac-server`) und die VAP-Zeilen bleiben draussen, weil deren MACs gerätevergeben und in Nautobot nicht modelliert sind. Die früheren „Ausnahmen" fallen aus den Daten heraus: IOT hat `bands:["2g"]` → landet automatisch nur auf `wifi2`; VLAN1/VLAN99 stehen als literale Zeilen ausserhalb der Schleife (**VLAN99 auf `bridge`, NICHT auf die Radios** — sonst Mgmt over-the-air).
|
||
- 🔑 **Formatregel gelernt: gegen den echten `/export` schreiben, nicht gegen die `.rsc`.** RouterOS sortiert Attribute **alphabetisch** und schreibt `ft-over-ds` nur bei `ft=yes`; die handgesetzte `.rsc` hat abweichendes Padding/Reihenfolge. Referenz-Export: `routeros/state-backups/ap1-gc-backup-scrubbed-20260813.cfg`. **RouterOS exportiert CRLF**, Jinja rendert LF — GC normalisiert das korrekt (die schon vorher grüne `system-identity`-Compliance war der Beleg).
|
||
- ✅ **Abnahme:** ap1 **Intended == Geräte-Ist, 0 Drift** (33 Zeilen, zeilenweise identisch); ap2 unterscheidet sich in **exakt den 4 erwarteten Werten** (identity, 5180↔5745, 2412↔2462, `.99.11`↔`.99.12`).
|
||
- ✅ **Mitgenommen:** WG-Privkey-Platzhalter im core-Zweig auf dieselbe Maske `"<<REDACTED>>"` vereinheitlicht (sonst Dauer-Diff, sobald eine Feature auf `/interface wireguard` liegt); **DNS-Statics korrigiert** (s. Nummernplan unten). `routeros/push-gc-template.py` gehärtet: **Pre-Push-Secret-Guard** (verweigert den PUT bei unmaskierten Werten), `--dry-run` mit Diff, `-m` statt hartkodierter Commit-Message, `sha` optional (sonst 404 nach Repo-Neuanlage).
|
||
- ✅ **Schritt 2 DURCH (2026-08-13) — Adoption + Backup/Compliance grün, 20/20.**
|
||
- SecretsGroup **„RouterOS Nornir"** an `crs326-core` + `crs326-branch` gehängt (ap1/ap2 hatten sie schon) — einheitliches Admin-PW seit 2026-08-08 macht eine Gruppe für alle 4 ausreichend.
|
||
- **Datenmodell-Korrekturen vorgezogen (technisch Voraussetzung):** `crs326-core` Status *Planned* → **Active** (ist der produktive L3-Router), `crs326-branch` `primary_ip4` `.99.13` → **`.99.2`** (live verifiziert).
|
||
- ✅ **Backup über alle 4 erfolgreich**, Sichtprüfung: **0 unmaskierte Secrets** (ap1/ap2 je 6 PSKs maskiert, core WG-Privkey maskiert, branch secret-frei).
|
||
- ✅ **4 neue ComplianceFeatures** (`wifi-channel`, `wifi-datapath`, `wifi-security`, `wifi-configuration`, alle `config_ordered=false`) + die bestehende `system-identity` → **20/20 compliant** über alle 4 Geräte.
|
||
- ⚠️ **Bewusst noch KEINE Features für `bridge-vlan`/`ip-address`/`ip-route`:** ComplianceRules gelten pro *Platform*, nicht pro Rolle — und der **`crs326-core`-Zweig ist in Slash-Form** geschrieben (`/ip/address add …`), was den Export (Space-Form, `/ip address add …`) **nicht** matcht → das gäbe permanenten Falsch-Drift auf dem Core. **Follow-up: core-Zweig auf Export-Form umstellen**, dann diese Features nachziehen. Die wifi-Features sind unkritisch, weil core/branch keine WLAN-Hardware haben (beide Seiten leer = compliant).
|
||
- ✅ **Follow-up DURCH (2026-08-13) — `crs326-core`-Zweig auf `/export`-Form.** Der Zweig war als *staged Cutover-Skript* geschrieben (Slash-Form `/ip/address`, plus `disabled=yes`-Flags aus der Vorbereitungszeit) und matchte den Export nicht → er hätte platform-weite ComplianceRules dauerhaft rot gefärbt. Jetzt Space-Form + alphabetische Attribute, `disabled=yes` entfernt (core ist seit 2026-08-08 produktiv), VLAN-Tabelle als Jinja-Konstante, GW-IPs weiter datengetrieben. **Ergebnis: 68 von 69 Zeilen byte-identisch zum Gerät.** Zusätzlich **Switch-Zweig** für `crs326-branch` (Mgmt-Layer) ergänzt — vorher fiel branch auf „nur `/system identity`" durch und meldete legitime Config als Drift. **9 weitere ComplianceFeatures** (interface-list/-vlan/-wireguard, ip-address/-pool/-dhcp-server/-dns/-firewall-nat/-route); bei `ip-dhcp-server` bewusst **drei spezifische Präfixe** statt `/ip dhcp-server`, sonst fingen die 54 dynamischen `lease`-Zeilen mit.
|
||
- ✅ **Schritt 3 DURCH (2026-08-13) — Deploy-Pipeline scharf, Pilot erfolgreich.**
|
||
- Image **`3.1.7-gc9`** auf der NAS gebaut (`/volume1/docker/nautobot-image`), Stack 203 retaggt. ⚠️ **Falle:** ein bereits vorhandenes `gc7` trug dieselben Flags; ein Build ohne geänderte Quelldatei zieht den **Docker-Cache** und liefert eine identische Image-ID — immer gegen die Flags im *fertigen* Image verifizieren. `scp` auf die NAS schlug fehl („Connection closed"), Übertragung per `ssh 'cat > datei'`.
|
||
- **Jobs sind in Nautobot zusätzlich einzeln freizuschalten** (`enabled=true`): die Plugin-Flags machen sie nur verfügbar.
|
||
- 🔴 **Kernbefund: `napalm-ros` ist ein READ-ONLY-Treiber.** Der Default-Dispatcher wählt NAPALM (weil `Platform.network_driver_mappings` `napalm: ros` enthält) → Backup (`get_config`) geht, **`merge_config` scheitert grundsätzlich**, mit leerer Fehlermeldung (`E1015 … ``). **Fix:** in den Golden-Config-Settings (nicht in den Nornir-Settings!) `custom_dispatcher: {"mikrotik_routeros": "nornir_nautobot.plugins.tasks.dispatcher.mikrotik_routeros.NetmikoMikrotikRouteros"}` — dieser Dispatcher pusht via `netmiko_send_config`. Danach lief der Deploy sofort.
|
||
- ⚠️ **Gescheiterter Deploy = sauberer Fehlschlag:** das Gerät blieb beim NAPALM-Versuch vollständig unverändert (kein Teilzustand). Zusätzlich meldet der Deploy-**Job** `SUCCESS`, obwohl der **Plan** auf `Failed` steht — wie beim Backup gilt: **nur der Objekt-Status zählt, nicht der Job-Status.**
|
||
- ✅ **Pilot-Deploy: die DNS-Statics auf dem Core.** Vorher `/system backup` (`core-pre-tp22-first-deploy-20260813.backup`). ⚠️ **`config_set` eines generierten Plans ist schreibgeschützt**, und `plan_type=missing` erzeugt **nur `add`** — das hätte Duplikate ergeben (`ap1.bf.lan` gleichzeitig auf `.99.3` und `.99.11`). Deshalb **manueller Plan mit Purge-vor-Add**. Ergebnis verifiziert: `ap1→.99.11`, `ap2→.99.12`, `branch→.99.2`, weiterhin 11 Einträge, keine Duplikate. **Compliance 51/56.**
|
||
- ✅ **Schritt 5 DURCH (2026-08-13) — Datenmodell-Nachträge, `nautobot/ingest-tp22-datamodell.py`.** Quelle war durchgehend **das Gerät**, nicht die Doku: `bridge/port` (pvid), `bridge/vlan` (tagged/untagged), `bridge/host` (gelernte MACs je Port+VID) plus ARP/DHCP-Leases zur Identifikation der Gegenstellen.
|
||
- **`crs326-core`: von 5 auf 26 Ports.** Vorher waren 3 davon als „GEPLANT (tentativ)" modelliert und `ether1` zeigte auf das tote `sw1 #12`. Belegt (MAC-hart): `ether8`→crs326-branch, `ether13`→pve `.20.100`, `ether14`→Sonoff `.30.250`, `ether15`→ap1, `ether16`→Arris/WAN, `ether5`/`ether6`→Sonos Schlafzimmer `.195`/`.193`. Die Trunk-Sets sind **exakt wie am Gerät** übernommen, inkl. Schiefstände (z.B. trägt `ether1` kein VLAN20/99) — bewusst nicht geradegezogen.
|
||
- **`crs326-branch`:** `ether1`-Ziel `sw1 #8` → `crs326-core ether8`; `ether5`/`ether6` = Sonos Arbeitszimmer (aktuell kein Link, die Schlafzimmer-Paare hängen am Core); `ether9–23`+sfp waren als „disabled" modelliert, sind live aber **enabled** (Bootstrap Rev4) → korrigiert.
|
||
- **Standort-Fehler gefunden:** `crs326-branch` **und** `ap2` standen in Nautobot auf *Technik UG*, real *Technik OG* (die Doku war richtig, das Modell falsch) → korrigiert.
|
||
- **Status-Endzustände:** sw1/sw2/cudy2 → **Decommissioned** (physisch ausgebaut; „Decommissioning" heißt *Prozess läuft*). Nautobot liefert diesen Status mit, aber nur für `circuits.circuit` → `content_types` um `dcim.device` erweitert statt einen zweiten gleichnamigen anzulegen. `cudy1` → **Offline** (core `ether11` hat kein Link; der endgültige Teardown bleibt TP19). sw1s 4 Duplikat-Ports (`gi8/gi11/gi15/gi16` neben `GE*`) entfernt.
|
||
- ✅ **Compliance-neutral verifiziert:** Generate-Intended + Compliance über alle 4 Geräte neu gelaufen → weiterhin **51/56** mit exakt denselben 5 bekannten Drifts. Grund: der core-Zweig des Templates iteriert nur Interfaces mit Präfix `vlan` und hält die Bridge-VLAN-Tabelle als Jinja-Konstante. **Umkehrschluss als Dauerregel: die `vlanXX`-Descriptions auf dem Core sind NICHT kosmetisch** — sie landen als `comment=` in der intended config.
|
||
- 🔍 **Nebenbefund, halbkonfigurierte Ports (NICHT angefasst, gehört zu TP19/TP5):** `core ether11` (cudy1) hat `pvid=10` ohne VLAN10-Membership → funktionslos; `core ether3` hat `pvid=1` bei untagged-VLAN40-Membership; `core ether2` ist gleichzeitig statisches untagged-Member von VLAN1 **und** VLAN40; `branch ether9–23` tragen `pvid=20` ohne jede Membership. Alles Bring-up-Reste, betriebsneutral (kein Link), aber sie gehören in die VLAN1-Aufräumrunde.
|
||
- ✅ **Nachtrag 2026-08-13 — Compliance-Abdeckung erweitert auf 68 Checks (63/68 grün; seit 2026-08-16 **68/68**).** Drei neue ComplianceFeatures, alle auf Anhieb grün:
|
||
- **`wifi-steering`** (`/interface wifi steering`) — sichert die TP3.3-Reparatur ab.
|
||
- **`bridge-port`** + **`bridge-vlan`** (`/interface bridge port` / `/interface bridge vlan`) — der **L2-Layer war bis dahin komplett unüberwacht**: der core-Zweig emittierte gar keine Bridge-Sektion, der AP-Zweig nur die VLAN-Tabelle ohne Ports. Jetzt für alle drei Geräteklassen im Template.
|
||
- 🔑 **Bewusst als Literal-Block, nicht aus DCIM abgeleitet.** Der As-built trägt akzeptierte Schiefstände (`core ether3` ist untagged-Member von VLAN40, hat aber `pvid=1`; `core ether2` hängt zusätzlich in VLAN1; `branch ether9–23` haben `pvid=20` ohne Membership). Würde man `pvid` aus `untagged_vlan` generieren, meldete die Compliance genau diese bekannten Altlasten als Dauerdrift. Der Literal-Block liefert das, was hier gebraucht wird: **Drift-Erkennung gegen den Ist-Zustand**.
|
||
- ⚠️ **`/interface bridge` selbst bleibt außen vor** — trägt die gerätespezifische `admin-mac`, wäre pro Gerät verschieden und ist kein Fleet-Standard.
|
||
- 🐞 **Falle dabei: Compliance vergleicht gegen das letzte BACKUP, nicht gegen das Live-Gerät.** Nach dem Steering-Deploy meldete sie erst Drift auf `wifi-configuration`/`wifi-steering`, weil das Backup vom Nachmittag stammte. **Reihenfolge nach jeder Geräteänderung: Backup → Intended → Compliance.**
|
||
- ✅ **Compliance-Backlog ABGEARBEITET (2026-08-16, User-Auftrag „beseitige autonom alle Compliance-Drifts") — Ergebnis: 68/68, 0 Drifts.**
|
||
- **Was entfernt wurde (alle vom Typ `extra`, also am Gerät vorhanden und in der intended config bewusst nicht vorgesehen):** ap1+ap2 `/ip dns static 192.168.88.1 router.lan` (Werks-`defconf`, zeigte auf eine IP, die es im Netz nicht gibt — der Core hat sein eigenes, korrektes `router.lan → 10.40.99.1`); `crs326-branch` `vlan10 "TEMP Mgmt VLAN10"` + `10.40.10.2` (Bring-up-Interim). Der fünfte Drift, `crs326-core` `10.40.41.211`, war schon vorher über den ConfigPlan `TP19-vlan1-core-address` gefallen.
|
||
- **Richtung der Beseitigung bewusst „am Gerät entfernen", nicht „ins Template aufnehmen"** — das entspricht der Absicht, die im Switch-Zweig von `mikrotik_routeros.j2` seit 2026-08-13 schriftlich steht („Bewusst NICHT emittiert … gehoeren entfernt"). Die frühere Zurückhaltung („potenzielle Rettungspfade") ist mit dem User-Entscheid vom 2026-08-16 aufgehoben; der Mgmt-Fallback aus VLAN10 entfällt damit, Rückweg im Notfall = MAC-Winbox am selben Draht.
|
||
- **Weg: 3 manuelle GC-ConfigPlans** (`TP22-drift-aps-defconf-dns`, `TP22-drift-branch-temp-vlan10`), Governance gewahrt — kein Direkt-Write. Vorher `/system backup` je Gerät (`{ap1,ap2,branch}-pre-drift-cleanup-20260816.backup`). Deploy **gestaffelt**: erst die beiden APs, am Gerät gegengeprüft, dann branch.
|
||
- 🔑 **Neue Falle gelernt: `POST /plugins/golden-config/config-plan/` ist `405 Method Not Allowed`** — das ViewSet ist read-only. ConfigPlans entstehen **ausschließlich** über den Job **`Generate Config Plans`** (bei `plan_type=manual` landet der `commands`-TextVar als `config_set` auf jedem ausgewählten Gerät). Das erklärt, warum es bis dahin kein Skript gab und alle 17 Vorgänger-Pläne per Hand entstanden sind.
|
||
- ✅ **Verifikation am Gerät, nicht am Job:** ap1/ap2 `list_dns_entries` → `total: 0` bei unveränderten 28 bzw. 3 WLAN-Clients; branch `/interface vlan` → nur `vlan99`, `/ip address` → nur `10.40.99.2/24`, `ping` vom Core 4/4 mit 0 % Loss. **`/interface bridge vlan/export` byte-identisch** zu vorher — die Gegenprobe darauf, dass kein neuer Drift entsteht (`bridge` steht dort statisch als tagged-Member von VLAN10, unabhängig vom SVI). Danach `Backup → Intended → Compliance`, alle 4 Geräte mit frischem `*_last_success_date`.
|
||
- 🛠️ **Tooling neu: `nautobot/gc-configplan.py`** — legt manuelle Pläne über den Job an, löst Device-UUIDs **einzeln per Name** auf und assertet `plan.device.display` **und** `config_set` gegen das Ziel (die alphabetische Sortier-Falle aus TP21.1 kann damit nicht wiederkommen), verweigert jedes `config_set` mit `<<REDACTED>>` (Regel 1) und jede `print`-Zeile, kann gestaffelt deployen (`--deploy-ids`) und kapselt die Reihenfolge `Backup → Intended → Compliance` als `--refresh-compliance`. Dry-Run ist Default.
|
||
- 🔒 **GOVERNANCE — verbindliche Deploy-Regeln (festgeschrieben 2026-08-13, VOR dem Scharfschalten von `enable_deploy`):**
|
||
1. **Config Plans werden ausschliesslich feature-/manual-scoped erzeugt, NIEMALS als „full intended".** Ein Voll-Push schriebe wörtlich `passphrase="<<REDACTED>>"` auf die APs (= alle WLAN-Clients raus, inkl. ~26 Shellys) bzw. `private-key="<<REDACTED>>"` auf den Core (= WG-Hub tot, FM/DW-Spokes weg). **Jede Sektion, die `<<REDACTED>>` enthält (`/interface wifi security`, `/interface wireguard`), ist vom Push generell ausgeschlossen.**
|
||
2. **Das AP-Template wird NIE zeilenweise auf ein laufendes Gerät gepusht.** Die Provisionierung setzt zwischenzeitlich `vlan-filtering=no` → das reisst den vlan99-Mgmt-Pfad ab, die restlichen Zeilen kämen über dieselbe SSH-Session nie an (halb konfigurierter AP). Voll-Reprovisionierung ausschliesslich per Datei-Upload + `/import` (`routeros/.secrets/ap{1,2}-prov-base.rsc`). Verschärfend: `device-mode=home` blockt auf den hAPs `scheduler`/`fetch` → die übliche Auto-Revert-Absicherung steht dort **nicht** zur Verfügung; der VLAN1-untagged-Rettungspfad darf nie wegoptimiert werden.
|
||
3. **Vor jedem Push ein `/system backup` auf dem Zielgerät.** Das GC-Backup ist wegen des Scrubbings **kein** vollwertiges Restore-Artefakt.
|
||
- ✅ **Schritt 4 ENTSCHIEDEN (User 2026-08-13): Variante (a) — keine Secret-Injection, bleibt wie es ist.** Ursprünglich geplant war „WLAN-PSKs + WG-Privkey via Nornir-Secrets injizieren"; die **Governance-Regel 1** (unten) hat das überholt: Sektionen mit `<<REDACTED>>` sind vom Push generell ausgeschlossen, die Secrets werden also nie gebraucht. **Konsequenz, bewusst akzeptiert:** Secrets bleiben dauerhaft außerhalb von Modell und Push, DR läuft weiter über `~/.secrets/` + `routeros/.secrets/*` + `routeros/ap1-wg-hub.privkey`; „Gerät vollständig aus dem Modell wiederherstellbar" gilt nur *ohne* Secrets. Die verworfene Alternative (b) hätte Regel 1 aufweichen müssen — ein Render-Fehler hätte dann WLAN bzw. WG-Hub abgeschossen. **Damit ist TP22 inhaltlich abgeschlossen.**
|
||
- **Schritte:** (1) **AP-GC-Template**: `mikrotik_routeros.j2` um `role == "Wireless AP"`-Zweig erweitern (Bridge/vlan-filtering/ether1-Trunk/vlan99-Mgmt/6 SSIDs **ohne** PSK/L3) → APs komplett aus GC generierbar; (2) **Nornir/NAPALM-Adoption** aller 4 (SecretsGroup „RouterOS Nornir"; **einheitliches Admin-PW seit 2026-08-08 vereinfacht das**), Backup/Compliance-Job grün; (3) **`enable_plan`+`enable_deploy`** scharf — erst Dry-Run/Plan, dann kontrollierter Push; (4) **Secret-Handling** WG-Privkey (core) + WLAN-PSKs (bleiben aus dem Git-Template, via Nornir-Secrets injizieren); (5) Datenmodell-Nachträge: branch/core-Ports final, sw1 (außer Betrieb) + cudy1-Status.
|
||
- **Nutzen:** Drift-Erkennung + reproduzierbarer Rebuild jedes Geräts aus dem Modell.
|
||
- **Abh.:** TP21 ✅ (Plattform/Modell/Templates), TP20 ✅, einheitliches Admin-PW ✅. **Danach ist der kritische Pfad frei für TP5 (Deny-by-default) → TP6 (CAKE).**
|
||
|
||
### TP23 — DNS-Policy & Self-Service-Ausnahmen ▸ 📋 KONZEPT ENTSCHIEDEN (2026-08-14), Umsetzung offen
|
||
- **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: Best-Practice-Audit statt Bauchgefühl ▸ ⏳ **SCHRITTE 1–3 DURCH (2026-08-17): beide APs 18 dBm, 20 MHz auf 2,4, überlappungsfrei** — offen: Signal-Boden + Re-Walk — Sammel-TP für Christophs Beobachtungen 1–6
|
||
> **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), gehören also zusammen. **TP25 übernimmt den offenen Rest von TP3.3** (Re-Walk, Dead-Spot-Kartierung)
|
||
> — dieselbe physische Arbeit, doppelt geführt wäre Unsinn. TP3.2/TP3.3 bleiben als Historie stehen.
|
||
> **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.
|
||
|
||
- ⚠️ **Ausgangslage: Drift ist bestätigt, aber NICHT die Ursache.** Christoph hat am 08-16/17 selbst an den APs
|
||
gespielt („drift ist garantiert. es hat vorher aber auch nicht funktioniert"). Der Audit unten ist gegen den
|
||
**Ist-Stand** gefahren (`/interface/wifi/export` + `/interface/wifi/monitor` + Log, beide APs, 2026-08-17 14:01).
|
||
Zwei der Funde sind älter als die Experimente und stammen aus der TP3-Neuprovisionierung.
|
||
|
||
#### 🔴 Fund A — 2,4 GHz läuft auf 40 MHz, obwohl das Profil 20 MHz sagt (Beobachtung 4)
|
||
- **Christophs Frage war berechtigt, aber der Adressat ist ein Override, keine Entscheidung.** Das Channel-Profil
|
||
ist korrekt: `add band=2ghz-ax frequency=2412 name=ch-2g width=20mhz`. **Überschrieben wird es inline am Radio:**
|
||
`set [find default-name=wifi2] channel.band=2ghz-ax .skip-dfs-channels=10min-cac .width=20/40mhz`
|
||
→ **das Inline-Override gewinnt gegen das verlinkte Profil.** `monitor` beweist es: ap1 `2412/ax/Ce`,
|
||
ap2 `2462/ax/eC` — `Ce`/`eC` = 40 MHz. **Niemand hat 20/40 „gewählt"**; es ist genau die Override-Klasse, die
|
||
CLAUDE.md für den TP3-Bring-up schon dokumentiert („Werks-Inline-Overrides auf wifi1/wifi2 überschreiben das
|
||
verlinkte Profil") — damals nur für `configuration.ssid`/`security.*` bereinigt, für `channel.*` **nie**.
|
||
- **Warum 40 MHz auf 2,4 GHz falsch ist (Manual-Ebene, nicht Geschmack):** es gibt nur 3 überlappungsfreie
|
||
20-MHz-Kanäle. ap1 belegt mit `2412/Ce` ≈ 2402–2442, ap2 mit `2462/eC` ≈ 2442–2482 → **die beiden APs decken
|
||
zusammen praktisch das ganze Band ab.** Jeder Nachbar-AP überlappt zwangsläufig einen von beiden. Dazu halbiert
|
||
40 MHz die spektrale Leistungsdichte → **~3 dB weniger Reichweite bei gleicher Sendeleistung.** Und der Nutzen
|
||
ist null: IoT-Clients sind fast alle 20-MHz-only. **Das ist die „miserable Reichweite" aus Beobachtung 4.**
|
||
- **Fix:** die Inline-`channel.*`-Overrides auf `wifi1`/`wifi2` **leeren** (`!channel`), damit die Profile greifen.
|
||
Nebenbefund: `skip-dfs-channels=10min-cac` auf `wifi2` ist bedeutungslos — im 2,4-GHz-Band gibt es keine
|
||
DFS-Kanäle. Copy-Paste-Spur, harmlos, gehört trotzdem raus.
|
||
|
||
#### 🔴 Fund B — ap2 sendet auf 5 GHz mit 9 dBm statt 18 dBm (Beobachtungen 1+2)
|
||
- **Gemessen:** ap1 `wifi1` `tx-power: 18`, ap2 `wifi1` **`tx-power: 9`** — bei identischer Hardware und
|
||
identischem Profil. **9 dB Unterschied = Faktor ~8 in der Leistung**, ap2s 5-GHz-Zelle hat grob ein Drittel
|
||
des Radius von ap1.
|
||
- ✅ **BEHOBEN 2026-08-17: ap2s 5-GHz-Radio läuft jetzt mit 18 dBm** (`5220/ax/Ce/I`). Messreihe am Gerät:
|
||
| Zustand | Kanal | tx-power |
|
||
|---|---|---|
|
||
| ap2 vorher | `5745/ax/Ceee` (80 MHz, ohne `/I`) | **9** |
|
||
| ap2 nach Frequenzwechsel | `5220/ax/eeCe/I` (80 MHz, mit `/I`) | **9** ⬅️ unverändert! |
|
||
| ap2 nach Breitenkorrektur | `5220/ax/Ce/I` (40 MHz) | **18** ✅ |
|
||
| ap1 durchgehend | `5180/ax/Ceee/I` → `5180/ax/Ce/I` | 18 → 18 |
|
||
- 🔴 **Ehrliche Korrektur: meine erste Begründung war falsch, und die zweite auch nicht vollständig.**
|
||
Ich hatte die 9 dBm auf **ETSI-Band C** (ch149 ohne `/I`-Flag) zurückgeführt. **Widerlegt:** der Wechsel ins
|
||
Indoor-Band bei gleicher Breite ließ die Leistung auf 9 dBm. „80 MHz kostet generell Leistung" trägt auch
|
||
nicht — **ap1 fuhr 80 MHz im selben Band mit 18 dBm.** Der Fix ist gemessen, der Mechanismus ist es nicht.
|
||
- 🔬 **Kohärente Resthypothese (nicht bewiesen, aber testbar):** es sind **zwei** Effekte, je einer pro Kanal —
|
||
(a) `5745/Ceee` = ETSI-Band-C-Limit (die erste Theorie gilt für *diesen* Kanal weiter), und
|
||
(b) `5220/eeCe` = das Kontrollkanal liegt **nicht** am Blockanfang (`eeCe` statt `Ceee`), was das Radio
|
||
derated. Das würde ap1s `5180/Ceee`=18 und ap2s `5220/eeCe`=9 gleichzeitig erklären.
|
||
**Diskriminierender Test:** ap2 testweise auf `5180/Ceee` — 18 dBm ⇒ Hypothese (b) trägt; 9 dBm ⇒ es ist
|
||
gerätespezifisch (dann ist ap2s Radio der Verdächtige, relevant für die Hardware-Frage!). **Nicht nötig für
|
||
den Betrieb, aber vor einem Hardwarekauf wissenswert.**
|
||
- ⚠️ **Die TP3-Notiz „Kanäle non-DFS ap1 ch36/ch1, ap2 ch149/ch11" hatte trotzdem keinen tragenden Grund** —
|
||
s. eigener Absatz „Herkunft der ch149-Notiz" unten.
|
||
- 🎯 **Der Fix löst Fund B und C in einem Zug — und er ist nicht offensichtlich:** unter ETSI Austria existiert
|
||
im Indoor-Band (5180–5240) **nur ein einziger 80-MHz-Block** (`5180/Ceee` = ch36–48). Zwei APs können dort
|
||
also nicht beide 80 MHz fahren, ohne sich zu überlappen — **genau deshalb ist ap2 überhaupt auf 5745 gelandet.**
|
||
Mit **40 MHz** gehen beide sauber ins Indoor-Band:
|
||
| AP | neu | Kanäle | Leistung | Belegung |
|
||
|---|---|---|---|---|
|
||
| ap1 | `5180/Ce` | 36+40 | **18 dBm** | 5170–5210 |
|
||
| ap2 | `5220/Ce` | 44+48 | **18 dBm** | 5210–5250 |
|
||
Beide `/I`-freigegeben (aus der Radio-Tabelle bestätigt), überlappungsfrei, **+9 dB für ap2**.
|
||
|
||
#### 🔴 Fund C — 80 MHz auf 5 GHz kostet Reichweite, die hier fehlt (Beobachtung 1)
|
||
- `ch-5g width=20/40/80mhz`, laufend `5180/ax/Ceee` bzw. `5745/ax/Ceee` = **80 MHz**. Dieselbe Sendeleistung auf
|
||
die vierfache Bandbreite verteilt kostet **~6 dB** effektiven SNR am Zellenrand gegenüber 20 MHz, ~3 dB
|
||
gegenüber 40 MHz. In einer 2-AP-Wohnung mit Terrasse ist Spitzendurchsatz das falsche Optimierungsziel —
|
||
**Randabdeckung und Stabilität sind das richtige.**
|
||
- **Beleg, dass genau das das Terrassen-Symptom ist:** ap1-Log, Telefon steht still im Halter:
|
||
`-81` → roamt auf 2,4 GHz `-82` → zurück `-83` → **`disconnected, connection lost, signal strength -88`**.
|
||
**−88 dBm ist unter der Nutzbarkeitsschwelle.** Das ist **kein** Roaming-Problem (Christoph sagt selbst
|
||
„ich red da nicht mal von roaming"), sondern **Link-Budget** — und dagegen hilft Breite runter, nicht drehen.
|
||
|
||
#### 🔴 Fund D — `w2-iot` trägt einen unzulässigen Channel-Override auf einem Slave-VAP (Beobachtung 3)
|
||
- **ap1:** `add channel.band=2ghz-n .width=20mhz configuration=cfg-iot … master-interface=wifi2 name=w2-iot`
|
||
- **ap2:** `add channel.width=20mhz configuration=cfg-iot … master-interface=wifi2 name=w2-iot`
|
||
- **Ein Slave-VAP teilt das Radio des Masters und kann keinen eigenen Kanal haben.** Auf ap1 erzwingt das
|
||
Override zusätzlich `2ghz-n`, **während der Master `wifi2` auf `2ghz-ax` läuft** — ein Band-Mismatch zwischen
|
||
Master und Slave ist keine unterstützte Konfiguration. **Das ist der Mechanismus hinter „alle SSIDs sind da,
|
||
`-iot` beharrlich nicht, und plötzlich ist es wieder da":** der VAP fällt aus der Beacon-Rotation und kommt
|
||
bei einem Re-Apply zurück.
|
||
- 📌 **Und es ist der Beweis für Beobachtung 6:** die beiden APs sind hier **nicht identisch** (ap1 mit Band+Width,
|
||
ap2 nur Width). Eine generierte Config kann das nicht produzieren — das ist Handarbeit, und zwar auf genau dem
|
||
Objekt, das keine Handarbeit verträgt.
|
||
|
||
#### 🟠 Fund E — keine `access-list`, also kein Signal-Boden gegen klebende Clients (Beobachtung 2)
|
||
- **`/interface/wifi/access-list` ist auf beiden APs leer.** Damit gibt es **keinen `signal-range`-Boden** — ein
|
||
Client darf hängen bleiben, bis die Verbindung zusammenbricht, statt frühzeitig abgestoßen zu werden. Das ist
|
||
der Standard-RouterOS-Griff gegen genau dieses Symptom.
|
||
- **Beleg für das Kleben:** ap2-Log, Client `56:71:6C:22:E6:A9` flappt in 22 Minuten **sechsmal** zwischen
|
||
`wifi1`↔`wifi2` bei −62…−83 dBm. Und: `F2:62:4C:E1:AF:09@wifi2 disconnected, not responding, signal strength -47`
|
||
— **Abbruch bei ausgezeichneten −47 dBm.** Beides zusammen = Band-Oszillation ohne Steering-Politik, nicht
|
||
schlechte Abdeckung.
|
||
- ⚠️ **Nebenbefund:** die TP3.2-Access-List, die den P750W an ap1 pinnte („überlebt ap2-Re-Provision"), ist
|
||
**beim Rebuild 2026-08-08 verlorengegangen** — im Export beider APs steht keine einzige Access-List-Zeile.
|
||
Laut CLAUDE.md ist der Pin nicht mehr nötig (L3-GW liegt auf dem Core), der **Verlust war aber unbemerkt.**
|
||
- `ft=yes ft-over-ds=no` ist dagegen **korrekt** für Standalone-APs (over-DS bräuchte ein Inter-AP-Protokoll) —
|
||
kein Fund, nur zur Abgrenzung festgehalten.
|
||
|
||
#### 🟡 Fund F — IoT-Clients trennen exakt alle ~5:05 bei gutem Signal (offen, präzise vermessen)
|
||
```
|
||
12:55:29 connected -59 → 13:00:36 disconnected -59 (5:07)
|
||
13:17:27 connected -63 → 13:22:32 disconnected -63 (5:05)
|
||
13:35:32 connected -60 → 13:40:37 disconnected -59 (5:05)
|
||
13:57:31 connected -59 → 14:02:35 disconnected -58 (5:04)
|
||
```
|
||
- **−59 dBm ist ein gutes Signal. Eine auf 3 Sekunden reproduzierbare 5-Minuten-Periode ist ein Timer, kein Funk.**
|
||
- 🚫 **Ausdrücklich NICHT die alte Power-Save-Merkregel wiederbeleben** — die ist am 2026-08-13 als Fehldiagnose
|
||
zurückgezogen worden (`ref_wifi_powersave_multicast`, Drucker war schlicht aus). Dieser Befund ist ein *anderer*:
|
||
vier saubere Messpaare mit konstanter Periode.
|
||
- **Kandidaten + der Test, der sie trennt:** (a) periodischer VAP-Re-Apply durch Fund D → prüfen, ob ap2
|
||
(ohne Band-Override) dieselbe Periode zeigt; (b) DHCP-Lease/Renew-Interaktion → `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 nach Fund-D-Fix unverändert. **Erst nach dem Fund-D-Fix erneut messen** — sonst misst man zwei
|
||
Effekte übereinander.
|
||
|
||
#### 🧭 Beobachtung 5 — „alle Welt sagt CAPsMAN, nur wir sagen Nautobot GC. Hilfe oder Last?"
|
||
- **Klare Antwort: es sind keine Alternativen, sie lösen verschiedene Probleme.** CAPsMAN = *Runtime*-Control-Plane
|
||
fürs WLAN (ein Ort für Radio-Settings, sofortiger Push, dynamische VAPs). Nautobot GC = *Config-as-Code*-SoT
|
||
+ Drift-Erkennung über die **ganze** Flotte (Core, Branch, beide APs). Man kann beides haben; das Reibungspunkt
|
||
ist nur, dass CAPsMANs dynamische Objekte für GC unsichtbar sind (der Grund von 2026-07-22, und der gilt).
|
||
- 🔎 **Aber eine Begründung von damals hält der Prüfung nicht stand.** Der Entscheid nannte als ersten Grund
|
||
„WLAN dauerhaft instabil, besonders wenn beide APs laufen". **Das WLAN ist nach dem Standalone-Rebuild
|
||
weiterhin instabil** — die These „CAPsMAN war die Ursache" ist damit empirisch geschwächt. Die Funde A–E sind
|
||
Funkparameter; CAPsMAN hätte sie weder verursacht noch geheilt. **Der Rebuild hat ein Symptom umgezogen,
|
||
keine Ursache beseitigt.**
|
||
- **Wo GC hier tatsächlich Last war:** es hat diesen Drift **nicht verhindert.** Die Compliance deckt
|
||
`wifi-steering` ab (seit TP3.3), aber offensichtlich **nicht die Channel-/Inline-Override-Fläche** — sonst wären
|
||
Fund A und D als Drift aufgeschlagen. Das ist eine **Lücke im Feature-Set, kein Argument gegen GC.**
|
||
- **Ehrliches Urteil (meine Empfehlung):** GC als SoT **behalten** — es ist das Einzige, was Hand-Tuning davon
|
||
abhält, sich still zu akkumulieren, und genau das ist hier passiert. Aber: **GC ist kein WLAN-Tuning-Werkzeug.**
|
||
Der Ausweg ist nicht CAPsMAN, sondern die Parameter **einmal nach Manual richtig** zu setzen und dann mit einer
|
||
Compliance-Feature auf `/interface/wifi` **festzunageln**. Bei genau 2 APs ist der Kanal-/Leistungsplan eine
|
||
Einmalentscheidung, kein Laufzeitproblem — der Hauptvorteil von CAPsMAN greift hier also kaum.
|
||
*(Wenn ein dritter AP dazukäme, wäre die Abwägung neu zu führen.)*
|
||
|
||
#### 🔎 Herkunft der ch149-Notiz (Christophs Frage 2026-08-17: „wie kam es zu dieser Notiz?")
|
||
- **Nachverfolgt bis Commit `03f328f`, 2026-06-18, CAPsMAN-Ära.** Wortlaut der Commit-Message:
|
||
*„Kanal-Plan non-DFS/überlappungsfrei: ap1 ch36+ch1, ap2 ch149+ch11 (Auto-Channel hatte beide APs auf
|
||
5500-DFS/2437 gelegt = Co-Channel)"*.
|
||
- 🎯 **Das gelöste Problem war Co-Channel, nicht DFS.** Auto-Channel hatte beide APs auf **denselben** Kanal
|
||
gelegt; der Fix war, überhaupt zu pinnen. Dass die Wahl auf 36/149 fiel, ist das **FCC-Standardpaar** aus
|
||
jedem Tutorial — „non-DFS" wurde als Begründung *nachträglich* mitgeschrieben, war aber nie eine geprüfte
|
||
Anforderung. **Christophs Einschätzung ist damit belegt: es gibt keinen Grund, Frequenzbänder auszunehmen.**
|
||
- 📌 **Und ein Detail, das die Sache entschärft: `skip-dfs-channels=10min-cac` schließt DFS gar nicht aus.**
|
||
Es überspringt nur Kanäle, die die **10-Minuten**-CAC brauchen (Wetterradar-Band 5600–5650). Der Rest des
|
||
DFS-Bands bliebe nutzbar. Ausgeschlossen wurde DFS in Wahrheit durch das **harte `frequency=`-Pinning** —
|
||
wo nichts ausgewählt wird, wirkt kein Skip. (Die Overrides sind mit Schritt 2 ohnehin weg.)
|
||
- **Konsequenz für den Kanalplan:** das DFS-Band **5500–5700** ist eine echte Option und liegt bisher brach —
|
||
**11 zusätzliche Kanäle**, in ETSI ohne `/I`-Beschränkung. Preis: CAC-Wartezeit beim Start und im
|
||
Radar-Fall ein erzwungener Kanalwechsel (30 min Sperre). Bei Christophs aktuellem Symptombild
|
||
(Abbrüche) wäre ein radar-getriggerter Wechsel unangenehm — **deshalb jetzt nicht**, aber es ist der
|
||
Reservekanalraum, falls ein dritter AP dazukommt und 40 MHz nicht mehr reicht.
|
||
|
||
#### 📡 Beobachtung 4b — „könnte `2ghz-g` nicht besser zu IoT passen?"
|
||
- **Verfügbar auf diesem Radio** (`/interface/wifi/radio`): `2ghz-g:20mhz` · `2ghz-n:20mhz,20/40mhz` ·
|
||
`2ghz-ax:20mhz,20/40mhz`.
|
||
- ❌ **Für Reichweite bringt es nichts.** `band=` setzt die **höchste** angebotene Generation, nicht die
|
||
einzige — ein `2ghz-ax`-AP ist rückwärtskompatibel, g/n-Clients assoziieren normal. Und ein schwacher
|
||
Client fällt über die Ratenadaption von selbst auf die robusten niedrigen Raten. `band` ändert weder
|
||
Sendeleistung noch Empfängerempfindlichkeit.
|
||
- ✅ **Für Interoperabilität ist der Gedanke aber richtig.** Billige ESP-/Realtek-IoT-Stacks haben
|
||
dokumentierte Probleme mit 802.11ax-Beacons (HE-Capabilities, PMF). `2ghz-n` nimmt die HE-Elemente aus
|
||
dem Beacon und kann Assoziationswackler beheben — ein **Kompatibilitäts-**, kein Abdeckungsargument.
|
||
- 🎯 **Pointe: genau dieser Instinkt steckte schon im Fehler.** `channel.band=2ghz-n` auf `w2-iot` (Fund D)
|
||
war exakt der Versuch, IoT ein legacy-freundlicheres Band zu geben. **Die Absicht war richtig, der
|
||
Mechanismus falsch** — `band` ist eine Eigenschaft des **Radios**, nicht eines Slave-VAPs. Alle
|
||
2,4-GHz-SSIDs teilen `wifi2`.
|
||
- **Empfehlung, falls Fund F (5-Minuten-Takt) nach dem Override-Fix bleibt:** `wifi2` global auf **`2ghz-n`**
|
||
— die saubere Version dessen, was der Override wollte. Kostet real nichts (kein 2,4-GHz-Client hier braucht
|
||
ax-Raten, `dirtyvader-main` auf 2,4 GHz ist ohnehin Fallback). **`2ghz-g` NICHT als ersten Schritt:** die
|
||
20-MHz-Bindung ist richtig, aber 54 Mbit/s-Deckel und kein HT für *alle* 2,4-GHz-Clients ist ein echter
|
||
Verlust ohne Zusatznutzen gegenüber `n`. `g` ist die Eskalationsstufe, nicht der Einstieg.
|
||
|
||
#### 🏠 Deckenmontage-APs — bringen sie einen echten Vorteil? (Christophs Überlegung 2026-08-17)
|
||
- **Der Gewinn liegt in Platzierung und Antennendiagramm, nicht im Silizium.** Ein cAP ax ist dieselbe
|
||
Chip-Generation und ebenfalls 2×2 wie der hAP ax² — **mehr Rohleistung gibt es nicht.** Was er gibt:
|
||
ein nach unten optimiertes Diagramm, freie Sichtlinien von der Decke, PoE-Montage ohne Möbel davor.
|
||
- 🔴 **Aber die Entscheidung wäre heute blind gewesen.** Vor dieser Session lagen ~9 dB auf ap2 brach
|
||
(Fund B), 2,4 GHz verschenkte ~3 dB an 40 MHz (Fund A) und der 5-GHz-Zellenrand ~3 dB an 80 MHz (Fund C).
|
||
**Hardware zu kaufen, um Fehlkonfiguration zu kompensieren, ist der teuerste Weg.** Genau das deckt sich
|
||
mit Christophs eigener Randbedingung („nicht kaufen, bevor alles aus dem AP raus ist").
|
||
- ✅ **Jetzt ist der Boden gelegt** (beide APs 18 dBm, überlappungsfrei, 20 MHz auf 2,4). **Die Entscheidung
|
||
gehört an den Re-Walk (Schritt 5).** Bleiben danach Dead Spots — Terrasse, Kanten —, dann *ist* es ein
|
||
Platzierungsproblem, und Deckenmontage ist die richtige Antwort. Dann stellt sich aber zuerst die
|
||
billigere Frage: **reicht Umhängen der vorhandenen APs?** „Drehen hat nicht geholfen" passt zu einer
|
||
Abschattung, die Drehen nicht behebt — Versetzen schon.
|
||
- 📌 **Falls es auf drei APs hinausläuft, wird die CAPsMAN-Abwägung neu geführt** (s. Beobachtung 5): bei
|
||
3 APs ist koordinierte Kanal-/Leistungsverwaltung erstmals ein Laufzeit- und nicht mehr ein
|
||
Einmalproblem. Und der diskriminierende Test aus Fund B (ist ap2s Radio gerätespezifisch schwach?)
|
||
gehört **vor** einen Kauf.
|
||
|
||
#### 📋 Umsetzungsreihenfolge (alles via GC, gestaffelt, ap2 zuerst)
|
||
1. ✅ **Fund D DURCH (2026-08-17)** — `channel.*`-Overrides von `w2-iot` auf **beiden** APs entfernt.
|
||
`w2-iot` ist danach auf ap1 **und** ap2 `BR` (bound + running) → Beobachtung 3 strukturell erledigt.
|
||
Dateien: `routeros/tp25-schritt2-fix-overrides-ap2.rsc`, `routeros/tp25-schritt1-3-ap1.rsc`.
|
||
2. ✅ **Fund A DURCH (2026-08-17)** — Inline-`channel.*` auf `wifi1`/`wifi2` geleert. **2,4 GHz läuft jetzt
|
||
auf 20 MHz** (`2412/ax` bzw. `2462/ax`, kein `Ce`/`eC` mehr), tx-power 15 dBm. ap1 ch1 / ap2 ch11 =
|
||
überlappungsfrei mit Platz für ch6 in der Nachbarschaft.
|
||
3. ✅ **Fund B+C DURCH (2026-08-17)** — `ch-5g` auf `width=20/40mhz`; ap1 `5180/ax/Ce/I`, ap2 `5220/ax/Ce/I`,
|
||
**beide 18 dBm** (ap2 vorher 9). Zellen benachbart, überlappungsfrei (5170–5210 / 5210–5250).
|
||
- 🔴 **GOTCHA, der zwei Deploys gekostet hat: `/interface/wifi/set <if> !channel` löscht die
|
||
Inline-Sub-Property-Overrides NICHT** — es wirft nicht, es tut nichts. Danach stand `channel.width`
|
||
unverändert da, obwohl Profil *und* `configuration` korrekt auflösten. **Richtig ist einzeln:
|
||
`!channel.width !channel.band !channel.skip-dfs-channels`.** Dasselbe Muster wie der bekannte
|
||
`!configuration.ssid !security.*`-Griff aus dem TP3-Bring-up — nur nie auf `channel.*` angewandt.
|
||
- ⚠️ **Zwischenzustand war schlechter als der Ausgangszustand:** weil die Breite noch auf 80 MHz stand,
|
||
rutschte ap2 mit der neuen Frequenz in **denselben** 80-MHz-Block wie ap1 (beide ch36–48) = genau die
|
||
Co-Channel-Lage, die 2026-06-18 wegkonfiguriert werden sollte. **Merke: bei Kanalarbeit Breite VOR
|
||
Frequenz ändern**, sonst erzeugt man auf dem Weg eine Kollision.
|
||
4. 🔜 **Fund E** — `access-list` mit `signal-range`-Boden je AP; Schwellen erst nach dem Re-Walk festlegen.
|
||
*(Hinweis aus der P750W-Historie: `/interface/wifi` hat **kein** `disconnect-timeout`/`keepalive` mehr —
|
||
das gab es nur im alten `wireless`-Paket, AX-Radios können nicht zurück. Der Signal-Boden ist damit der
|
||
einzige verbleibende Griff gegen klebende Clients.)*
|
||
5. **Re-Walk + Dead-Spot-Kartierung** (der übernommene TP3.3-Rest) — **erst jetzt**, gegen die korrigierte Basis.
|
||
Vorher gemessene Werte sind wertlos.
|
||
6. ⏳ **Drift-Lücke — Teil 1 GESCHLOSSEN, Teil 2 offen und jetzt exakt vermessen (2026-08-17).**
|
||
- ✅ **Der akute Teil ist zu:** die neuen Werte stehen in der SoT (`nautobot/ingest-ap-configcontext.py`:
|
||
`radios[5g].width` `20/40/80mhz`→`20/40mhz`, `DEVICE_CHANNELS[ap2][5g]` `149`→`44`), Config-Context
|
||
gepatcht, dann **Backup → Intended → Compliance** → **72/72, keine Drifts.** Damit kann ein künftiger
|
||
Deploy die Fixes **nicht** mehr zurückdrehen. *(Bemerkenswert: `width` für 2,4 GHz stand dort die ganze
|
||
Zeit korrekt auf `20mhz` — die SoT war richtig, nur das Gerät hat sie nicht befolgt. Der Beweis, dass
|
||
das Problem der Inline-Override war und nicht die Datenlage.)*
|
||
- 🔴 **Der Erkennungsteil bleibt offen. Die 18 Compliance-Rules abgefragt — es fehlen genau zwei Sektionen:**
|
||
| vorhanden | fehlt |
|
||
|---|---|
|
||
| `/interface wifi channel` · `… configuration` · `… datapath` · `… security` · `… steering` | **`/interface wifi`** (die Interface-Sektion) |
|
||
| `/ip firewall nat` | **`/ip firewall filter`** |
|
||
- **Folge 1 (WLAN):** die fünf `wifi-*`-Features decken nur die **Profil**objekte ab. Die Inline-Overrides
|
||
leben in `/interface wifi` — **deshalb sind Fund A und D seit dem 2026-08-08 unentdeckt geblieben, obwohl
|
||
die Flotte durchgehend „compliant" meldete.** Genau die Lücke, die ich unter Beobachtung 5 vermutet hatte;
|
||
sie ist jetzt belegt, nicht vermutet. Erschwerend: die VAP-MAC-Adressen sind gerätespezifisch (Template
|
||
Zeile ~220 nimmt sie bewusst raus), eine Rule auf diese Sektion braucht also erst
|
||
`local_config_context_data` je AP.
|
||
- 📋 **Vorarbeit `/ip firewall filter` (2026-08-17, Reconnaissance — vor dem Template-Bau nötig):**
|
||
`crs326-core` **25** Regeln (defconf + TP10 + 6 TP5-Holes + 11 TP5-E2 + Log-Regel) · `crs326-branch` **0** ·
|
||
`ap1`/`ap2` je **12 defconf-Regeln** (Werksreste: input-seal, fasttrack, ipsec-Zeilen, sogar
|
||
„accept to local loopback (for CAPsMAN)" — inert, weil die APs nicht routen, aber vorhanden).
|
||
➡️ **Zwei Entscheidungen, bevor die Rule scharf gemacht wird**, sonst meldet sie sofort flächendeckend Drift:
|
||
(a) **APs:** die 12 defconf-Regeln als Sollzustand ins Template schreiben **oder** sie abräumen
|
||
(sie tun nichts — ein reiner AP hat keine `forward`-Kette zu schützen). Empfehlung: **abräumen**, sonst
|
||
schreibt man Werksmüll als Absicht in die SoT — dasselbe Argument wie bei `telnet` in TP16.1.
|
||
(b) **branch:** 0 Regeln ist der korrekte Sollzustand und muss im Template auch als *leer* gerendert werden.
|
||
- 🔴 **Folge 2 (und die ist gewichtiger): `/ip firewall filter` ist NICHT abgedeckt.** Die TP5-Zeile
|
||
„läuft über Nautobot GC (`ip-firewall-*`-Features aus TP22)" ist damit **irreführend — es existiert nur
|
||
NAT.** Die 11 Etappe-2-Regeln und der kommende Deny-by-default sind **nicht drift-überwacht**:
|
||
„72/72 compliant" sagt über die Firewall **gar nichts**. ➡️ **Das gehört VOR TP5 Etappe 3**, denn eine
|
||
Drop-Regel, die niemand überwacht, ist genau die, die still verschwindet.
|
||
- ⚠️ **`steering=`/Channel-Änderungen re-applien alle VAPs und werfen jeden Client kurz raus** (TP3.3 am
|
||
2026-08-13 gemessen: ap1 25→2, ap2 7→14). **Nicht während eines Calls deployen.** `/system backup` je AP vorher.
|
||
- **Abh.:** TP22 ✅ (GC-Deploy-Pipeline). Übernimmt den offenen Rest von **TP3.3**, verwandt **TP3.2** (Coverage-Doku
|
||
`docs/wifi-p750w-coverage-and-map.md`). **Kein Blocker für TP5/TP6** — läuft parallel.
|
||
|
||
### TP16.3 — cloudflared-Reduktion: was der Mesh als Datenpfad kann (und was nicht) ▸ ⏳ **RECHERCHE DURCH (2026-08-17)**, Umsetzung offen
|
||
> **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.**
|
||
- **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.
|
||
|
||
### TP-R — Router-Capabilities-Sweep ▸ FERTIG (`docs/research/routeros-capabilities.md`)
|
||
- **Leitsatz: nativ vor Container, NAS vor Router** (128MB-Flash-Limit).
|
||
- **Sofort nativ (~0 RAM):** RoMON · Netwatch · Scheduler + Auto-Backup/Mail · SNMP→externes Monitoring · **mDNS-Repeater** · spectral-scan · **802.11r/k/v (Fast-Roaming statt Mesh)** *(die Sweep-Fassung nannte hier CAPsMAN — das ist seit 2026-08-08 abgeschafft; 11r/k/v läuft standalone weiter, s. TP3/TP3.3)* · Back-to-Home/WireGuard.
|
||
- **Auf NAS:** FreeRADIUS(+LDAP) · NPM · icinga/Grafana · CF-Tunnel.
|
||
- **Weglassen:** LoRa (keine HW) · OpenFlow · CALEA · **ZeroTier (CPU-Fresser bis ~60 % → WireGuard)** · lokales `dude`.
|
||
- ✏️ **Korrektur Reverse-Proxy:** RouterOS **7.22+ HAT** einen nativen (`/ip/reverse-proxy`, ACME/SNI) — aber **ersetzt NPM NICHT** (kein WebSocket/gRPC/Sticky, nur IPv4-Backends, TLS frisst Router-CPU) → NPM bleibt auf NAS.
|
||
- Speist TP8/9/11/12.
|
||
|
||
---
|
||
|
||
## Reihenfolge / Abhängigkeiten
|
||
|
||
### 🎯 Kritischer Pfad (Stand 2026-08-17)
|
||
|
||
```
|
||
TP5 E1 ✅ ──► TP5 E2 ✅ ──► [mehrtägiges stilles Fenster] ──► TP5 E3 (Drop) ──► TP5 E4 ──► TP6 (CAKE) ◄ Projektziel
|
||
▲
|
||
D2: iPhone aus IOT-SSID
|
||
```
|
||
|
||
1. ✅ **TP5 Etappe 1 — Log-Lauf.** Lief 2026-08-16/17, **43.027 Zeilen** Material.
|
||
2. ✅ **TP5 Etappe 2 — 11 Whitelist-Regeln** (2026-08-17, ConfigPlan `86fbd528`). Log-Regel verstummt.
|
||
3. ⏳ **Wartezeit, kein Arbeitsschritt:** das Log muss **mehrere Tage** still bleiben. 70 Sekunden Stille sind
|
||
keine Aussage — es gibt Geräte, die einmal pro Woche funken. **Das ist das Gate, nicht eine Meinung.**
|
||
4. 🔜 **TP5 Etappe 3 — Drop scharf schalten.** Vorbedingungen: das stille Fenster · D2 (iPhone `.30.201`
|
||
ins MAIN-SSID, Hands-on Christoph) · **und neu: eine Compliance-Rule auf `/ip firewall filter`.**
|
||
🔴 **Am 2026-08-17 festgestellt: die Filter-Kette ist NICHT drift-überwacht** — es gibt nur
|
||
`ip-firewall-nat`. Eine Deny-by-default-Regel ohne Drift-Erkennung ist genau die, die still verschwindet
|
||
und niemandem auffällt, bis etwas nicht mehr geht. **Siehe TP25 Schritt 6.**
|
||
🛟 Auto-Revert-Scheduler davor (auf dem Core möglich, `device-mode` erlaubt scheduler — auf den hAPs nicht).
|
||
5. 🔜 **TP5 Etappe 4 — UNTRUSTED/GUEST Internet-only + MGMT isolieren** (`seal-lan` verengen → schaltet
|
||
zugleich die 5 toten mDNS-`input`-Regeln scharf). **Mit im Paket:** TP7.1 (SSDP-Reflector für die
|
||
macOS-Sonos-App) — gemeinsam testen, sonst prüft man zweimal dieselbe Strecke.
|
||
6. 🔜 **TP6 — QoS/CAKE + Call-Quality-A/B-Test.** Das eigentliche Projektziel; hängt nur an TP5.
|
||
|
||
**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`** (heute plain `1.1.1.1`) — ist zugleich TP21.1 TODO 1 **und** TP23 Stufe 1.
|
||
- **TP24 — DC-USV** (seit 2026-08-16 eigener TP, aus TP15 herausgelöst).
|
||
- **TP19 — VLAN1-Client-Retirement / cudy-Teardown:** Rest sind physischer cudy-Ausbau, Media-Check, Inventar/DNS
|
||
und die HA-Portainer-Integration (`setup_retry`). Die VLAN1-Adressen sind ✅ abgeräumt (2026-08-15/16).
|
||
- ~~**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).
|
||
- **TP14.4 —** CF-Access-Service-Token rotieren.
|
||
- **Doku-Aufräumen** (`docs/doku-cleanup-session.md`) — Punkte A–D am 2026-08-16 abgearbeitet, E teilweise.
|
||
|
||
### Nachgelagert / research-getrieben
|
||
|
||
**TP8** (Identity/802.1X) · **TP11** (Monitoring) · **TP12** (IPv6) · **TP13** (Botschafts-WLANs) ·
|
||
**TP16.2** (Härtung bypass-Dienste) · **TP18** (Garage-Objektspeicher) · **TP20.1** (Vaultwarden → Platform-PG) ·
|
||
**TP23** (DNS-Policy, s. Regel oben).
|
||
*(**TP16.1** stand hier bis 2026-08-17 fälschlich als offen — es ist seit demselben Tag ✅ abgeschlossen und
|
||
steht unten unter „Durch". Nachfolger ist **TP16.3**, das oben unter Follow-ups läuft.)*
|
||
|
||
### ✅ Durch (Fundament — nicht mehr planen, nur nachschlagen)
|
||
|
||
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. **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>
|