- RB5009 final gestrichen (User-Entscheid 2026-07-22) — Router bleibt ap1/ap2, Referenzen in teilprojekte.md + hw-refresh-requirements.md bereinigt. - TP16.1 Ziel-Device von ap1 auf CRS326 Core-Switch retargeted (Doku-only, Scharfschalten bleibt gated bis TP21 den CRS326 abdeckt), Runbook umbenannt auf tp16.1-warp-mesh-native-crs326.md, cf-tunnel-mapping.md §14 + Handoff- Prompt mitgezogen. - TP21: docs/nas-vlan20/nautobot-image/ neu — der Dockerfile/nautobot_config.py/ allnet_sg8316m_driver.py, aus denen das laufende Custom-Image tatsächlich gebaut ist (der bisherige Verweis auf scratch/nautobot-gc-build existierte nirgends). Ergänzt napalm-ros + nornir-napalm + librouteros + gepinntes setuptools<81 (pkg_resources-Regression), Nornir-Credentials auf CredentialsNautobotSecrets umgestellt, Compliance/Intended-Config/SoT-Agg aktiviert. Backup/Intended/Compliance-Pipeline live gegen ap1 verifiziert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
17 KiB
TP16.1 — Private Access via native Cloudflare Mesh (WARP Connector) auf dem CRS326 Core-Switch
Status: Konzept + Runbook fertig (2026-07-16), Recherche verifiziert + Runbook gehärtet (2026-07-17), Ziel-Device retargeted von ap1 auf CRS326 (User-Entscheid 2026-07-22), Scharfschalten = eigene Session, gated bis TP21 den CRS326 abdeckt. ⚠️ Retarget-Hinweis (2026-07-22): Alles unten war ursprünglich für ap1 geschrieben und ist jetzt auf den CRS326 Core-Switch ummünzt. Der CRS326 ist aktuell noch Werkszustand — die konkrete Management-IP/Interface-Zuordnung für den WG-Mesh-Node ist noch nicht getroffen (TBD nach TP15-Bring-up). §4.3 (Config-Befehle) ist deshalb ein Platzhalter, keine ausführungsreifen 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 (gemessen 2026-07-16, read-only)
- Team-Domain:
emsenhuber.cloudflareaccess.com→ Mesh-Node-Identität =warp_connector@emsenhuber.cloudflareaccess.com - Noch KEIN
warp_connector-Tunnel im Account (GET /accounts/…/warp_connector= []). - Device-Settings:
use_zt_virtual_ip: false(Unique-Device-IP AUS — muss für Mesh AN). - Split-Tunnel-Modus = Exclude; Exclude-Liste enthält u.a.
100.64.0.0/10(schluckt die Mesh-Overlay-Range100.96.0.0/12→ Mesh-Traffic würde aktuell NICHT durch WARP gehen). Enthält NICHT10.0.0.0/8→ deshalb geht10.40.0.0/16schon heute über WARP (= warum TCP funktioniert). - vnet-Route
10.40.0.0/16(vnet1480b545…, Route-ID5546dcb6-5901-4da6-8d91-b17f94703f71) zeigt aktuell auf cfd_tunnelbf-pve(f7fdf3a6…). Das bleibt der Fallback, bis Mesh bewiesen ist — nichts vorher löschen. - ap1-WireGuard IST-Stand (bleibt unverändert, unabhängig vom Retarget): 1 Interface
wg-hub(listen 51821, MTU 1412), Peersfm(10.101.0.0/24) +dw(10.95.10.0/24) — das ist TP10, nicht Teil dieses TPs. - CRS326 IST-Stand (Retarget-Ziel): Werkszustand, noch keine WireGuard-Config, keine Management-IP zugewiesen — das neue Mesh-Interface (outbound zum CF-PoP, kein Listen-Port) entsteht dort auf einem sauberen Blatt, sobald der CRS326-Bring-up (TP15: Management-IP, VLAN-Filtering) steht.
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.
⚠️ Token-Permission-Gotcha (2026-07-17, real erlebt): 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 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.2 WireGuard-Config extrahieren (einmalig, ephemer)
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 nativ konfigurieren ⚠️ PLATZHALTER — noch NICHT ausführungsreif
Dieser Block war ursprünglich für ap1 geschrieben (per MikroMCP
plan_changesdryRun →apply_plan). Nach dem Retarget auf den CRS326 (2026-07-22) fehlen noch: die Management-IP/Interface-Zuordnung des CRS326 (TP15-Bring-up), und der Zugriffsweg für Config-Changes ist dann Nautobot Golden Config (TP21), nicht mehr MikroMCP direkt (die ap1-Ausnahme gilt für den CRS326 nicht). Die folgenden Zeilen zeigen nur das Muster (identisch zur RouterOS-Syntax),<CRS326-INTERFACE>und die konkreten IP-Werte müssen nach dem Bring-up final werden:
/interface wireguard add name=cf-mesh mtu=1420 private-key="<PrivateKey aus .conf>"
/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
/ip route add dst-address=100.96.0.0/12 gateway=cf-mesh
- Endpoint: falls die Config
162.159.192.xliefert →162.159.193.xnehmen (Latenz-Tuning laut Guide). - MTU 1420 aus dem Guide; gegen die TP10-Hub-MTU 1412 (auf ap1, zum Vergleich) gegenprüfen (ggf. angleichen bei Path-MTU-Problemen).
- Rückweg-Routing TBD: ob der CRS326 selbst L3 für alle VLANs braucht oder nur als Mesh-Endpoint mit einer Route zurück zu ap1 (dem weiterhin bestehenden L3-Router) fungiert, ist Teil der TP15-Bring-up-Entscheidung — anders als beim ursprünglichen ap1-Plan (der war automatisch L3-Router aller VLANs) ist das beim CRS326 nicht automatisch gegeben.
- Firewall: abhängig vom dann geltenden Firewall-Stand (TP5) — Accept
100.96.0.0/12 ↔ 10.40.0.0/16ggf. gezielt ergänzen. - Governance: „Config nur via Nautobot" (TP21) → diese CRS326-Zeilen laufen regulär über Nautobot GC, sobald
das Device dort adoptiert ist — die ap1-Ausnahme gilt hierfür nicht (s.
teilprojekte.mdIst-Stand-Zeile 31).
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 (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.