44 KiB
TP16.1 — Private Access via native Cloudflare Mesh (WARP Connector) auf dem CRS326 Core-Switch
✅ TP16.1 ABGESCHLOSSEN — 2026-08-17
Der private Zugang läuft über natives WireGuard auf
crs326-corestatt über den cloudflared-QUIC-Proxy. ICMP ist damit repariert: 0 % Loss auf alle BF-VLANs (vorher 100 %) — genau das Symptom aus dem Incident vom 2026-07-16, das dieses TP ausgelöst hat. Die öffentlichen FQDNs blieben unberührt auf dem 3-Tunnel-HA (TP16). Auflage aus Ausnahme #4 erfüllt: 68/68 compliant, keine Drifts.Die drei Erkenntnisse, die Zeit gekostet haben und beim nächsten Mal Zeit sparen:
- Der Blocker war nie der Free-Plan, sondern der API-Token (§4.0) — Mesh ist im Free-ZT-Plan erlaubt.
/ip service address=10.40.0.0/16sperrt das Router-Mgmt aus dem Mesh aus (§4.5) — Ping geht, Management nicht. Fürbranch/ap1/ap2noch offen.- MikroMCP taugt für WireGuard nur halb (§4.3): kein Privkey möglich, und
endpoint="IP:Port"wird falsch zerlegt → kein Handshake.✅ Nachlauf am selben Tag, ebenfalls abgeschlossen: die Mgmt-ACL wurde via Golden Config auf alle vier Geräte ausgerollt (neue Compliance-Feature
ip-service, 72/72 compliant) — s. §4.7. Und der Dashboard-Schalter ist recherchiert und bewusst AUS — s. §4.1 Schritt 2. TP16.1 hat damit keine offenen Punkte mehr, außer den weiterhin getrennt geführten Fremdthemen (TP16-HA, TP5-Firewall).POST /warp_connectorerfolgreich:bf-core-mesh=d1da7c8a-2736-4cbb-8af1-32db5393fb9c, Register-Token inmcp/cloudflare/.env(CF_MESH_REGISTER_TOKEN, gitignored,chmod 600). ➡️ Die seit 2026-07-17 offene Free-Plan-Frage ist damit beantwortet: der Free-ZT-Plan erlaubt Cloudflare Mesh. Der LXC-Fallback (§6) ist vom Tisch. Am Gerät ist weiterhin nichts angefasst (kein Backup, keincf-mesh, keine Route) — nächster Schritt ist §4.1, und der ist wegen des account-weiten WARP-Reconnects user-gated.Historie dieses Anlaufs: 2026-08-16 blockiert auf Token-Scope (zwei fehlende Permissions, s. §4.0) → 2026-08-17 Token neu aufgesetzt, jetzt account-owned.
crs326-coreist seit 2026-08-08 der produktive L3-Router und seit 2026-08-13 in Nautobot adoptiert (68/68 compliant) — die Bedingung „gated bis TP21 den CRS326 abdeckt" ist erfüllt. §3 am 2026-08-16 neu gemessen, §4.3 von Platzhalter auf ausführungsreif gezogen, Governance-Ausnahme #4 erteilt (WG-Zeilen direkt, weil ein Privkey über Golden Config strukturell nicht deploybar ist). Scharfschalten bleibt eine eigene Session — es fasst account-weite WARP-Einstellungen an. Historie: Konzept + Runbook 2026-07-16 · Recherche verifiziert + gehärtet 2026-07-17 · Ziel-Device von ap1 auf CRS326 retargeted 2026-07-22. ⚠️ Retarget-Hinweis (2026-07-22, Stand 2026-08-16 aufgelöst): Alles unten war ursprünglich für ap1 geschrieben und wurde auf den CRS326 Core-Switch ummünzt.Der CRS326 ist aktuell noch Werkszustand — Management-IP/Interface-Zuordnung TBD, §4.3 ist ein Platzhalter.→ überholt:crs326-coreist produktiver L3-Router mit Mgmt10.40.99.1, §4.3 trägt jetzt echte Werte. Grund für den Retarget: TP15-Endstand (kein RB5009, Router bleibt ap1/ap2 rein für L3/WLAN) + TP21s Modell "ganzer Kabel-Fabric via RouterOS" — der CRS326 wird ohnehin Nautobot-verwaltet, ap1 bleibt Public-Edge/WLAN-Anker. Selbst-tragend: eine frische Session kann das mit diesem Doc +docs/cf-tunnel-mapping.mdstraight bauen — vorausgesetzt der CRS326-Bring-up (TP15) und die Nautobot-Adoption (TP21) stehen. SSoT-Kontext:docs/cf-tunnel-mapping.md§13/§14, Memoryproject_cf_tunnel_1033. Härtungs-Delta 2026-07-17 (gilt unabhängig vom Zielgerät): Split-Tunnel auf BEIDEN Profilen (§4.1.4), vnet-Gotcha + Weg B beim Route-Umzug (§4.4), v4-only-Entscheid (IPv6-site-to-site laut Guide broken), Quellen verifiziert (§2). Korrektur: ICMP-Proxy ist bereits AN (fm-Ping10.101.0.0/24beweist es) — kein To-Do, s. §4.1.5.
1. Warum überhaupt / Root Cause
Incident 2026-07-16 (unterwegs): keine BF-IPs über WARP. Diagnose:
- TCP über den CF-WARP-Pfad funktioniert (SSH, alle Web-UIs, MCP-Endpoints erreichbar) —
- ICMP ist strukturell kaputt. Dreiländer-Ping-Befund: fm 36 % Loss (ICMP-Proxy über QUIC-Connector, funktioniert aber mies), bf 100 % (macmini-Connector läuft seit dem http2-Fix von heute = QUIC-los → ICMP-unfähig; zusätzlich cloudflared-Container ohne Ping-Sockets), dw 100 % (192.168.0.0/16 steht in der WARP-Split-Tunnel-Exclude → Pings betreten den Tunnel gar nicht).
Kernursache: cloudflared ist kein WireGuard, sondern ein QUIC/HTTP2-L7/L4-Proxy. ICMP darüber ist
Zusatz-Gefrickel (Account-ICMP-Flag + QUIC-Transport + ping_group_range-sysctl je Host) und war nie
zuverlässig eingerichtet. Der WARP-Client selbst spricht WireGuard — die passende Gegenstelle für einen
sauberen privaten L3-Zugang ist deshalb Cloudflare Mesh (WARP Connector), ebenfalls WireGuard.
2. Entscheidungsweg (was verworfen wurde und warum)
- WG-Roadwarrior (eigene WG-Peers je Gerät): ❌ verworfen — User will KEINE Extra-App/kein Profil pro Gerät. „Ein Client = WARP für alles" bleibt Anforderung.
- Alle ZT-Anbieter mit Helper-Host (CF WARP Connector als Daemon-Host, Tailscale, NetBird, Twingate): brauchen dauerhaft einen Linux-Host → verletzt „Router = einziger SPOF, keine Abhängigkeit zu anderen Rechnern".
- Connector als RouterOS-Container: ❌ nicht möglich — RouterOS-7-Container haben kein
/dev/net/tun- Passthrough; der WARP-Connector-Daemon braucht ein TUN-Device. Gilt auf jeder Router-/Switch-HW (hAP ax²/ax³/CRS326/RB5009 — RB5009 mittlerweile ohnehin nicht mehr geplant, s. TP15). → hAP ax³ löst das NICHT (und ist zudem Wi-Fi 6, nicht 7 — kein WLAN-Gewinn ggü. ax²). HW-Kauf ist vom Tunnel-Fix entkoppelt. - ✅ Gewählt: Cloudflare Mesh als NATIVES WireGuard-Interface auf dem CRS326 Core-Switch (Retarget 2026-07-22, ursprünglich ap1). Cloudflare Mesh spricht WireGuard, RouterOS kann natives WireGuard (der TP10-Hub auf ap1 ist schon einer, Muster überträgt sich). Ein Mesh-Node wird als WG-Peer zu einem CF-PoP registriert — kein Container, kein 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. ICMP/TCP/UDP nativ.
Quelle/Vorlage: animmouse „Setup Cloudflare Mesh on MikroTik" + „Setup Cloudflare Mesh using WireGuard". Ehrliche Einschränkung: von uns noch nicht gebaut — starker, technisch schlüssiger Lead; echter Beweis = bauen+pingen.
✅ Recherche verifiziert (2026-07-17, Primärquellen gelesen + offizielle CF-Docs + OpenAPI-Spec):
- Produkt-Status: „WARP Connector" heißt seit 2026-04-14 offiziell „Cloudflare Mesh" (Rebranding, kein Migrationszwang);
Node-Limit 50/Account; neues Dashboard unter Networking → Mesh (interaktive Map, Route-Config, Setup-Wizard).
Die API-Pfade heißen weiterhin
/accounts/{id}/warp_connector— im OpenAPI-Spec bestätigt: POST (create), GET…/{tunnel_id}/token(Register-Token), dazu sogar HA-Endpoints (…/configurationsactive-passive-Replicas,…/failover) — für uns nicht nötig (ap1 = bewusster SPOF), aber gut zu wissen. - CIDR-Routes für Mesh-Nodes laufen über dieselbe
teamnet/routes-API wie cloudflared (POST {network, tunnel_id: <mesh_node_id>}, Token-ScopeCloudflare One Networks WriteoderCloudflare Tunnel Write) — unserCF_API_TOKEN-Pfad passt. - animmouse-MikroTik-Rezept bestätigt (alle Kommandos gegengelesen, s. §4.3): CF-Wellknown-PublicKey, Endpoint-Substitution
162.159.192.x → 162.159.193.x(Latenz), MTU 1420,100.96.0.0/12 → cf-mesh-Route. Guide nutztpersistent-keepalive=1m(unser Entwurf sagte 25s — beides ok, 25s konservativer hinter NAT; wir sind Public-Edge → 1m reicht). - IPv6-Befund (animmouse): Mesh-site-to-site-IPv6 war beim Guide-Test broken (NAT66-Workaround nötig) → wir bauen bewusst v4-only
(kein v6 auf
cf-mesh, kein NAT66 — BF nutzt intern eh kein v6, s. Memoryproject_ipv6_state). - Sources: Setup Cloudflare Mesh on MikroTik · Setup Cloudflare Mesh using WireGuard · wgcf-connector (GitHub) · CF-Changelog „Introducing Cloudflare Mesh" · CF-Docs Mesh Routes
3. Ist-Stand Account (neu gemessen 2026-08-16, read-only — CF-API + MikroMCP)
Die Messung vom 2026-07-16 ist auf der CF-Seite unverändert geblieben; auf der Geräteseite hat sich alles geändert (Core-Cutover 2026-08-08, Nautobot-Adoption 2026-08-13). Beides unten getrennt.
Cloudflare (alle Werte am 2026-08-16 gegengeprüft, identisch zu 2026-07-16):
- Team-Domain:
emsenhuber.cloudflareaccess.com→ Mesh-Node-Identität =warp_connector@emsenhuber.cloudflareaccess.com - Noch KEIN
warp_connector-Tunnel (GET /accounts/…/warp_connector=[]). Wichtig: der GET antwortet (kein 403) — die Plan-Frage entscheidet sich also erst amPOST(§4.0). devices/settings:use_zt_virtual_ip: false→ Unique-Device-IP weiterhin AUS, muss für Mesh AN.gateway_proxy_enabled: true,gateway_udp_proxy_enabled: true(ICMP-Flag ist Dashboard-only, s. §4.1.5).- Genau EIN Device-Profil (das Default-Profil
0197d1b3-d98a-7c24-b70c-a4d89df7583b,service_mode_v2: warp). ➡️ Der „auf BEIDEN Profilen"-Hinweis in §4.1.4 meint deshalb: Default jetzt, Mesh-Profil sobald es in Schritt 3 angelegt ist — es gibt aktuell kein zweites, auf dem man etwas vergessen könnte. - Split-Tunnel-Modus = Exclude; die Liste enthält weiterhin
100.64.0.0/10(schluckt die Mesh-Overlay-Range100.96.0.0/12) und kein10.0.0.0/8→10.40.0.0/16läuft schon heute über WARP (= warum TCP geht). Nebenbefund:192.168.0.0/16steht drin — das ist die Erklärung für die 100 % Ping-Loss nach dw, unabhängig von diesem TP. - vnet-Route
10.40.0.0/16(vnet1480b545…=vnetemsenhuber, default, Route-ID5546dcb6-5901-4da6-8d91-b17f94703f71) zeigt weiterhin auf cfd_tunnelbf-pve(f7fdf3a6…). Bleibt der Fallback, bis Mesh bewiesen ist — vorher nichts löschen. ⚠️ Neu zu wissen:bf-pvefährt aktuell nur einen Connector (statt zwei, s. TP16-HA-Befund 2026-08-16) — der private Pfad hängt damit heute an einem einzelnen cloudflared-Prozess. Ein weiteres Argument für das Mesh, aber kein Ersatz für die HA-Reparatur der öffentlichen Tunnel. CF_API_TOKENistactive(verify OK). Ob er die separate Permission „Cloudflare One Connector: WARP" trägt, lässt sich nur durch denPOSTin §4.0 feststellen — genau dort schlug es am 2026-07-17 mit10000fehl.
Geräteseite — die alten Zeilen hier waren überholt, Neufassung 2026-08-16:
„CRS326 = Werkszustand, keine WireGuard-Config, keine Management-IP"→ falsch seit dem Core-Cutover.crs326-coreist der produktive L3-Router (RouterOS 7.19.5): Mgmt10.40.99.1(vlan99), Gateway.1in jedem VLAN, WANvlan100mit der öffentlichen90.146.33.177, NAT, DHCP, DNS.„ap1-WireGuard: 1 Interface→ wg-hub liegt seit 2026-08-08 auf dem Core, nicht mehr auf ap1 (listen 51821, MTU 1412, Peerswg-hub"fm10.101.0.0/24 +dw10.95.10.0/24, beide handshaken). Das ist TP10 und bleibt unangetastet — aber es ist jetzt das direkte Vorbild auf demselben Gerät: das Mesh-Interface entsteht daneben, nicht auf einem fremden Blatt.- ✅ Die offene Frage „Rückweg-Routing TBD" aus §4.3 ist damit beantwortet: der Core ist der L3-Router aller
VLANs, Rückverkehr aus
10.40.0.0/16zum Mesh-Interface braucht keine Zusatzroute. crs326-coreist seit 2026-08-13 in Nautobot adoptiert und compliance-verwaltet (68/68) — damit ist das Gate „gated bis TP21 den CRS326 abdeckt" erfüllt.
4. Runbook (nächste Session — Reihenfolge)
4.0 Plan-Probe (billig, reversibel) — ZUERST
POST /accounts/{account_id}/warp_connector {name:"bf-ap1-mesh"} via CF_API_TOKEN (curl/Bearer — der cloudflare-
MCP ist read-only, s. §11 der Mapping-Doc). Erfolgt der Create → Mesh ist im Free-ZT-Plan erlaubt. Scheitert er mit
Plan-/Auth-Fehler → Stopp, Fallback = LXC-auf-pve-WARP-Connector (alter Plan, ebenfalls dokumentiert).
Token danach: GET /accounts/…/warp_connector/{tunnel_id}/token → das ist das eyJhIjoi…In0=-Register-Token.
🔴 STAND 2026-08-16: Plan-Probe erneut ausgeführt — identisch gescheitert, Blocker jetzt vollständig vermessen.
POST /accounts/…/warp_connector {"name":"bf-core-mesh"} → {"success":false,"errors":[{"code":10000, "message":"Authentication error"}]}, HTTP 403. Der Token (455e4f8e…) ist active. Gegenproben mit
demselben Token, um Scope von Plan-Gate zu trennen:
| Endpoint | Methode | Ergebnis | Bedeutet |
|---|---|---|---|
warp_connector |
GET | 200 ([]) |
Endpoint existiert für den Account, Feature nicht wegge-403-t |
warp_connector |
POST | 403 10000 |
⛔ §4.0 — Permission Cloudflare One Connector: WARP fehlt |
cfd_tunnel |
GET | 200 | Cloudflare Tunnel-Scope vorhanden (TP16-Strang unberührt) |
teamnet/routes |
GET | 200 | §4.4-Pfad grundsätzlich da (PATCH-Edit 2026-07-17 bewiesen) |
devices/settings |
GET | 403 9109 |
⛔ NEU: §4.1 ist ebenfalls blockiert — Zero Trust-Scope fehlt |
user/tokens/{id} · tokens/permission_groups |
GET | 403 9109 |
Token kann sich selbst nicht introspizieren → Scope-Liste nur im Dashboard |
⚠️ Der wichtigste neue Befund: das Runbook nannte bisher NUR die eine fehlende Permission (§4.0). Die Probe
zeigt, dass auch §4.1 komplett scheitern würde — devices/settings ist für den Token schon lesend dicht.
Ohne diesen Nachtrag hätte die Scharfschalt-Session den Token zweimal nachziehen müssen. Beides in einem
Edit erledigen.
Gegenprobe, dass es NICHT das Free-Plan-Gate ist: derselbe devices/settings-GET liefert über den
cloudflare-MCP (OAuth, read-only, volle Account-Sicht) sauber 200 mit
{gateway_proxy_enabled:true, gateway_udp_proxy_enabled:true, use_zt_virtual_ip:false}. Der Account kann das
also — nur der Token darf nicht. ➡️ Die Free-Plan-Frage aus §4.0 bleibt damit weiterhin unentschieden: sie
beantwortet sich erst beim Retry des POST mit korrekt gescoptem Token. Erst ein dann immer noch fehlschlagender
POST wäre das Plan-Gate und würde den LXC-Fallback (§6) auslösen.
✅ AUFGELÖST 2026-08-17 — Token neu aufgesetzt, alle Proben 200. Der Weg dahin hatte zwei Stolpersteine, die man kennen muss, weil beide aussehen wie „Token kaputt", es aber nicht sind:
- Der neue Token ist ACCOUNT-OWNED (id
9984078812bc18d4ebb6a64b570144f2, gültig bis 2027-01-09 ⏰). Account-Tokens verifizieren an einem anderen Endpoint:GET /accounts/{account_id}/tokens/verify. ⚠️ Am altenGET /user/tokens/verifyantwortet ein gültiger Account-Token mit1000 "Invalid API Token"/401 — zeitgleich liefern alle echten Endpoints 200. Nicht als abgelaufen fehldeuten. - Dashboard-Fehler
"Account tag in access policy must match tag in request uri"(real erlebt, mehrfach): tritt auf, wenn eine Zone-Permission (hierDNS) in dieselbe Policy-Zeile gepackt wird, die Account- Ressourcen trägt. Zone-Permissions brauchen eine eigene Policy-Zeile mit Zone-Ressourcen. Halb richtig gesetzt = Permission sichtbar, aber jede Zone403, weil keine Zone eingeschlossen ist.
Verifiziertes Soll-Set (alle am 2026-08-17 mit 200 gegengeprüft) — Dashboard sagt „Edit", die API sagt „Write":
| Dashboard | API-Name | Permission-ID | braucht |
|---|---|---|---|
| Cloudflare One Connector: WARP → Edit | Cloudflare One Connector: WARP Write |
5b5c774a5d174ca88d046c8889648b3f |
§4.0 |
| Zero Trust → Edit | Zero Trust Write |
b33f02c6f7284e05a6f20741c0bb0567 |
§4.1 |
| Cloudflare One Networks → Edit | Cloudflare One Networks Write |
e2980d9241cf4939bbbd74fdc43b9651 |
§4.4 |
| Cloudflare Tunnel → Edit | Cloudflare Tunnel Write |
c07321b023e944ff818fec44d8203567 |
TP16 |
| Access: Apps and Policies → Edit | Access: Apps and Policies Write |
— | Bestand |
| Access: Organizations, IdP, and Groups → Edit | … Write |
— | Bestand |
Zone DNS → Edit (emsenhuber.net) |
DNS Write |
— | Tunnel-CNAMEs |
⚠️ Namensfalle: Cloudflare One Connectors Write (Plural, Sammelgruppe) ist nicht die Mesh-Permission.
Ebenso heißt „Cloudflare Tunnel" in neueren Listen zusätzlich „Cloudflare One Connector: cloudflared" — beide
Gruppen existieren parallel. Vollständige Liste (396 Gruppen) via MCP: GET /user/tokens/permission_groups.
Historischer Klickpfad (2026-08-16, vor der Auflösung)
➡️ Was zu tun ist (Dashboard, nur der User — Token-Bearbeitung ist keine Agent-Aktion):
dash.cloudflare.com → My Profile → API Tokens → Token 455e4f8e… → Edit → Account-Permissions ergänzen:
- „Cloudflare One Connector: WARP" → Edit (§4.0:
POST /warp_connector+/token) - „Zero Trust" → Edit (§4.1:
devices/settingsPATCH,devices/policyPOST, Split-Tunnel PUT) - „Cloudflare One Networks" → Edit (§4.4 Routes/vnets — GET geht heute, Edit war 2026-07-17 ok; sicherheitshalber mitnehmen)
Danach neuen Wert nach mcp/cloudflare/.env und ~/.secrets/credentials.env (beide tragen CF_API_TOKEN).
⚠️ Token-Permission-Gotcha (2026-07-17, real erlebt — Ursachenanalyse, weiterhin gültig): POST /warp_connector schlug mit code 10000 "Authentication error" (HTTP 403) fehl, obwohl der CF_API_TOKEN gültig ist und teamnet/routes PATCHen kann.
Ursache: Cloudflare hat beim WARP-Connector→Mesh-Rebranding (2026-04-14) eine eigene, separate Permission-Group
eingeführt — Cloudflare One Connector: WARP (Read/Edit) — „Grants write access to Cloudflare Mesh nodes". Das ist
nicht dasselbe wie Cloudflare Tunnel Write (nur für cloudflared) oder Cloudflare One Connectors Write
(Sammel-Permission, deckt aber laut Doku nicht zuverlässig Mesh ab). Verifiziert gegen
developers.cloudflare.com/fundamentals/api/reference/permissions/ (aktuelle Tabelle, nicht die älteren
tunnel-spezifischen Doc-Seiten, die noch die alten Namen zeigen). Im Token-Editor unter Account-Permissions nach
„Cloudflare One Connector: WARP" suchen (nicht „Tunnel"), Edit wählen. Für §4.4 zusätzlich
„Cloudflare One Networks" → Edit (Routes/vnets).
4.1 CF-Prerequisites — ✅ ERLEDIGT 2026-08-17, bis auf einen Dashboard-Klick
| Schritt | Stand |
|---|---|
| 1. Unique Device IP | ✅ use_zt_virtual_ip: true gesetzt (PATCH devices/settings) |
| 2. „Allow all Cloudflare One traffic to reach enrolled devices" | ✅ entschieden: bleibt AUS — nicht nötig (s.u.) |
| 3. Device-Profil „Cloudflare Mesh" | ✅ 4d3c0f57-a717-49ac-ab92-b420e33e6380, match identity.email == "warp_connector@emsenhuber.cloudflareaccess.com", tunnel_protocol=wireguard, precedence 100 |
| 4. Split-Tunnel-Exclude | ✅ auf beiden Profilen: 100.64.0.0/10 raus, 100.64.0.0/11 + 100.112.0.0/12 rein (14→15 bzw. 16→15 Einträge) |
| 5. ICMP-Proxy | ✅ war schon an, nichts zu tun (s. §4.1.5) |
✅ Schritt 2 — recherchiert 2026-08-17, Entscheid: bleibt AUS. Die CF-Settings-Referenz führt ihn unter „Global device client settings" (also global, nicht per Profil — die Mesh-Get-Started-Seite behauptet das Gegenteil, die Docs widersprechen sich). Verfügbar in allen Plänen, alle OS, Client-Mode „Traffic and DNS". Was er tut: er lässt Traffic aus Mesh/WAN zu den eingebuchten Geräten hin — Zugriff auf Device-IPs, also die Client↔Client-Richtung. Unser Anwendungsfall ist die andere Richtung (Gerät → Mesh-Node →
10.40.0.0/16), und der funktioniert bewiesenermaßen ohne ihn (§4.5). Die CF-Docs nennen keinen Menüpfad, und es gibt kein API-Feld (Spec,devices/settings-PATCH und Profil-GET gegengeprüft). Nach User-Vorgabe „im Zweifel ohne Schalter" nicht gesetzt. Erst dann relevant, wenn Zugriff auf ein Endgerät statt auf das Netz gebraucht wird.
Ursprüngliche Handlungsanweisung (vor der Recherche)
🔴 Schritt 2 ist der einzige verbliebene Handgriff und NUR im Dashboard machbar. Weder
PATCH /devices/settingsnochPOST /devices/policykennen ein entsprechendes Feld — im OpenAPI-Spec und in der GET-Antwort des Default-Profils taucht es nicht auf (gegengeprüft 2026-08-17). Es verhält sich damit genau wie das ICMP-Flag: Dashboard-only. CF-Docs führen es als Mesh-Prerequisite („Mesh connectivity"), es ist also nicht optional. Pfad: Team & Resources → Devices → Device settings → Profil → „Allow all Cloudflare One traffic to reach enrolled devices" einschalten. ⚠️ Laut CF-Doc ist das eine Profil-Einstellung — unser Runbook führte sie fälschlich als Account-Einstellung („gleiche Seite" wie Unique Device IP).
4.7 Mgmt-ACL via Golden Config auf alle vier Geräte — ✅ ERLEDIGT 2026-08-17, 72/72 compliant
Der /ip service-Fix aus §4.5 war zunächst nur am Core und direkt gesetzt. Nachgezogen als sauberer
GC-Rollout auf alle vier Geräte.
Der Befund war das Gegenteil der Erwartung. §4.5 schloss mit „für branch/ap1/ap2 noch offen — die
haben eigene /ip service-Beschränkungen". Falsch: sie hatten gar keine — ssh, www, winbox,
api, ftp, telnet alle aktiv und ohne Address-Beschränkung. Die dynamischen Einträge zeigten sogar
REMOTE 100.96.0.1, waren also längst per Mesh erreichbar. Und winbox war auf allen vier offen, auch am
Core. Damit wurde aus dem erwarteten Erreichbarkeits-Fix eine Härtung.
| 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 |
- Neue Compliance-Feature
ip-service(match_config=/ip service,config_type=cli,config_ordered=false) → 17→18 Regeln, 68→72 Checks. Ohne die Regel stünde die ACL zwar im Template, würde aber nie verglichen — der Rollout wäre nicht durchsetzbar. - Ablauf regelkonform:
/system backupauf allen Zielen →--job mgmt-acl(Dry-Run) →--apply --no-deploy→ gestaffelter Deploy: erstap2, am Gerät gegengeprüft, dannap1/branch/core→ Geräte-Gegenprobe →--refresh-compliance. - Kein Lockout-Risiko: der Deploy läuft von Nautobot (
10.40.20.30) aus, also aus10.40.0.0/16— in jeder gesetzten ACL enthalten. RouterOS wendetaddress=ohnehin erst auf neue Verbindungen an. - ⚠️ Scope-Erweiterung, bewusst:
ftp/telnet/api-sslauf branch/ap1/ap2 abgeschaltet. Die Alternative wäre gewesen, „telnet aktiv" als Sollzustand in die SoT zu schreiben. Nichts hier nutzt sie (der ALLNET-Telnet-Runner ist Archiv, das Gerät ausgebaut). - 📌 Schreibweise:
/ip service set ssh …mit dem Dienstnamen, NICHT[find name=ssh]— letzteres trifft auch den dynamischen Verbindungs-Eintrag →failure: this is configured elsewhere. - 🧪 Mess-Falle am Rande:
[/ip service get … address]in einem:put-Ausdruck verketten erzeugt bei zwei ACL-Einträgen das Kreuzprodukt (16 Zeilen statt 1) —addressist eine Liste. Zum Prüfen/ip service print detailnehmen, nicht String-Verkettung.
Job liegt als mgmt-acl in nautobot/gc-configplan.py (idempotent, wiederholbar).
📎 Nachtrag zu Schritt 3/4 aus den CF-Docs (gelesen 2026-08-17): CF empfiehlt für Mesh-Nodes eigentlich ein Profil im Include-Modus mit
100.96.0.12— das gilt für Nodes, die den Cloudflare One Client fahren. Unser Node ist natives RouterOS-WireGuard und konsumiert überhaupt kein Device-Profil; für ihn zählt ausschließlich die Routing-Config aus §4.3. Das Profil legen wir trotzdem an (Guide-konform, schadet nicht). Relevant ist die Exclude-Korrektur für die Client-Geräte (MacBook/iPhone) — und die ist gesetzt.
Ursprüngliche Schrittliste
4.1 CF-Prerequisites setzen (⚠️ account-weit, trifft LIVE-Geräte → 1× kurzer WARP-Reconnect einplanen)
- Unique Device IP AN:
PATCH /accounts/…/devices/settings {use_zt_virtual_ip:true}(Dashboard: Team & Resources → Devices → Management → „Assign a unique IP address to each device"). - „Allow all Cloudflare One traffic to reach enrolled devices" AN (gleiche Seite).
- Device-Profile „Cloudflare Mesh" anlegen: Match
identity.email == warp_connector@emsenhuber.cloudflareaccess.com, Tunnel-Protokoll = WireGuard (POST /accounts/…/devices/policy). - Split-Tunnel-Exclude anpassen (
PUT /accounts/…/devices/policy/exclude— ⚠️ ersetzt die GANZE Liste, erst GET, dann editiert zurückschreiben):100.64.0.0/10raus, dafür100.64.0.0/11+100.112.0.0/12rein (= 100.64/10 minus 100.96/12 → Mesh-Overlay100.96.0.0/12läuft nun durch WARP statt als „local" behandelt zu werden). ⚠️ Auf BEIDEN Profilen (Default und dem neuen „Cloudflare Mesh"-Profil aus Schritt 3 — per-Profile-Endpoint…/devices/policy/{policy_id}/exclude); animmouse macht das explizit auf beiden. - ICMP-Proxy — ✅ bereits AN, KEIN To-Do (Korrektur 2026-07-17, User): Die offiziellen Mesh-Docs listen „Gateway proxy
mit TCP, UDP, ICMP" als Prerequisite. TCP+UDP sind an (
gateway_proxy_enabled/gateway_udp_proxy_enabled=true); ICMP ist ebenfalls schon angehakt — Beweis:pingins FM-Netz10.101.0.0/24funktioniert (über den fm-QUIC-Connector). Das ICMP-Flag ist nur nicht im public OpenAPI-Spec sichtbar (Dashboard-only), daher hatte ich es fälschlich als „fehlt" geführt. → Nichts zu klicken. Dass bf-Ping im Incident 100 % verlor lag NICHT am Flag, sondern daran, dass die macmini-Connectoren nach dem http2-Fix QUIC-los sind (cloudflared-ICMP-Proxy braucht QUIC). Mit dem nativen WG-Mesh-Node ist ICMP ohnehin nativ (kein Gateway-ICMP-Proxy im Pfad). Trotzdem: nach dem Scharfschalten Ping gegengeprüft (§4.5) — falls wider Erwarten doch tot, hier zuerst schauen.
4.4 Route-Umzug — ✅ ERLEDIGT 2026-08-17, Weg A hat funktioniert
PATCH /teamnet/routes/5546dcb6-5901-4da6-8d91-b17f94703f71 {tunnel_id: d1da7c8a-…} → success: true.
Der befürchtete vnet-Gotcha ist NICHT eingetreten — CF hat den PATCH auf einen warp_connector-Tunnel
anstandslos angenommen, obwohl die Route am vnet 1480b545… hängt. Weg B (DELETE+POST) war nicht nötig und
bleibt nur als Fallback dokumentiert. 10.40.0.0/16 zeigt jetzt auf bf-core-mesh statt auf bf-pve.
Rollback unverändert 1 PATCH zurück auf f7fdf3a6… — bf-pve läuft weiter, nichts gelöscht.
4.2 WireGuard-Config extrahieren (einmalig, ephemer) — ✅ erledigt 2026-08-17
As-built: gelaufen in LXC 400 auf pve (x86_64; der macmini ist arm64 — bei den cloudflared-Connectoren hatten wir dort schon eine arm64-Leiche). Ergebnis s. §4.3. Der
.confmit dem PrivateKey wurde nach dem Auslesen auf dem LXC geshreddert (shred -u) — der Schlüssel liegt jetzt nur noch inmcp/cloudflare/.env(CF_MESH_PRIVKEY, gitignored,chmod 600) und am Gerät.
Auf macmini oder pve (Docker vorhanden):
docker run --rm -v $(pwd):/app/output ghcr.io/animmouse/wgcf-connector <REGISTER_TOKEN>
→ erzeugt wgcf-connector-<registration_id>.conf mit: PrivateKey, Address (100.96.x.y/32 + eine IPv6 —
ignorieren, wir bauen v4-only), DNS (CF-Resolver — ignorieren, ap1 hat eigenes DNS), MTU 1420, Peer-PublicKey
(= CF-Wellknown bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=), Endpoint (162.159.193.x:2408).
Registriert den Node via CF-API (macht Netz-Call), läuft danach nie wieder. PrivateKey nach mcp/cloudflare/.env
o. ~/.secrets (nicht committen).
4.3 crs326-core nativ konfigurieren — ✅ AS-BUILT 2026-08-17
Ist-Stand am Gerät (verifiziert):
| Interface | cf-mesh, MTU 1420, running, listen-port 13279 (auto) |
| PublicKey (Gerät) | vGkiAuQt8iHGtNkllTxMxjlgQhN9RtSTjC8qHwnccAw= |
| Mesh-IP | 100.96.0.6/32 (v4-only, die mitgelieferte v6 2606:4700:cf1:1000::6/128 bewusst ignoriert) |
| Peer | bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo= @ 162.159.193.2:2408, allowed 0.0.0.0/0, keepalive 25s |
| Handshake | ✅ steht (last-handshake < 10s, rx/tx laufen) |
| Route | 100.96.0.0/12 → cf-mesh, Flags A s (active/static) |
| Registrierung | reg_id 01a00f2d-2316-12f6-90f6-c3f344469fb3, CF-Node-Status healthy, 1 Connection |
| Backup vor dem Eingriff | pre-tp16.1-mesh-20260817.backup (Auflage Ausnahme #4 ✅) |
Endpoint-Hinweis erledigt: die Config lieferte direkt 162.159.193.2 — die im Guide beschriebene
Substitution 162.159.192.x → 162.159.193.x war nicht nötig.
⚠️ Zwei Werkzeug-Fallen, beide real getroffen — für die nächste WG-Arbeit wichtig:
- MikroMCPs
manage_wireguard_interfacekann prinzipiell KEINEN privaten Schlüssel annehmen („RouterOS generates the private key on create — it is never passed in"). Bei CF Mesh kommt der Key aber von CF — das Tool ist für diesen Fall also strukturell ungeeignet. Weg:sshpass+SSH mit$CF_MESH_PRIVKEYaus der gitignoreten.envinterpoliert, damit der Schlüssel weder durch den Agent-Kontext noch ins MCP-Journal wandert; Fehlerausgabe vorher durchsedmaskieren (Memoryfeedback_redact_router_passwords_in_tracebacks). Peer/IP/Route liefen danach regulär überplan_changes→apply_plan.manage_wireguard_peerverarbeitetendpoint: "IP:Port"falsch: es schreibt den ganzen String nachendpoint-addressund lässtendpoint-port=0→ kein Handshake, rx/tx bleiben 0. Das sieht aus wie ein Netz-/Firewall-Problem, ist aber ein Parameter-Bug. Fix:/interface/wireguard/peers/set [find …] endpoint-address=<IP> endpoint-port=<Port>. Nach jedem Peer-Add per MikroMCPprint detailgegenlesen.- Ebenso ohne Parameter im Tool:
persistent-keepalive→ separat perrun_commandsetzen.
Ursprünglicher Plan (Stand 2026-08-16)
Der frühere Platzhalter-Vorbehalt („Management-IP/Interface-Zuordnung fehlt") ist erledigt: Zielgerät ist
crs326-core(Mgmt10.40.99.1, MikroMCP-routerIdcrs326-core). Offen bleibt nur, was erst zur Laufzeit existiert: der PrivateKey und die100.96.x.y-Adresse aus §4.2.
/interface wireguard add name=cf-mesh mtu=1420 private-key="<PrivateKey aus .conf>" comment="TP16.1 Cloudflare Mesh"
/interface wireguard peers add interface=cf-mesh name=cf-pop \
public-key="bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=" \
endpoint-address=162.159.193.1 endpoint-port=2408 \
allowed-address=0.0.0.0/0,::/0 persistent-keepalive=25s
/ip address add address=<100.96.x.y>/32 interface=cf-mesh comment="TP16.1 Mesh-Overlay"
/ip route add dst-address=100.96.0.0/12 gateway=cf-mesh comment="TP16.1 Mesh"
- Endpoint: falls die Config
162.159.192.xliefert →162.159.193.xnehmen (Latenz-Tuning laut Guide). - MTU: 1420 aus dem Guide. Direkter Vergleichswert steht jetzt auf demselben Gerät:
wg-hubläuft mit 1412. Bei Path-MTU-Symptomen (TCP baut auf, große Transfers hängen) zuerst auf 1412 angleichen. - ✅ Rückweg-Routing — erledigt, keine Zusatzarbeit.
crs326-coreist der L3-Router aller VLANs (vlan10/20/30/40/50/90/99mit.1), Rückverkehr nach10.40.0.0/16läuft also ohne Zusatzroute. Das war beim ursprünglichen CRS326-Retarget die einzige echte Unbekannte. - Namenskollision vermeiden: auf dem Gerät existiert bereits
wg-hub(TP10). Das neue Interface heißtcf-mesh— ⚠️ Bindestrich inname=hat RouterOS beim GC-Push schon einmal abgelehnt (Memoryref_gc_push_gotchas_routeros); beim Direkt-Write über MikroMCP war das nie ein Problem, aber falls die Zeilen später doch durch die GC laufen, istcfmeshder sichere Name. - Firewall: die
forward-Kette endet derzeit ohne Drop (TP5 steht aus) → der Mesh-Verkehr passiert ohne Zutun. ⚠️ Für TP5 vormerken: sobald deny-by-default greift, braucht es explizitforward accept 100.96.0.0/12 ↔ 10.40.0.0/16, sonst kappt die Firewall den privaten Zugang. Gehört in die TP5-Whitelist, nicht hierher. - ✅ Governance — Ausnahme #4 erteilt (User, 2026-08-16). Die frühere Zeile („läuft regulär über Nautobot GC")
trägt nicht mehr: TP22-Regel 1 schließt jede Sektion mit
<<REDACTED>>generell vom Push aus, und/interface wireguardist genau so eine Sektion — ein Privkey ist über GC gar nicht deploybar. Diese vier Zeilen dürfen daher direkt (MikroMCPplan_changesdryRun →apply_plan). Auflage wie bei Ausnahme #2: danach Ist-Stand als intended config zurück nach Nautobot. Scope: nur der Mesh-Bring-up aufcrs326-core, nicht spätere WG-Änderungen, nicht andere Geräte. Vorher/system backup(TP22-Regel 3).
Und wie hält man Secrets langfristig aus der Config raus?
Die Ausnahme soll ein einmaliger Bootstrap bleiben, kein Dauerzustand. Der Denkfehler, den man vermeiden muss, ist, einen privaten Schlüssel als Konfiguration zu behandeln — er ist Geräte-Identität, wie ein SSH-Hostkey. Die branchenübliche Regel:
Der private Teil entsteht auf dem Gerät und verlässt es nie. Nur der öffentliche Teil geht in die Source of Truth — und wird von dort in die Configs der Gegenstellen gerendert.
| Was | Klasse | Wo verwaltet |
|---|---|---|
| PrivateKey | Geräte-Identität | nur am Gerät — nie in Git, nie in der intended config, nie in einem ConfigPlan |
| PublicKey | öffentliche Information | Nautobot (Custom Field/Data) → in die Peer-Configs gerendert |
listen-port, mtu, comment, Peers, allowed-address, Routen, Firewall |
Konfiguration | Golden Config, ganz normal |
RouterOS unterstützt das direkt: /interface wireguard add erzeugt den Privkey selbst, print gibt den
Pubkey aus. Compliance bleibt trotzdem grün, weil die ConfigReplace-Regel aus TP22 Schritt 0 den Privkey im
Backup auf byte-identisch dieselbe Maske normalisiert, die das Template emittiert.
⚠️ Vorbehalt genau hier: bei Cloudflare Mesh erzeugt CF das Schlüsselpaar (§4.2 holt es per wgcf-connector).
Wenn der Flow keinen eigenen Pubkey akzeptiert, fällt die On-Device-Erzeugung weg — das Prinzip („nie in Git, nie
in der intended config") hält trotzdem, der Key wird dann einmalig eingespielt und lebt danach nur am Gerät.
Stufe 2, falls Secrets doch verwaltet werden müssen (mehr Geräte, Rotation, PSKs): nautobot-secrets-providers
nachinstallieren (Vault/AWS SM/Azure KV/1Password; Core kann schon Env-Var + Text-File) und den echten Wert erst
bei der ConfigPlan-Erzeugung einsetzen — gespeicherte intended config behält den Platzhalter, der Plan wird
nach dem Deploy gelöscht. Preis: Klartext liegt transient in Postgres, braucht Retention-Disziplin. Bei vier
Geräten und einem Key lohnt das nicht; das ist ein TP für die Zeit nach TP18/TP20.1.
(Nicht verwechseln: CredentialsNautobotSecrets + SecretsGroup „RouterOS Nornir" sind schon im Einsatz — das
sind die Login-Credentials für Nornir, nicht Secrets im Config-Inhalt.)
Sofort fälliger Modellierungs-Nachzug, unabhängig vom Mesh: die WG-Peers fm und dw stehen heute mit
hartkodierten public-key="…"-Werten im Jinja-Template (nautobot/mikrotik_routeros.j2). Public Keys sind Daten,
keine Templatezeilen — die gehören nach Nautobot und von dort gerendert.
4.4 Subnetz-Route + vnet-Route umziehen
- Ziel: die CIDR-Route
10.40.0.0/16zeigt auf den neuen Mesh-Node statt aufbf-pve. - Weg A (zuerst versuchen):
PATCH /accounts/…/teamnet/routes/5546dcb6… {tunnel_id: <warp_connector_id>}— gleicheteamnet/routes-API wie cloudflared, per CF-Docs auch für Mesh-Nodes gültig. - ⚠️ Neu-Fund vnet-Gotcha: CF-Docs sagen „Virtual networks are only supported for cloudflared tunnels" —
unsere Route hängt am vnet
1480b545…(vnetemsenhuber, ist aber das default-vnet des Accounts). Möglich, dass der PATCH auf einenwarp_connector-Tunnel deshalb mit 4xx abgelehnt wird. Weg B (Fallback):DELETEder alten Route5546dcb6…+POST /teamnet/routes {network:"10.40.0.0/16", tunnel_id:<mesh_node_id>}ohne vnet-Angabe (landet im default). Kurze Lücke (Sekunden) dazwischen ist ok — Reihenfolge DELETE→POST zwingend (CIDR-Kollision verhindert POST-vor-DELETE). - Rollback jederzeit: PATCH (bzw. DELETE+POST) zurück auf
f7fdf3a6…(bf-pve) — cloudflared/bf-pve bleibt die ganze Zeit bestehen. Wichtig fürs Remote-Arbeiten: alle CF-API-Writes laufen über die öffentliche API (api.cloudflare.com), NICHT über WARP → Rollback funktioniert auch, wenn der private Pfad gerade tot ist.
4.5 Verifikation — ✅ BESTANDEN 2026-08-17 (MacBook am iPhone-Hotspot, WARP connected)
Ping — der eigentliche Zweck des TPs. Vorher 100 % Loss, jetzt:
| Ziel | VLAN | Loss | avg RTT |
|---|---|---|---|
10.40.10.1 |
10 | 0 % | 47 ms |
10.40.20.105 (HA) |
20 | 0 % | 56 ms |
10.40.99.12 (ap2) |
99 | 0 % | 57 ms |
10.40.20.10 (NAS) |
20 | 0 % | 63 ms |
10.40.99.1 (core) |
99 | 0 % | 58 ms |
TCP-Gegenprobe (echter Datenfluss, nicht nur Connect): https://10.40.20.100:8006 → 200 ·
http://10.40.20.30:8080 → 302 · ssh macmini → ok. FQDN-Smoke (gitea/hass/pve/nautobot/vw über
*.emsenhuber.net): 200/200/302/302/200 in 0,2–0,3 s → der cloudflared-Public-Teil blieb unberührt.
(10.40.20.10:5000/5001 antwortet nicht — die DSM-Web-Ports lauschen dort schlicht nicht; SSH und 443 auf
demselben Host sind offen. Kein Mesh-Befund.)
🔴🔴 DIE FALLE DIESES TPs —
/ip servicesperrt das Router-Management aus dem Mesh aus.Unmittelbar nach dem WARP-Connect war
crs326-coremgmt-seitig tot: MikroMCP brach mitConnection lost before handshakeab, SSH mitkex_exchange_identification: Connection reset, REST mit HTTP 502 — während Ping zu genau derselben IP verlustfrei lief und alle Hosts hinter dem Core (pve, Nautobot, macmini) normal antworteten.Ursache: auf dem Core steht
/ip service set ssh,www address=10.40.0.0/16. Der Mesh-Client kommt aus100.96.0.0/12und fällt aus der ACL. ICMP kennt keine Service-ACL → geht. Undnc -zmeldete „offen", weil der CF-Gateway-Proxy den TCP-Handshake terminiert, bevor das Origin überhaupt antwortet — ein TCP-Connect ist über WARP also kein Reachability-Beweis.Fix:
/ip service set [find name=ssh] address=10.40.0.0/16,100.96.0.0/12(analogwww). Danach SSH und REST über den Mesh sauber. Merkregel: wer per Mesh ans Netz kommt, ist noch lange nicht am Router. Jede Mgmt-ACL, die auf10.40.0.0/16steht, muss die Mesh-Range mitnehmen — fürcrs326-branch/ap1/ap2ist das noch offen (die haben eigene/ip service-Beschränkungen).⚠️ Zwei Fehlspuren, die ich unterwegs verfolgt habe und die man sich sparen kann: (1) MTU — große Pings ab ~1350 B scheitern, das ist aber das WARP-Client-Interface (
utunMTU 1380), nichtcf-mesh; normaler TCP-Verkehr ist davon nicht betroffen. (2) SSH-Session-Erschöpfung — naheliegend beiConnection reset, war es aber nicht. Der Test, der es entschied: Banner-Grab vom macmini aus (nc 10.40.99.1 22→SSH-2.0-ROSSSH) — von innen gesund, also Pfad/ACL statt Gerät.ℹ️ Nebenbefund beim Setzen:
/ip service set [find name=ssh] …trifft auch den dynamischen Verbindungs-Eintrag (D c ssh … local 10.40.99.1) und quittiert mitfailure: this is configured elsewhere. Harmlos — der statische Eintrag wird trotzdem gesetzt. Nicht als Fehlschlag werten.
4.6 Auflage Ausnahme #4 — ✅ ERLEDIGT 2026-08-17: Ist-Stand ist intended config, 68/68 compliant
Ablauf: --refresh-compliance zeigte zuerst 65/68 mit drei extra-Drifts (interface-wireguard,
ip-address, ip-route) — exakt die Mesh-Zeilen. Die Zeilen byte-genau aus dem Nautobot-Backup (nicht aus
dem Runbook!) ins Jinja-Template übernommen, ins GC-Repo bf-golden-config gepusht, Repo-Sync, erneut
compliance: 68/68, keine Drifts.
- Der Privkey bleibt draußen: das Template emittiert
private-key="<<REDACTED>>"— byte-identisch zurConfigReplace-Maske aus TP22 Schritt 0, genau wie beiwg-hub. Secret-Gegenprobe vor jedem Push gelaufen. - ⚠️ Gotcha beim Push: Nautobot schreibt Backups und intended configs in dasselbe Repo → der zweite
Push wurde
rejected (fetch first), weil die Compliance-Läufe dazwischen committen.git pull --rebasevor jedem Push einplanen. /ip servicesteht nicht im Template → die ACL-Erweiterung erzeugt keine Drift, ist damit aber auch nicht in der SoT abgebildet. Bewusst so belassen; gehört zu TP5, wenn die Mgmt-Ebene modelliert wird.
Ursprüngliche Abnahme-Kriterien
4.5 Verifikation (Abnahme)
- MacBook, WARP connected:
ping 10.40.20.105,ping 10.40.10.1,ping 10.40.99.12→ verlustfrei (Regressions-Gegenprobe zu heute: fm 36 % / bf 100 %). - TCP-Gegenprobe inkl. NAS-macvlan-IP direkt:
ssh 10.40.20.167,https://10.40.20.100:8006,10.40.20.157:3000(gitea) mehrfach → Beweis „keine Blindheit". - FQDN-Smoke (Stichprobe gitea/hass/pve über
*.emsenhuber.net) → der cloudflared-Public-Teil (3-Tunnel-HA) blieb unberührt.
5. Danach (Cleanup, teils ins „vertagt"-Gespräch)
- Nach Mesh-Beweis:
warp-routingauf bf-nas/bf-pve/bf-mm ggf. auffalse(Hygiene — Public-Tunnel bedienen keine privaten Netze mehr). CF-vnet-Route-Historie bereinigen. - Vertagt (User „müssen wir noch reden, hat Zeit"): 4 tote Tunnel (TeilzeitCharlie/coolify/johnny2/openclaw),
Ghost-Connector-Session bf-pve (arm64-Leiche vom 12.07.),
gateway-dw-CNAME.
6. Risiken / Fallbacks
- Einziger Eingriff mit Nutzer-Impact = vnet-Route-Umzug → Rollback = 1 PATCH zurück auf bf-pve.
- CF-Prerequisites sind account-weit (Unique-IP-ReIP, Split-Tunnel) → 1× kurzer WARP-Reconnect; alle reversibel.
- Plan-Gate: wenn
warp_connector-Create scheitert → LXC-auf-pve-WARP-Connector als Fallback (TUN-Passthroughc 10:200 rwm,warp-cli connector new, ap1-Static-Route100.96.0.0/12→LXC). - ax³/ZeroTier/Tailscale = separate Eval-Fußnoten, nicht Teil dieses Fixes.
Nachtrag 2026-08-25 — „Connector als RouterOS-Container ❌" galt dem TUN-Bedarf, nicht jedem Container
§2 schließt „Connector als RouterOS-Container" aus, weil RouterOS-7-Container kein /dev/net/tun
durchreichen und der WARP-Connector-Daemon ein TUN-Device braucht. Das stimmt weiterhin — für den
WARP-Connector.
🔴 Es wurde damals aber nicht getrennt, und die Verallgemeinerung hat sich festgesetzt:
cloudflared braucht kein TUN. Es ist ein Userspace-HTTP/QUIC-Proxy und läuft in einem
RouterOS-Container problemlos — auf arm64 oder x86, container-Paket und device-mode vorausgesetzt.
Live gemessen 2026-08-25: ap1/ap2 sind arm64 mit 95 MB freiem Flash und 690 MB freiem RAM
— genug für einen Connector. crs326-core ist arm 32-bit mit 2,9 MB frei von 16 MB und kommt für
Container nie in Frage.
⇒ Die Zeile „verletzt Router = einziger SPOF, keine Abhängigkeit zu anderen Rechnern" trug für den privaten Strang — für den öffentlichen hat sie nie jemand geprüft. Genau das holt TP31 nach.