CF/#1033 📄 CF-Tunnel-Mapping (SSoT) + cloudflare-MCP-Scaffold
- docs/cf-tunnel-mapping.md: Single Source of Truth zur #1033-Diagnose (bf-Tunnel = Round-Robin über 3 Connectors macmini/pve/NAS) - mcp/cloudflare/: README + .env.example (echtes .env via mcp/.gitignore ausgeschlossen) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
144
docs/cf-tunnel-mapping.md
Normal file
144
docs/cf-tunnel-mapping.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Cloudflare-Tunnel — Mapping & #1033-Diagnose (Single Source of Truth)
|
||||
|
||||
> **Stand:** 2026-06-30 · erstellt via `cloudflare`-MCP (live) + Portainer-API + macmini-Probe.
|
||||
> Track A aus `docs/handoff-cf-tunnel-1033.md`. **Diagnose abgeschlossen — Fixes noch NICHT angewendet** (warten auf Freigabe).
|
||||
|
||||
## 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.41.126 | host | VLAN1/.41 |
|
||||
| `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.41.126:9443 | OK(self) | ? | OK | ok |
|
||||
| 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 — STATUS 2026-06-30
|
||||
> Zugang gelöst über **scoped API-Token** in `mcp/cloudflare/.env` (OAuth-MCB blieb read-only).
|
||||
> **A1 + A2 ✅ ANGEWENDET** (Ingress v106). **A3 (DNS) ⛔ blockiert:** Token hat kein DNS-Permission
|
||||
> (`dns_records` = 403) → Christoph muss **DNS:Edit** für emsenhuber.net zum Token hinzufügen.
|
||||
|
||||
### ✅ 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.
|
||||
|
||||
### ⛔ Offen A3 (sobald Token DNS:Edit hat)
|
||||
- `hermes-geli` CNAME → `70d6a4cf….cfargotunnel.com` (proxied) anlegen (bis dahin 000).
|
||||
- Löschen: `oc`,`oc2`,`oc3`,`win11test`,`jc`,`charlie`,`coolify`,`dashboard`,`drawio`,`mcp-ms365`,
|
||||
`mcp-qdrant`,`ssh-nasbfnew`.
|
||||
|
||||
### 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).
|
||||
22
mcp/cloudflare/.env.example
Normal file
22
mcp/cloudflare/.env.example
Normal file
@@ -0,0 +1,22 @@
|
||||
# Cloudflare scoped API-Token — Vorlage. Echte Werte → .env (gitignored via mcp/**/.env)
|
||||
# Token-Scopes (least-privilege): Cloudflare Tunnel:Edit, DNS:Edit (Zone emsenhuber.net),
|
||||
# Access: Apps and Policies:Edit, Access: Organizations, Identity Providers, and Groups:Edit
|
||||
CF_API_TOKEN=
|
||||
|
||||
# Feste IDs (kein Secret, hier als Referenz):
|
||||
CF_ACCOUNT_ID=393c051f3accf51881d6c98fc5b66c36
|
||||
CF_ZONE_ID=1b5bc02fdf61b6b989afde543f3f4134
|
||||
CF_BF_TUNNEL_ID=70d6a4cf-aa1d-4a91-b918-91fab4fa7270
|
||||
|
||||
# --- OAuth-App-Secrets für Access-IdPs (von den jeweiligen Provider-Konsolen) ---
|
||||
# Callback-URL überall: https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback
|
||||
GITHUB_CLIENT_ID=Ov23li2h96hAkGRPJXYV
|
||||
GITHUB_CLIENT_SECRET=
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
FACEBOOK_APP_ID=
|
||||
FACEBOOK_APP_SECRET=
|
||||
|
||||
# --- Geli ---
|
||||
GELI_EMAIL=
|
||||
GELI_PUBLIC_IP= # optional, /32 — nur falls stabile öffentliche IPv4 (bei CGNAT leer lassen)
|
||||
38
mcp/cloudflare/README.md
Normal file
38
mcp/cloudflare/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Cloudflare — scoped API-Token (Writes) + OAuth-IdP-Secrets
|
||||
|
||||
Cloudflare wird wie jeder andere Dienst im Repo über einen **scoped API-Token** geschrieben
|
||||
(Konvention wie `mcp/portainer`, `mcp/omada`). Die `cloudflare`-OAuth-MCP in Claude Code ist
|
||||
**read-only** (Consent bietet keinen Write-Scope) → nur zum Lesen.
|
||||
|
||||
Plan/Kontext: `~/.claude/plans/schei-e-wenn-ich-das-breezy-biscuit.md` · SSoT: `docs/cf-tunnel-mapping.md`.
|
||||
|
||||
## 1. API-Token anlegen
|
||||
dash.cloudflare.com → **My Profile → API Tokens → Create Token → Create Custom Token**
|
||||
- **Permissions:**
|
||||
- Account · Cloudflare Tunnel · **Edit**
|
||||
- Zone · DNS · **Edit**
|
||||
- Account · Access: Apps and Policies · **Edit**
|
||||
- Account · Access: Organizations, Identity Providers, and Groups · **Edit**
|
||||
- **Account Resources:** Include → Christoph@emsenhuber.com's Account
|
||||
- **Zone Resources:** Include → Specific zone → emsenhuber.net
|
||||
- Create → Token kopieren → in `.env` als `CF_API_TOKEN`.
|
||||
|
||||
## 2. OAuth-Apps für Access-Login (Callback überall gleich)
|
||||
**Callback-URL:** `https://emsenhuber.cloudflareaccess.com/cdn-cgi/access/callback`
|
||||
|
||||
- **GitHub** (reparieren — Secret fehlt): github.com → Settings → Developer settings → OAuth Apps
|
||||
→ bestehende App (client_id `Ov23li2h96hAkGRPJXYV`) → **Generate a new client secret** →
|
||||
Authorization callback URL = obige Callback-URL → Secret in `.env` (`GITHUB_CLIENT_SECRET`).
|
||||
- **Google:** console.cloud.google.com → APIs & Services → Credentials → Create OAuth client ID →
|
||||
Web application → Authorized redirect URI = Callback-URL → client_id/secret in `.env`.
|
||||
- **Facebook:** developers.facebook.com → Create App → Facebook Login → Valid OAuth Redirect URI =
|
||||
Callback-URL → App-ID/Secret in `.env`.
|
||||
|
||||
## 3. Geli
|
||||
`GELI_EMAIL` (für Social-Login-Policy). `GELI_PUBLIC_IP` nur falls stabile öffentliche IPv4 (CGNAT → leer).
|
||||
|
||||
## 4. Ausführung
|
||||
Writes laufen per `curl` gegen `api.cloudflare.com` mit `Authorization: Bearer $CF_API_TOKEN`
|
||||
(`set -a; . mcp/cloudflare/.env; set +a`). Claude wendet die Change-Sets aus dem Plan an und
|
||||
verifiziert jeden Schritt extern (HTTP-Status, kein 1033). Reihenfolge: Token-Verify → Track A
|
||||
(Tunnel) → Track B (Access).
|
||||
Reference in New Issue
Block a user