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

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

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

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

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

446 lines
40 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Cloudflare-Tunnel — Mapping & #1033-Diagnose (Single Source of Truth)
> **Aktueller Stand: → §10 (2026-07-10, TP16 UMGESETZT ✅).** §9 = Analyse/Zielbild, §10 = As-Built.
> Abschnitte 1–8 sind Historie (Track A, 2026-06-30); die „3 Connectors gut/Zielbild"-Aussagen dort sind
> durch §9/§10 **ĂŒberholt** (Round-Robin = macvlan-Host-Isolation → 1/N-AusfĂ€lle). Track A aus `docs/handoff-cf-tunnel-1033.md`.
## 1. Alle Tunnel im Account (`393c
66c36`)
| Tunnel | ID | Status | Conns | Verwendung |
|---|---|---|---|---|
| **bf.emsenhuber.net** | `70d6a4cf-
-91fab4fa7270` | **healthy** | **12 (=3 Connectors)** | **BF-Dienste — relevant** |
| fm.emsenhuber.net | `b697d124-
-384cced4db1a` | healthy | 4 (1 Connector) | FM-Standort (nas-fm), separat |
| TeilzeitCharlie | `6c784c98-
` | down | 0 | tot |
| coolify | `4f54ad8a-
` | down | 0 | tot |
| johnny2 | `acc73eb5-
` | down | 0 | tot |
| openclaw | `7a8f7b53-
` | down | 0 | tot (odroid-m1, offline) |
## 2. bf-Tunnel — die 3 Connectors (Round-Robin!)
Fingerprint via Colo-Locations (CF-API ↔ lokale cloudflared-Logs) + Arch.
**Wichtig:** DS923+ = AMD Ryzen = amd64; macmini = Apple Silicon = arm64.
| CF-Connector | arch | Host (Portainer) | LAN-IP | Docker-Netz | Vantage |
|---|---|---|---|---|---|
| `1856dfc3-
` | arm64 | **macmini** (ep20) | 10.40.20.167 | **bridge** `cloudflared_default` | **VLAN20** |
| `db713b30-
` | amd64 | **pve-LXC** (ep2) | 10.40.20.126 | host | **VLAN20** (TP14.2 2026-07-10 → #1033-Zielbild) |
| `d7454e68-
` | amd64 | **nas-bf DS923** (ep14) | 10.40.41.10 | host | VLAN1/.41 |
Alle 3 fahren **denselben Tunnel-Token** (`tunnel run`, token-managed Ingress im Dashboard).
CF round-robined Requests ĂŒber alle 3 → **jeder Origin muss von allen 3 Vantages erreichbar sein**, sonst sporadisch 1033.
Leichen auf dem NAS (exited, harmlos, aufrÀumen): `oc-tzcharlie-cloudflared`, `oc-johnny2-cloudflared`.
## 3. Ingress (token-managed, v104) — Reachability je Connector
Quelle: macmini aktiv geprobt; pve/NAS aus echten cloudflared-Fehler-Logs (tail 2000).
`OK` = erreichbar, `FAIL` = no route / down, `?` = nicht beobachtet (vermutl. OK).
| Hostname | Origin | pve | NAS | macmini | Befund |
|---|---|---|---|---|---|
| pve | https://10.40.41.100:8006 | OK | ? | OK | ok |
| hass | http://10.40.41.105:8123 | OK | **FAIL** | OK | NAS no-route (sporadisch) |
| ha-mcp | http://10.40.41.105:9583 | OK | **FAIL?** | OK | wie hass |
| pbs | https://10.40.41.135:8007 | ? | ? | **FAIL** | macmini no-route |
| n8n | http://10.40.41.167:5678 | **FAIL** | **FAIL** | **FAIL** | **.167 STALE** (Host weg) |
| mcp-ms365 | http://10.40.41.167:3005 | **FAIL** | **FAIL** | **FAIL** | **.167 STALE** |
| hermes | http://10.40.41.167:9119 | **FAIL** | **FAIL** | **FAIL** | **.167 STALE** |
| gitea-mcp | http://10.40.41.167:3000 | **FAIL** | **FAIL** | **FAIL** | **STALE → lĂ€uft auf 10.40.20.167:3000** |
| n8n-mcp | http://10.40.41.167:3001 | **FAIL** | **FAIL** | **FAIL** | **STALE → lĂ€uft auf 10.40.20.167:3001** |
| 82unkpb5 (ssh) | ssh://10.40.41.167:22 | **FAIL** | **FAIL** | **FAIL** | **STALE → macmini 10.40.20.167:22** |
| vw | http://10.40.41.127:80 | OK | **FAIL (1736×)** | **FAIL** | **pve-lokaler Container** — nur pve erreicht |
| ccu | http://10.40.41.232:80 | OK | ? | OK | wahrsch. pve-lokal |
| iobroker | http://10.40.41.19:8080 | ? | **FAIL** | **FAIL** | nur pve? prĂŒfen |
| gateway-dw | http://192.168.178.1 | ? | ? | **FAIL** | **DW-Netz, nur ĂŒber WG — kein BF-Connector hat die Route** |
| gitea | http://10.40.41.157:3000 | OK | ? | OK | ok (macmini transient) |
| nginx-bf | http://10.40.41.123:81 | OK | ? | OK | ok |
| ds-bf | http://10.40.41.10:8080 | OK | OK | OK | ok |
| portainer | https://10.40.20.126:9443 | OK | OK | OK | TP14.2: Origin .41→.20.126; Tunnel-Smoke 200 |
| grafana | http://10.40.41.109:3000 | ? | ? | OK | ok |
| pve-mcp | http://10.40.41.173:3000 | ? | ? | OK | ok |
| gateway-bf | http://10.40.41.254 | OK | ? | OK | ok (FB) |
| j44d6tua (ssh) | ssh://10.40.41.100:22 | OK | ? | OK | ok |
| 3k23uow7 (ssh) | ssh://10.40.41.10:22 | OK | OK | OK | ok |
| (catch-all) | http_status:404 | — | — | — | — |
## 4. DNS-Probleme (Zone emsenhuber.net, `1b5bc02f
`)
**Orphan-CNAME → bf-Tunnel, aber KEINE Ingress-Regel → 404:**
- `mcp-qdrant.emsenhuber.net`, `ssh-nasbfnew.emsenhuber.net`
**CNAME → tote/gelöschte Tunnel → konstante 1033:**
- `oc`, `dashboard`, `drawio` → openclaw (down)
- `jc` → johnny2 (down) · `charlie` → TeilzeitCharlie (down) · `coolify` → coolify (down)
- `oc2` → `d8df70a7
`, `oc3` → `3702dc6e
`, `win11test` → `de818071
` — **Tunnel existiert nicht mehr**
(FM-Tunnel-CNAMEs `ds-fm`/`gateway-fm` → `b697d124
` healthy = ok, separat.)
## 5. Root-Cause #1033 (zusammengefasst)
1. **3 Connectors mit asymmetrischer Reachability** + Round-Robin = sporadisch 1033 (Kernursache, log-bewiesen).
2. **pve-lokale Container** (`vw .127`, `ccu .232`) nur vom pve-Connector erreichbar (macvlan, kein LAN-Route von NAS/macmini).
3. **Stale Origin `.41.167`**: macmini nach VLAN20 (`10.40.20.167`) gewandert → 5 Dienste zeigen ins Leere.
4. **gateway-dw** braucht WG-Route — kein BF-Connector hat sie.
5. **DNS-MĂŒll**: 9 CNAMEs auf tote Tunnel (konstante 1033) + 2 Orphans (404).
## 6. Fix-Plan (gestaffelt — Freigabe nötig)
**Stufe 1 — Sofort-EntschĂ€rfung — ✅ ANGEWENDET 2026-06-30:**
- bf-Tunnel auf **nur pve-Connector** reduziert (NAS ep14 + macmini ep20 cloudflared gestoppt, reversibel via `start`).
- Verifiziert: Tunnel `healthy`, 1 Connector (`db713b30`/pve). Smoketest `vw` 4×200 (vorher 1736 Fehlversuche), `hass`/`portainer` 302. **Kein 1033 mehr.**
**Stufe 2 — Stale-Origins fixen (Dashboard-Ingress) — OFFEN, braucht Entscheidungen:**
Die .167-Dienste laufen real auf dem **macmini (ep20, VLAN20 10.40.20.167)** — aber uneinheitlich:
- `gitea-mcp` → `10.40.20.167:3000` ✓ · `n8n-mcp` → `10.40.20.167:3001` ✓ · `82unkpb5 ssh` → `10.40.20.167:22` ✓ (saubere Host-Ports)
- `n8n` (`n8nio/n8n`): **kein Host-Port** (`pub=[]`) → nur im Docker-Netz, von pve NICHT routbar. Entscheidung: Port publishen ODER macmini-lokalen Connector ODER stilllegen.
- `hermes`: **2 Instanzen** — `hermes-christoph` `10.40.20.167:8642`, `hermes-geli` `10.40.20.167:8643`. Ingress-Port `9119` obsolet → klĂ€ren, welche `hermes.emsenhuber.net` bedienen soll.
- `mcp-ms365`: **auf keinem Host gefunden** → Ingress + DNS entfernen?
- ⚠ **Vor Repoint zu verifizieren:** erreicht der pve-Connector (.41.126, FB-Default-GW!) ĂŒberhaupt VLAN20 (.20.167)? → beim Apply per Smoketest prĂŒfen, sonst Rollback.
**Stufe 3 — DNS-Hygiene:**
- Tote CNAMEs löschen: `oc`,`oc2`,`oc3`,`win11test`,`jc`,`charlie`,`coolify`,`dashboard`,`drawio`.
- Orphans `mcp-qdrant`,`ssh-nasbfnew`: Ingress-Regel ergÀnzen **oder** CNAME löschen.
- NAS-Leichen `oc-tzcharlie`/`oc-johnny2` entfernen.
---
## 7. CHANGE-SET — ✅ KOMPLETT 2026-06-30
> Zugang ĂŒber **scoped API-Token** in `mcp/cloudflare/.env` (OAuth-MCP blieb read-only).
> **A1 + A2 + A3 alle angewendet.** Endzustand: Tunnel healthy/1 Connector (pve), Ingress v106,
> 23 Ingress-Hostnames ↔ 23 DNS-CNAMEs, keine Waisen, keine CNAMEs auf tote Tunnel.
### ✅ Erledigt
- **A1:** n8n-Compose-Port `10.40.41.167→10.40.20.167` (Stack 174 redeploy, Volume/Encryption-Key erhalten,
`/healthz` 200). NAS-Leichen `oc-tzcharlie`/`oc-johnny2` entfernt.
- **A2 (Ingress v106):** gitea-mcp/n8n-mcp/82unkpb5/n8n/hermes → `.20.167`; `hermes-geli` (:8643) neu;
`mcp-ms365` entfernt. Keine `.41.167`-Origins mehr. pve→VLAN20 verifiziert (n8n-mcp 200 via bf4).
- **App-Level-Notizen (kein 1033):** `gitea-mcp` 404 auf `/` (Sub-Pfad?), `hermes` 502 (Origin .20.167:8642
erreicht, App liefert 502) — separat prĂŒfen.
### ✅ A3 (DNS) erledigt
- `hermes-geli` CNAME → `70d6a4cf
.cfargotunnel.com` (proxied) angelegt → jetzt erreichbar (302).
- Gelöscht: `oc`,`oc2`,`oc3`,`win11test`,`jc`,`charlie`,`coolify`,`dashboard`,`drawio`,`mcp-ms365`,
`mcp-qdrant`,`ssh-nasbfnew`.
- Konsistenz verifiziert: 23↔23, keine Orphans, keine toten Tunnel-Verweise.
### UrsprĂŒnglicher Plan (Referenz)
### A. Portainer (Write vorhanden — kann sofort, careful):
- **macmini n8n-Container** mit `-p 5678:5678` neu erstellen (Volumes/ENV erhalten!) → Origin `10.40.20.167:5678`.
- NAS-Leichen entfernen: `oc-tzcharlie-cloudflared`, `oc-johnny2-cloudflared` (exited).
### B. Tunnel-Ingress `70d6a4cf
` (PUT /configurations) — Ziel-Origins:
| Hostname | NEU | alt |
|---|---|---|
| gitea-mcp | `http://10.40.20.167:3000` | .41.167:3000 |
| n8n-mcp | `http://10.40.20.167:3001` | .41.167:3001 |
| 82unkpb5 (ssh) | `ssh://10.40.20.167:22` | .41.167:22 |
| n8n | `http://10.40.20.167:5678` | .41.167:5678 (nach A) |
| hermes | `http://10.40.20.167:8642` | .41.167:9119 |
| **hermes-geli** (NEU) | `http://10.40.20.167:8643` | — |
| mcp-ms365 | **Regel löschen** | .41.167:3005 |
⚠ **Vor B: pve→VLAN20-Reachability per Smoketest verifizieren** (1 Repoint, extern testen, sonst Rollback — pve hat FB-Default-GW).
### C. DNS (Zone `1b5bc02f
`) — CNAMEs löschen:
`oc`, `oc2`, `oc3`, `win11test`, `jc`, `charlie`, `coolify`, `dashboard`, `drawio`, `mcp-ms365`.
**Neu anlegen:** `hermes-geli.emsenhuber.net` CNAME → `70d6a4cf-aa1d-4a91-b918-91fab4fa7270.cfargotunnel.com` (proxied).
**Orphans** `mcp-qdrant`, `ssh-nasbfnew`: ohne Ingress → löschen (oder Ingress ergĂ€nzen, falls Dienst gewĂŒnscht — offen).
**Stufe 4 — Zielbild (ĂŒberlappt Track C / IP-Migration):**
- Origins auf konkret routbare IPs in VLAN20 konsolidieren, dann **HA-Connector-Paar** (z.B. pve + NAS) **beide in VLAN20**, sodass jeder Connector jede Origin erreicht. `gateway-dw` ĂŒber WG-fĂ€higen Connector lösen.
- TP5-Firewall ZULETZT (erst wenn alle Origins/Connectors in VLAN20).
---
## 8. Update 2026-07-09 — NAS→VLAN20-Cutover + Ingress v116
Nach NAS-DSM-Cutover auf `10.40.20.10` und Docker-Migration auf ein Macvlan `vlan20`
(alle NAS-Container jetzt `10.40.20.x`, s. `docs/nas-vlan20/`):
**Ingress v115→v116 (via scoped Token, `cf_repoint`):** 6 Origins `.41→.20` repointet —
`ha-mcp` .105:9583, `3k23uow7`(NAS-ssh) .10:22, `gitea` .157, `vw` .127, `grafana` .109, `pve-mcp` .173.
Keine `.41`-Stale unter den migrierten Hosts mehr. Bleibt `.41`: pve .100, j44d6tua .100,
portainer .126, nginx-bf .123, gateway-bf .254.
**Connector-Reachability — geklĂ€rt (kein Routing-Problem):** Der pve-Connector `.41.126` **erreicht
VLAN20** — `vw.emsenhuber.net` → **200** ĂŒber den Tunnel (Vaultwarden `.20.127` lĂ€uft). ap1 macht das
Inter-VLAN-Routing VLAN1↔VLAN20, das steht. Ein `502` direkt **nach** dem Ingress-PUT war **transient**
(Connector-Origin-Cache/ARP noch nicht warm), verschwindet nach kurzer Zeit. `grafana` `502` = Container
`exited` (starten → geht). **Kein pve-Static-Route nötig.**
**Bleibt offen (Stufe 4, Connector-Vantage — nicht dringend):** Round-Robin-Asymmetrie #1033, falls
mehrere Connectors aktiv: macmini (`.20.167`, VLAN20) erreicht NAS-Macvlan, scheitert aber an
pve-lokalen Origins/pbs/gateway-dw; NAS-eigener host-net-Connector taugt nicht (Host↔eigene-Macvlan-
Isolation). Zielbild = **ein** Connector, der alles erreicht — löst sich weitgehend von selbst, sobald
pve (+ Connector) mit dem PVID1-Cutoff in VLAN20 wandert (dann sind Origins+Connector im selben L2).
---
## 9. Ist-Inventory & Endanalyse 2026-07-10 (TP16) — SSoT-Stand
> ⚠ Die „3 Connectors sind gut/Zielbild"-Framings der Abschnitte 2/6/8 oben sind **ĂŒberholt** — maßgeblich
> ist dieser Abschnitt. **Analyse turnkey; Umsetzung = eigene Session** (User-Entscheidung).
### 9.1 Invariante (die Regel, an der alles hÀngt)
- **Ein cloudflared-Connector ist blind NUR fĂŒr macvlan/ipvlan-Container auf seinem EIGENEN Host**
(Linux-Kernel: Host ↔ eigene macvlan/ipvlan-Children isoliert). Fremdhost-L2 + co-lokierte *Bridge*-Container
erreicht er sehr wohl.
- **Mehrere Connectoren auf EINEM Tunnel = geteilter Ingress + CF-Round-Robin.** Jede Origin, die auf dem Host
*eines* Connectors als macvlan/ipvlan liegt, fĂ€llt bei ~**1/N** der Requests aus (#1033, „jeden 3. Schuss eine Niete").
**Strukturell** — nicht durch „Origins fixen" heilbar, solange ein Connector Origins seines eigenen Hosts bedient.
- **Kein Route→Connector-Pinning INNERHALB eines Tunnels.** „AusgewĂ€hlte Routen fĂŒr ausgewĂ€hlte Connectoren" gibt
es nur ĂŒber **getrennte Tunnel** (CNAME → jeweiliger Tunnel; pro Tunnel eigene Connectoren).
### 9.2 Live-Inventory (gemessen 2026-07-10, Ingress **v119**, 24 Hostnames + catch-all, 2 live Connectoren `b797ee1b`/`f480dc69`)
CF-Access: **`vw` = `bypass` (ÖFFENTLICH!)** ⚠ · `hass` & Rest geschĂŒtzt via Wildcard `*.emsenhuber.net`
(`allow:christoph` / `non_identity:bf4` / `allow:claude-mcp`).
| Hostname | Origin | Live | Host/Netz (zu verifizieren) |
|---|---|---|---|
| pve / j44d6tua(ssh) | `.41.100:8006` / `:22` | UP | Proxmox-Host (VLAN1) |
| hass / ha-mcp | `.20.105:8123` / `:9583` | UP | HA-Host .105 |
| pbs | `.20.135:8007` | **DOWN** | Proxmox Backup Server |
| n8n / hermes / hermes-geli / gitea-mcp / n8n-mcp / 82unkpb5(ssh) | `.20.167:*` | n8n/mcp UP · **hermes+hermes-geli DOWN** | macmini |
| portainer | `.20.126:9443` | UP | pve-LXC (host-net) |
| nginx-bf | `.41.123:81` | **DOWN** | **noch VLAN1!** |
| ds-bf / 3k23uow7(ssh) | `.20.10:8080` / `:22` | UP | NAS-Host |
| gitea / grafana / pve-mcp | `.20.157` / `.20.109` / `.20.173` | UP | **NAS-macvlan** (NAS-Connector-blind) |
| omada | `.20.175:8043` | UP | **NAS-macvlan** (NAS-Connector-blind) |
| ccu / vw / iobroker / z2m25 | `.20.232` / `.20.127` / `.20.107:8081` / `.20.106:8080` | UP | **Host/Netz unklar → messen** |
| gateway-dw | `192.168.178.1` | — | **nur via WG** (kein BF-Connector hat Route) |
### 9.3 Ziel-Design: reziproke Per-Host-Tunnel (HA)
Jeder Host-Dienst wird von den Connectoren der **anderen** Hosts bedient (nie vom eigenen), gegenseitig:
| 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** (fĂŒr die 2 anderen Tunnel) → Host-Ausfall ⇒ jeder Tunnel ≄1 Connector = **voll HA**.
Der macmini ist vollwertiger dritter Knoten (nicht „vergessen").
### 9.4 Umsetzungs-Reihenfolge (eigene Session)
1. **Reachability-Matrix je Host** (pve/NAS/macmini → jede der 24 Origins, read-only) — klĂ€rt v.a. `vw`/`ccu`/`iobroker`/`z2m25`
(Bridge nur-eigener-Host? macvlan? ipvlan-auf-pve → dann pve-blind!). Ergebnis bestimmt die Tunnel-Gruppierung.
2. **Interim-Sofortfix:** bf-Tunnel auf **pve-only** (pve erreicht alles außer gateway-dw) → 0×1033. Reversibel.
3. **Reziprokes 3-Tunnel-HA bauen:** 3 Tunnel anlegen, ~24 CNAMEs re-pointen, 6 Connectoren (2/Host, je eigenes Token),
Alt-Token aus NAS/macmini-cloudflared entfernen. `vw`/`ccu` ggf. auf VLAN20-macvlan heben (dann L2-erreichbar).
4. **Tote Origins bereinigen:** `pbs`, `nginx-bf` (noch .41!), `hermes`, `hermes-geli`.
5. **Access-Strang (Track B):** `hass`-400 ohne Passthrough → iPhone in **WARP** enrollen; **`vw` von bypass → geschĂŒtzt**.
6. **Loop-Gegentest** aller FQDNs (0×1033), `gateway-dw` als WG-Sonderfall klĂ€ren/entfernen.
---
## 10. AS-BUILT 2026-07-10 (TP16 umgesetzt) — reziprokes 3-Tunnel-HA ✅
> Gebaut & verifiziert in eigener Session. Round-Robin-#1033 **strukturell weg** (Loop-Gegentest 0×530 ĂŒber alle 19 Live-FQDNs, HA per Host-Ausfall-Sim bewiesen). Schritte 1–4+HA durch; **Schritt 5 (Access/WARP + `vw`) offen** (user-gated).
### 10.1 Reachability-Matrix (die Basis, read-only gemessen)
Einzige Blindheit im System: **NAS-Connector (host-net) ↔ NAS-Docker-macvlan** (Kernel-Isolation). Alles andere cross-host-L2 / inter-VLAN-geroutet erreichbar.
- **NAS-`vlan20` = macvlan** (parent `ovs_eth0`): gitea `.157`, grafana `.109`, pve-mcp `.173`, omada `.175`, vw `.127`, drawio `.139`, prometheus `.151`, iob_slave `.33` → **NAS-Connector blind**.
- **pve-LXC-400-`vlan20` = ipvlan** (parent `veth20`): adguard `.16/.17`, omada-mcp `.176` → pve-Connector blind, aber **keine davon ist Tunnel-Origin** → irrelevant.
- **macmini** = alles Docker-**bridge + Port-Publish** auf `.20.167` → keine Blindheit.
- `ccu .232`=RaspberryMatic(qemu/330), `iobroker .107`=iob-exposed(lxc/150), `z2m25 .106`=lxc/112, `hass/ha-mcp .105`=haos(qemu/100) = **pve-GĂ€ste auf vmbr/VLAN20** → von allen erreichbar (keine Docker-macvlan-Kinder).
- **Ergebnis:** pve **und** macmini erreichen je 100 % der Live-Origins; NUR NAS ist fĂŒr seine 5 eigenen macvlan-Dienste blind. Darum: NAS darf nie bf-nas fahren.
### 10.2 Die 3 Tunnel (config_src=cloudflare, token-managed Ingress)
| Tunnel | ID | Dienste | Connectoren (2/Tunnel) |
|---|---|---|---|
| **bf-nas** ⚠ *ID ĂŒberholt, s. §11* | ~~`70d6a4cf`~~ → **`220c9958-401b-4111-9451-f3db09bba2d5`** (2026-07-12 frisch) | gitea, grafana, pve-mcp, omada, vw, ds-bf, 3k23uow7 (+gateway-dw→404) | **pve + macmini** |
| **bf-pve** (neu) | `f7fdf3a6-
-b0f273794d09` | pve, j44d6tua, ccu, iobroker, z2m25, portainer, hass, ha-mcp | **NAS + macmini** |
| **bf-mm** (neu) | `7a322261-
-8ebce99f5ed1` | n8n, n8n-mcp, gitea-mcp, 82unkpb5 | **pve + NAS** |
Prinzip: **jeder Host-Dienst wird von den Connectoren der ANDEREN Hosts bedient** → Host-Ausfall lĂ€sst jeden Tunnel ≄1 Connector = voll HA. Innerhalb eines Tunnels kein Route-Pinning (CF round-robined) — aber beide Connectoren erreichen 100 % → Round-Robin schadet nicht.
### 10.3 Connector-Roster (6 = 2/Host, Docker `cloudflare/cloudflared:latest`, `restart=unless-stopped`)
| Host (Portainer ep) | Container | Tunnel | Netz |
|---|---|---|---|
| pve-LXC (ep2) | `cloudflared-bfnas` (c80a7db) · `cloudflared-bfmm` (faa0960) | bf-nas · bf-mm | host |
| NAS (ep14) | `cloudflared-bfpve` (97312b5) · `cloudflared-bfmm` (963217983) | bf-pve · bf-mm | host |
| macmini (ep20) | `cloudflared-bfnas` (5c5b3ba) · `cloudflared-bfpve` (3339f86) | bf-nas · bf-pve | bridge |
Tokens: nur im Container-Env + jederzeit via `GET /accounts/
/cfd_tunnel/<id>/token` (Bearer `CF_API_TOKEN`). Tunnel-IDs in `mcp/cloudflare/.env` (`CF_BF/PVE/MM_TUNNEL_ID`). **Nicht** als Compose-Stacks angelegt (raw Portainer-API-Container) → bei Neuaufbau: Container mit `TUNNEL_TOKEN=<token>` + `tunnel --no-autoupdate run`.
### 10.4 As-built Verifikation
- Loop-Smoke 19 FQDNs ×5: **0×530**. gitea/omada/vw/ds-bf/pve/portainer/ccu/iobroker/z2m25/n8n/n8n-mcp/82unkpb5 = 200; grafana 302 (Access); pve-mcp 400 (MCP-Handshake); hass 400 / ha-mcp 403 (Access davor, s. Schritt 5); gitea-mcp 404 (App-Pfad).
- HA-Sim: macmini-Host down → bf-nas via pve (4 conns), bf-pve via NAS (4 conns), bf-mm unberĂŒhrt (8) — alle Dienste weiter 200. Restore → alle 3 Tunnel 8 conns.
### 10.5 Cleanup gemacht
- Tote CNAMEs gelöscht: `pbs`, `nginx-bf`, `hermes`, `hermes-geli`. NAS-cloudflared-Leichen `oc-tzcharlie`/`oc-johnny2` entfernt.
- `gateway-dw` (192.168.178.1, nur via WG) bleibt CNAME→bf-nas = **404** (kein BF-Connector hat die WG-Route). **Offen: klĂ€ren/entfernen.**
### 10.6 Schritt 5 Access-Strang — TEILWEISE ✅ (2026-07-10)
**✅ `vw`-Leck geschlossen:** vw-App (`1dbc45ca`) hatte 1 Policy = **bypass/everyone (öffentlich)**. Ersetzt durch 2 eigene (engere als die Wildcard!) Policies: `non_identity bf4-home-ip` (`90.146.35.38/32` = Heim ohne Login) + `allow christoph` (email `christoph@emsenhuber.com`, **kein** `login_method:*`). Bypass war eine **reusable** Policy `a8129e37` → nicht via App/Policies-DELETE löschbar, sondern per **App-PUT detacht** (nur die 2 neuen im `policies`-Array). Verifiziert: Heim = 200, kein `everyone` mehr; Account-weiter Sweep = **keine** App mehr öffentlich. Heim-IP `90.146.35.38` = aktuell (== bf4-DNS).
**🔮 NEUER FUND (wichtiger als vw!) — Wildcard `*.emsenhuber.net` (`16aaec78`) zu offen:** Policy `christoph` hat `include: email:christoph OR login_method:github OR login_method:google`. **`login_method:<idp>` als include matcht JEDEN, der sich via GitHub/Google einloggt** — nicht nur christoph. D.h. **jeder GitHub-/Google-User erreicht nach Login alle internen Dienste** (hass, grafana, portainer, pve, gitea, 
). Fix = die zwei `login_method`-Includes raus (nur `email:christoph` + ggf. weitere erlaubte Mails + `non_identity bf4` + `claude-mcp`). **NICHT einseitig geĂ€ndert** (Ă€ndert Login-Verhalten ĂŒberall) → User-Entscheidung. War im Memory schon als „Policy christoph verschlanken" geflaggt.
**⏞ `hass` 400 / `ha-mcp` — zwei getrennte Layer:**
- **Access-Layer (remote):** HA-Companion-App kann kein interaktives Access-Login → Fix = iPhone in **WARP** enrollen (`Warp Login App` `6c32fe23` `allow:christoph` existiert → christoph darf enrollen). Client-seitig, braucht User am GerĂ€t. Vom Heim-Netz (bf4-IP) ohnehin ohne Login erreichbar.
- **Origin-Layer:** `hass.emsenhuber.net` gibt **vom Heim-Netz** (Access passt via bf4-IP) trotzdem **400** (CF `server:cloudflare`, aber Origin-verursacht) = **HA lehnt den Request ab** — HA-`http:`-Config (`use_x_forwarded_for` + `trusted_proxies` inkl. cloudflared-Range, ggf. Host-Allowlist). **Separates HA-Thema, NICHT Tunnel/Access** — offen.
**gateway-dw** (192.168.178.1, nur via WG) = CNAME→bf-nas = 404 (kein BF-Connector hat WG-Route). Offen: Route bauen oder CNAME entfernen.
---
## 11. Nachtrag 2026-07-12 — bf-nas als EIGENER Tunnel nachgezogen ✅
§10 hatte bf-nas noch als **wiederverwendeten Legacy-Monolith** `70d6a4cf` (Name „bf.emsenhuber.net") gefahren. Jetzt sauber getrennt:
- **Neuer Tunnel `bf-nas` = `220c9958-401b-4111-9451-f3db09bba2d5`** (config_src=cloudflare, Ingress 1:1 kopiert). 2 Connectoren neu: pve `cloudflared-bfnas` (host-net), macmini `cloudflared-bfnas` (`cloudflared_default` bridge).
- **8 CNAMEs** (gitea/grafana/pve-mcp/omada/vw/ds-bf/3k23uow7/gateway-dw) auf den neuen Tunnel umgebogen.
- **WARP-Route `10.40.0.0/16`** (vnet `1480b545-
`) via `PATCH /accounts/
/teamnet/routes/{id}` `{tunnel_id}` umgezogen — **sonst Block:** DELETE-Tunnel scheitert mit `1023 „private network routes"`.
- **Legacy-Tunnel `70d6a4cf`/`bf.emsenhuber.net` GELÖSCHT.** `mcp/cloudflare/.env CF_BF_TUNNEL_ID` = neue ID.
- Zero-downtime: neue Connectoren parallel hoch → CNAMEs → alte Container/Tunnel weg. Verifiziert: gitea/omada/vw/ds-bf 200, grafana 302, pve-mcp 400 (MCP-Bare-GET), bf-nas 2 Connectoren healthy.
- **Writes gehen NUR ĂŒber `CF_API_TOKEN` (curl/Bearer)** — der `cloudflare`-MCP (OAuth) ist read-only (Create-Tunnel → `10000 Authentication error`).
> ⚠ **CF-Zugang fĂŒr frische Sessions — die hĂ€ufigste Stolperfalle (2× reproduziert 2026-07-17):** Es gibt **zwei getrennte** CF-ZugĂ€nge, und `~/.claude.json` verweist NUR auf den read-only-MCP (`https://mcp.cloudflare.com/mcp`), **nicht** auf den Write-Token → ein frischer Agent weiß nichts vom Token und meldet fĂ€lschlich „fehlende Permissions".
> - **`cloudflare`-MCP** (`mcp__cloudflare__docs/search/execute`, OAuth): **strikt read-only**. Reads/Spec-Suche/Batch super; **jeder** Write → `10000: Authentication error` (erwartet, KEIN echtes Rechteproblem).
> - **`CF_API_TOKEN` in `mcp/cloudflare/.env`** (scoped, `valid & active`): **der Write-Pfad.** Damit wurde das komplette 3-Tunnel-HA gebaut. Verifiziert 2026-07-17 mit identischem no-op-vnet-PATCH: MCP → `10000`, curl+Token → `success:True`.
> - **Muster:** `cd ~/dev/bf-network-r6/mcp/cloudflare && set -a; . ./.env; set +a` → dann `curl -H "Authorization: Bearer $CF_API_TOKEN" 
/accounts/$CF_ACCOUNT_ID/<pfad>`. Keys im .env: `CF_API_TOKEN/CF_ACCOUNT_ID/CF_ZONE_ID/CF_{BF,PVE,MM}_TUNNEL_ID`.
> - Alle Calls ĂŒber `api.cloudflare.com` → **WARP-unabhĂ€ngig** (Rollback klappt auch bei totem Privatpfad).
> - **Klarstellung „Claude hat doch zig Tunnel erstellt/geĂ€ndert":** ja — aber immer ĂŒber curl+Token, **nie** ĂŒber den MCP. Der MCP war nie der Write-Pfad.
**hass-400 (2026-07-12 prĂ€zisiert):** `hass`/`vw`/`gitea` sind aktuell wieder auf **`bypass`** (App „hass, vw, gitea") → der 400 ist **rein** der Origin-Layer, **nicht Access**. HA-Log: „Received X-Forwarded-For header from an untrusted proxy **10.40.20.10**". Die reziproken bf-pve-Connectoren (macmini `.20.167`, NAS `.20.10`) fehlen in HAs `http.trusted_proxies`. **Fix** = beide IPs + `use_x_forwarded_for: true` + Core-Restart. **Kein SSH-Key auf HA `.20.105` → user-gated** (oder Zugang geben). Access-HĂ€rtung (bypass→WARP) bleibt der zweite, device-gated Schritt.
---
## 12. Nachtrag 2026-07-13 — pve-Host-Mgmt VLAN1→VLAN20 (letzter TP14-Host-Umzug) ✅
Letzte in §9.2/§8 als „bleibt `.41`" gefĂŒhrte Origin-Klasse (`pve .41.100`, `j44d6tua`-SSH `.41.100`) nachgezogen — der pve-Host selbst (nicht nur seine GĂ€ste/Container) ist jetzt auf VLAN20:
- pve-Host: `vmbr0.20` (bereits als Stub vorhanden, aber mit ungĂŒltiger `address 10.40.20.0/24` — Netzadresse statt Host-IP) korrigiert auf **`10.40.20.100/24`**, live via `ifreload -a` (ifupdown2, kein Reboot). `vmbr0`/`.41.100` bleibt drauf, aber **ohne** `gateway`-Zeile (kein Doppel-Default-Route) — interim wie sw1/sw2/ap2-Mgmt bis VLAN99.
- Default-Route auf pve geflippt: `default via 10.40.20.1 dev vmbr0.20`. Outbound (`1.1.1.1`) + SSH-Key-Login extern beide grĂŒn.
- **Ingress `bf-pve` (`f7fdf3a6-
`) gepatcht** (via `CF_API_TOKEN`/curl, `cloudflare`-MCP weiterhin read-only): `pve.emsenhuber.net` `.41.100:8006`→`.20.100:8006`, `j44d6tua.emsenhuber.net`(ssh) `.41.100:22`→`.20.100:22`. Smoke: beide 200 ĂŒber den Tunnel.
- ap1-DNS: `pve.bf.lan`→`.20.100`. **Kollateral-Fund:** `pve-mcp.bf.lan` zeigte noch auf `.41.173` (nie nachgezogen seit TP14.1) → korrigiert auf `.20.173`.
- GeprĂŒft nur der Tunnel `bf-pve` (8 Hostnames + catch-all) — sonst keine `.41`-Origins mehr darin (`ccu`/`iobroker`/`z2m25`/`portainer`/`hass`/`ha-mcp` waren schon `.20.x`). `nginx-bf .41.123`/`gateway-bf .41.254` aus §8/§9.2 gehören zu anderen Tunneln/Sub-TPs, **nicht** geprĂŒft in dieser Session.
---
## 13. Incident 2026-07-16 — macmini-Connectoren QUIC-Flap (unterwegs, WARP „spinnt") ✅ gefixt
**Symptom (User, unterwegs/BF-fern):** ĂŒber WARP keine BF-IPs mehr erreichbar; FM-Tunnel (`fm.emsenhuber.net`) ging; FQDNs (`*.emsenhuber.net` ĂŒber CF Access) gingen noch. User hatte selbst „in Cloudflare herumgedreht".
**Befund 1 — Connector-Flap auf macmini (Hauptbefund):** `cloudflared-bfnas` + `cloudflared-bfpve` auf dem **macmini** liefen zwar (`docker ps` = Up 3 Tage), aber die QUIC-Verbindungen zum CF-Edge brachen alle 1–10 Min ab (`timeout: no recent network activity` / `accept stream listener encountered a failure`), live reproduzierbar in den Container-Logs. Dadurch hatten **`bf-nas` und `bf-pve` nur noch je 1 von 2 Connectoren aktiv** (4 statt 8 Conns) — TP16-HA faktisch außer Kraft (nicht down, aber kein Host-Ausfall mehr abgefangen). `bf-mm` (nur pve+NAS, kein macmini) war die ganze Zeit sauber bei 8 Conns — das hat die Diagnose auf macmini eingegrenzt.
- **Root Cause:** macminis cloudflared-Connectoren laufen unter **Docker-Desktop-Bridge-Networking** (`cloudflared_default`/`bridge`, userspace-NAT/vpnkit), im Gegensatz zu pve/NAS die **Host-Networking** fahren. Docker Desktop for Mac hat ein bekanntes Problem mit langlebigen UDP/QUIC-Flows ĂŒber die interne NAT → periodische Idle-Drops. `ping`/UDP-Punktcheck von macmini aus liefen sauber (0 % Loss), nur die **dauerhaften** QUIC-Streams von cloudflared waren betroffen.
- **Fix (angewendet, rollend, 0 Downtime da jeweils der andere Connector des Tunnels durchgehend lief):** beide Container auf macmini neu erstellt mit `-e TUNNEL_TRANSPORT_PROTOCOL=http2` (erzwingt TCP/HTTP2 statt QUIC/UDP) — Token/Netz/`restart unless-stopped` unverĂ€ndert ĂŒbernommen. cloudflareds eigener Precheck bestĂ€tigte das sogar (`suggested_protocol=http2`). Beide sofort stabil, 4/4 Conns, keine Reconnects mehr seit Fix. Verifiziert ĂŒber `GET /cfd_tunnel/{id}/connections`: `bf-nas` und `bf-pve` wieder je 2 Connectoren / 8 Conns.
- **Konvention fĂŒr die Zukunft:** jeder kĂŒnftige cloudflared-Connector **auf dem macmini** (egal welcher Tunnel) sollte von vornherein `TUNNEL_TRANSPORT_PROTOCOL=http2` bekommen — pve/NAS (Host-Networking) brauchen das nicht.
**Befund 2 — WARP-Private-Network-Route umgebogen (User selbst, Audit-Log bestĂ€tigt):** Route `10.40.0.0/16` (vnet `1480b545
`) zeigte bis eben laut §11 auf `bf-nas`. Audit-Log zeigt: User hat um **11:36:11 UTC die alte Route gelöscht und um 11:36:24 UTC eine neue angelegt** — die neue zeigt auf **`bf-pve`** (`f7fdf3a6
`), neue Route-ID `5546dcb6
`. Funktional unproblematisch (bf-pve ist nach Befund-1-Fix wieder voll HA, NAS+macmini erreichen wie pve/macmini bei bf-nas 100 % der Origins/VLANs, s. §10.1). Keine weiteren Anomalien im Audit-Log (10.09–10.36 UTC nur erwartete Änderungen: `nautobot`-DNS+Ingress auf `bf-nas` angelegt, mehrere `tunnel.management_session` = Dashboard-Logins).
- Gateway-Regeln, Split-Tunnel-Exclude/Include, Virtual-Networks (nur 1, `vnetemsenhuber`) — alle unauffĂ€llig, kein Blocker gefunden.
- ⚠ **Zwischenentscheidung (2026-07-16, spĂ€ter am Tag REVIDIERT — s. Befund 3 + §14):** kurzzeitig als „`bf-pve` bleibt WARP-Route-Baseline wegen USV" festgehalten (Commit `1c1a676`). **Diese BegrĂŒndung war invertiert** und ist hinfĂ€llig: `bf-pve`s Connectoren laufen auf **NAS + macmini** (NICHT auf pve). Bei Stromausfall (nur pve an USV) wĂ€ren damit **beide** `bf-pve`-Connectoren tot → Route weg. FĂŒr die WARP-Route zĂ€hlt der **Connector**-Standort, nicht der Origin-Host. Der USV-Gedanke fĂŒhrt daher NICHT zu bf-pve. Route bleibt interim auf `bf-pve` als Fallback, bis der native Mesh-Node (§14) steht.
**Befund 3 — ICMP strukturell kaputt (User-Ping-Test, nach dem Commit):** TCP ĂŒber die WARP-Route ging ĂŒberall (SSH/Web-UIs/MCP), **ICMP nicht.** DreilĂ€nder-Befund: **fm 36 % Loss** (45–655 ms Jitter — ICMP-Proxy ĂŒber QUIC-Connector, funktioniert aber mies), **bf 100 %** (macmini-Connector jetzt http2 = QUIC-los → ICMP-unfĂ€hig; cloudflared-Container ohne Ping-Sockets), **dw 100 %** (192.168.0.0/16 in der WARP-Split-Tunnel-Exclude → Pings betreten den Tunnel gar nicht). **Kernursache:** cloudflared ist ein L7/L4-QUIC-Proxy, kein WireGuard — ICMP darĂŒber ist Zusatz-Gefrickel und war nie sauber eingerichtet. Das ist **kein Bug im heutigen Fix**, sondern eine strukturelle Grenze des cloudflared-Pfads fĂŒr Private Access.
**Einordnung „WARP spinnt" beim User selbst:** die macmini-Connector-Flaps waren ein echter, messbarer Backend-Defekt (Befund 1) und plausibel (mit-)ursĂ€chlich fĂŒr die UnzuverlĂ€ssigkeit; der ICMP-Totalausfall (Befund 3) ist davon getrennt und strukturell.
**NĂ€chster Schritt = Richtungswechsel, s. §14:** Private Access verlĂ€sst den cloudflared-Pfad und wandert auf einen **nativen Cloudflare-Mesh-Node (WireGuard) auf dem CRS326 Core-Switch** (Retarget von ap1 auf CRS326, User-Entscheid 2026-07-22). Der cloudflared-Public-FQDN-Teil (3-Tunnel-HA) bleibt unberĂŒhrt. (Ghost-Connector-Eintrag bei `bf-pve`, arm64, 1 Conn, `run_at` 2026-07-12, seither inaktiv — harmlos, Cleanup bei Gelegenheit.)
---
## 14. Richtungsentscheid 2026-07-16 — Private Access via native Cloudflare Mesh (WARP Connector) auf dem CRS326 Core-Switch (TP16.1)
> ✅ **Update 2026-07-22 (User-Entscheid):** Ziel-Device retargeted von **ap1** auf den **CRS326 Core-Switch** — konsistent mit TP15-Endstand (kein RB5009, Router bleibt ap1/ap2) und TP21s Kabel-Fabric-Modell. Reine Ziel-Doku-Änderung, Scharfschalten bleibt gated bis TP21 den CRS326 abdeckt. Der Rest dieser Sektion ist entsprechend auf den neuen Zielhost umgeschrieben; CRS326 ist aktuell noch Werkszustand, Management-IP/Interface TBD.
**Trennung der Concerns (wichtig):**
- **Public FQDNs** (`*.emsenhuber.net`, MCP-Endpoints, HA-Companion, Access-Policies): bleiben auf dem **cloudflared 3-Tunnel-HA** (bf-nas/bf-pve/bf-mm). UnverÀndert. macmini-Connectoren = `http2` (Befund 1).
- **Private Access** (unterwegs → `10.40.0.0/16` per IP, inkl. ICMP): wechselt vom cloudflared-QUIC-Proxy auf einen **nativen WireGuard-Mesh-Node auf dem CRS326 Core-Switch**.
**Warum CRS326-nativ statt cloudflared/LXC/Container:** Cloudflare Mesh spricht WireGuard, RouterOS kann natives WireGuard (der TP10-Hub auf ap1 *ist* einer, Muster ĂŒbertrĂ€gt sich) → Mesh-Node = WG-Peer zu einem CF-PoP, **kein Container, kein `/dev/net/tun`, kein LXC, keine neue HW**. Der CRS326 ist der zentrale Kabel-Fabric-Knoten und sieht ohnehin alle VLANs; ap1 bleibt Public-Edge/WLAN-Anker, ĂŒbernimmt aber nicht mehr die Mesh-Node-Rolle. RouterOS-Container-Weg bleibt tot (kein TUN-Passthrough auf JEDER Router/Switch-HW) — daher weiterhin natives WireGuard.
**Status: Konzept + Runbook fertig, Scharfschalten = eigene Session, jetzt zusÀtzlich gated durch CRS326-Bring-up** (User-Entscheid: heute nur Konzept, da der TCP-Pfad funktioniert und nur ICMP-Komfort fehlt; die CF-Prerequisites sind account-weit und trÀfen die Live-WARP-GerÀte). **VollstÀndiges Runbook + gemessener Account-Ist-Stand: `docs/tp16.1-warp-mesh-native-crs326.md`.**
**Kernpunkte fĂŒrs Scharfschalten (Details im TP16.1-Doc):**
- Plan-Probe zuerst: `POST /accounts/
/warp_connector` (via `CF_API_TOKEN`) — zeigt, ob Mesh im Free-ZT-Plan erlaubt ist; sonst Fallback LXC-auf-pve.
- Account-weit (1× kurzer WARP-Reconnect): Unique-Device-IP AN (`use_zt_virtual_ip`), „allow CF-One-Traffic → devices", Device-Profile „Cloudflare Mesh" (WireGuard), Split-Tunnel-Exclude `100.64.0.0/10` → `/11`+`100.112.0.0/12`.
- WG-Config via `ghcr.io/animmouse/wgcf-connector <token>` (ephemer) → 4 native WG-Zeilen auf dem **CRS326** (IF + CF-PoP-Peer `bmXOC+
`/`162.159.193.x:2408` + `100.96.x/32` + Route `100.96.0.0/12`) — konkrete Interface-/IP-Zuordnung erst nach CRS326-Bring-up (TP15) final.
- vnet-Route `5546dcb6
` von `bf-pve` auf den Mesh-Tunnel umhĂ€ngen (Rollback = PATCH zurĂŒck; bf-pve bleibt Fallback).
- Team-Domain gemessen: `emsenhuber.cloudflareaccess.com` → Node-IdentitĂ€t `warp_connector@emsenhuber.cloudflareaccess.com`. Noch kein `warp_connector`-Tunnel im Account.
- Governance „Config nur via Nautobot" (TP21): CRS326-WG-Zeilen regulĂ€r via Golden Config, sobald das Device dort adoptiert ist — die alte ap1-Ausnahme gilt hierfĂŒr **nicht**.
## 15. Incident 2026-07-21 → ✅ GEFIXT 2026-08-24 — macmini-Connectoren gestoppt, HA fĂŒnf Wochen degradiert
**Symptom (erhoben 2026-08-16, gefixt 2026-08-24):** `bf-nas` und `bf-pve` liefen auf **je einem**
Connector statt zwei. Kein `530`, kein Round-Robin — reiner **Redundanzverlust**: die Dienste hinter
diesen Tunneln hingen an einem einzigen cloudflared-Prozess.
**Ursache — nicht das erwartete QUIC-Flap.** Die beiden macmini-Container standen auf
`Exited (0)`, `finishedAt` **beide auf `2026-07-21T13:00:53`** (gleiche Sekunde, Exit 0,
`restart=unless-stopped`, `TUNNEL_TRANSPORT_PROTOCOL=http2` korrekt gesetzt). Ein Absturz sieht anders
aus: gleiche Sekunde + Exit 0 + kein Neustart trotz `unless-stopped` = **ein `docker stop` bzw.
`compose down` auf genau diese zwei**. Die ĂŒbrigen macmini-Container liefen die ganze Zeit, der Daemon
ist seither auch neu gestartet — Docker hat die zwei also als „vom Benutzer gestoppt" gefĂŒhrt.
⇒ **Die Datierung in TP16 war falsch: degradiert seit 2026-07-21, nicht seit dem 08-16.** Der 08-16 war
nur der Tag, an dem es *aufgefallen* ist. Zwischen Eintritt und Entdeckung lagen **vier Wochen**.
**Fix:** `docker start cloudflared-bfnas cloudflared-bfpve` auf dem macmini. Sonst nichts —
Tokens, Transport und Restart-Policy waren korrekt.
**Abnahme (2026-08-24):**
- CF-API: `bf-mm` / `bf-nas` / `bf-pve` je **2 Connectoren / 8 conns**, alle `healthy`.
- Connector-Log: `Registered tunnel connection 
 protocol=http2` (Konvention aus §13 gehalten).
- **Smoke-Test gegen das Round-Robin-Muster: 6 FQDNs ĂŒber beide betroffenen Tunnel
(`gitea`/`nautobot`/`grafana` = bf-nas, `portainer`/`hass`/`vw` = bf-pve), je 6 LĂ€ufe = 36 Anfragen,
`530er = 0`.** Das reziproke Design hÀlt: macmini hostet weder NAS- noch pve-Origins, die
macvlan-Host-Isolation aus §9 kann dort also nicht zuschlagen.
🔮 **Die eigentliche Lehre ist nicht der Fix, sondern die NachweislĂŒcke.** Ein Tunnel mit einem von
zwei Connectoren meldet `healthy` — die Degradation ist ĂŒber den Tunnel-Status **nicht sichtbar**, nur
ĂŒber die **Connector-Anzahl**. Genau deshalb blieb sie vier Wochen unbemerkt und wurde beim
Doku-AufrÀumen zufÀllig gefunden. **Ein HA-Design ohne ZÀhler auf die Redundanz ist kein HA-Design.**
⇒ Gehört als Check nach **TP11** (Monitoring): `connectoren < 2` je bf-Tunnel = Alarm.
### Korrektur: die vier toten Alt-Tunnel sind harmloser als notiert
Stand 2026-08-24, live erhoben: `openclaw`, `coolify`, `johnny2`, `TeilzeitCharlie` sind `down`,
0 Connectoren. Ihre **Ingress-Configs beanspruchen weiterhin Hostnames** — `openclaw` unter anderem
`n8n.emsenhuber.net` → `10.40.41.147:5678` (toter VLAN1-Origin), dazu `oc`, `dashboard`, `drawio`;
`coolify` → `10.40.41.133`; `johnny2` → `jc`; `TeilzeitCharlie` → `charlie`.
đŸ”” **Aber: kein einziger CNAME zeigt auf einen dieser vier Tunnel.** Alle 23 Tunnel-CNAMEs der Zone
zeigen auf `bf-mm`/`bf-nas`/`bf-pve`/`fm`/`terpene-db`; **`n8n.emsenhuber.net` zeigt korrekt auf
`bf-mm`**. ⇒ Die in TP16 notierte Sorge, ein wiederbelebter `openclaw` wĂŒrde „exakt das alte
Round-Robin-Muster auf diesem Hostname" erzeugen, ist **so nicht richtig**: **welcher Tunnel einen
Hostname bedient, entscheidet das DNS**, nicht die Ingress-Config. Ein hochkommender `openclaw` wÀre
inert, solange niemand `cloudflared tunnel route dns` dafĂŒr ausfĂŒhrt (was den CNAME umschreiben
*wĂŒrde* — das ist der reale, aber aktive Angriffspfad). Das Round-Robin aus §9 war ein Problem
**mehrerer Connectoren auf EINEM Tunnel**, nicht mehrerer Tunnel auf einem Namen.
⇒ **Löschen bleibt richtig — als Hygiene und um die `route dns`-Falle zu entfernen, nicht als
Störungsbehebung.** Weiterhin user-gated (Löschen ist nicht umkehrbar).
📌 **Doku-Drift mitkorrigiert:** §10 fĂŒhrt `bf-nas` als `70d6a4cf`; live ist die Tunnel-ID
**`220c9958`** (Tunnel am 2026-07-12 neu angelegt, s. §11). §10 gilt sonst unverÀndert.
â„č **Nicht Teil des BF-HA-Designs** (und daher kein Defekt, obwohl sie 1 Connector haben):
`fm.emsenhuber.net` (Standort FM) und `terpene-db` (eigenes Projekt).
### ✅ Nachtrag 2026-08-24 — die vier toten Tunnel sind gelöscht
User-Entscheid „alle vier löschen". Über die CF-API entfernt, je `success: true`:
`openclaw` (`7a8f7b53`), `coolify` (`4f54ad8a`), `johnny2` (`acc73eb5`), `TeilzeitCharlie` (`6c784c98`).
**Gegenprobe direkt danach — 5 Tunnel verbleiben:**
| Tunnel | Status | Connectoren |
|---|---|---|
| `bf-mm` | healthy | **2** |
| `bf-nas` | healthy | **2** |
| `bf-pve` | healthy | **2** |
| `fm.emsenhuber.net` | healthy | 1 *(Standort FM, kein BF-HA-Ziel)* |
| `terpene-db` | healthy | 1 *(eigenes Projekt)* |
Nebenwirkung, die zu **TP19** gehört: mit `openclaw` und `coolify` sind die letzten **VLAN1-Origins**
(`10.40.41.147`, `.148`, `.139`, `.133`) aus der Cloudflare-Konfiguration verschwunden. `.41.133` war
eines der „unidentifizierten VLAN1-GerĂ€te" aus TP19 B1.2 und ist damit endgĂŒltig abgerĂ€umt.
## 16. Korrektur 2026-08-25 — die macvlan-Blindheit war behebbar, der Workaround war grĂ¶ĂŸer als der Fix
§9 hĂ€lt die Host-Isolation als **„strukturell, nicht durch Origins-Fixen heilbar"** fest, und daraus ist
das reziproke 3-Tunnel-Design mit **sechs** Connectoren entstanden. **Das war zu pessimistisch.**
Christoph erinnerte sich (2026-08-24) an einen frĂŒheren Fall — *„dass ich vom container meinen host
nicht sehen konnte 
 ich glaube, das haben wir damals die routing table gepatcht"*. Das trifft zu und
ist der dokumentierte Standardfix: ein **Shim** — ein zweites macvlan-Interface auf dem Host am selben
Parent, mit eigener IP im Subnetz, plus eine Route fĂŒr die Container-IPs darĂŒber. Danach erreicht der
Host seine eigenen macvlan-Container. FĂŒr ipvlan gilt dasselbe Muster.
⇒ **Sechs Connectoren und drei Tunnel standen gegen ein Interface und eine Route pro Docker-Host.**
Gratis ist der Shim nicht (er muss Reboots ĂŒberleben — systemd-Unit, LXC-Hook, auf Synology ein
Boot-Task), aber der Aufwand liegt um GrĂ¶ĂŸenordnungen darunter.
🔑 **Merkregel, die bleibt: bei einer als „strukturell" notierten EinschrĂ€nkung erst prĂŒfen, ob sie ein
Default ist oder ein Gesetz.** Hier stand die pessimistische Lesart ĂŒber ein Jahr unwidersprochen in der
SSoT und hat eine ganze Architektur getragen.
📌 **FĂŒr TP31 wird der Shim nicht gebraucht:** Caddy bekommt einen **eigenen LXC** (eigener
Netzwerk-Namespace, sieht ohnehin alles), und die cloudflared-Connectoren laufen auf **ap1/ap2** —
eigene Maschinen, auf denen die Blindheit prinzipiell nicht auftreten kann. Der Shim bleibt als Option
fĂŒr den Fall, dass spĂ€ter doch ein Dienst neben macvlan-Nachbarn einziehen soll.