diff --git a/docs/teilprojekte.md b/docs/teilprojekte.md index dda1c6e..a5a20d5 100644 --- a/docs/teilprojekte.md +++ b/docs/teilprojekte.md @@ -44,9 +44,10 @@ liest, liest ihn als Erstes: er wird bei jeder Änderung mitgezogen, nicht nur d **und** DNS entfernt — `pve`/`portainer`/`pve-mcp`/`ha-mcp`/`ds-bf`/`ccu`/`iobroker`/`z2m25`/`pbs` plus die drei CF-Access-SSH-Ziele. Ingress: `bf-mm` 6→4, `bf-nas` 6→3, `bf-pve` 9→2. **Öffentlich bleiben nur `vw`/`hass`/`n8n`/`gitea`** (weiterhin HTTP 200). Intern unverändert über AdGuard→Caddy - (9× HTTP 200). ⚠️ **`gitea-mcp`/`n8n-mcp` bewusst stehen gelassen** — hängen noch in 10 Dateien - (8 fremde Projekte, `bf-infra/opencode.jsonc`, `~/.claude.json`); **TP35 Schicht 1 ist nur global - vollzogen, nicht auf Projekt-Ebene.** 🔴 **`bf-public` hat weiterhin 0 Connectoren** — er gehört + (9× HTTP 200). ✅ **Nachtrag 2026-08-30 (F1 durch): `gitea-mcp`/`n8n-mcp` sind jetzt AUCH + geschnitten** — damit **14 Hostnames** gesamt und `bf-mm` **4→2** (nur noch `n8n` + Catch-all). + Möglich wurde das, weil zuvor **12 MCP-Client-Configs** auf LAN-IP migriert wurden (nicht 10 wie + geschätzt: zwei Worktree-Kopien in `bf-network-r6{,.opencode}` kamen dazu). 🔴 **`bf-public` hat weiterhin 0 Connectoren** — er gehört laut Entscheid auf **ap1/ap2**, dort fehlen aber `container`-Paket **und** `device-mode container=yes` (physische Bestätigung nötig). Bis dahin stehen `bf-mm`/`bf-nas`/`bf-pve` mit **6 Containern**. Backups: `docs/cf-backup/*-20260830-vor-tp16.3-schnitt.json`. @@ -121,8 +122,9 @@ liest, liest ihn als Erstes: er wird bei jeder Änderung mitgezogen, nicht nur d **Nächster Schritt (Stand 2026-08-30): Vor-Ort-Session ap1/ap2** — sie ist der einzige Weg, den Public-Strang auf `bf-public` zu heben und die drei Alt-Tunnel samt sechs Containern abzubauen -(TP16.3 Follow-up F2). Davor unabhängig machbar: **F1** (`gitea-mcp`/`n8n-mcp` in 10 Dateien auf -LAN-IP, vollendet TP35 Schicht 1) und die Announcement-Doku (TP35 Schicht 4). +(TP16.3 Follow-up F2). ✅ **F1 ist am 2026-08-30 durch** (12 Client-Configs auf LAN-IP, danach +`gitea-mcp`/`n8n-mcp` aus Ingress+DNS geschnitten) — davor unabhängig machbar bleibt nur noch die +**Announcement-Doku (TP35 Schicht 4)**, die den anderen Projekten die neuen MCP-URLs mitteilt. **Vorherige Fassung (Stand 2026-08-28): drei Folge-Sessions parallel** (siehe `docs/handoff-20260828-mcp-bestand-und-performance.md`): > - ✅ **Session A** — `/projektstatus`-Skill global für opencode (TP35 Schicht 6). Funktionsbeweis erbracht 2026-08-28. @@ -232,7 +234,7 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na > | TP14.4 | 🔜 | CF-Access-Token | — | > | TP16 | ✅ | CF-Tunnel HA wieder voll | 2026-08-24 | > | TP16.2 | 🔜 | Härtung bypass-Dienste | — | -> | TP16.3 | ⏳ | cloudflared-Reduktion (12 Hostnames geschnitten 08-30; Abbau braucht Vor-Ort-Session) | — | +> | TP16.3 | ⏳ | cloudflared-Reduktion (14 Hostnames geschnitten 08-30, F1 durch; Abbau braucht Vor-Ort-Session) | — | > | TP17.1 | ❌ | Shelly Gen4 → Zigbee | 2026-08-23 | > | TP17.3 | ✅ | Shelly-Regression behoben | 2026-08-23 | > | TP18 | 🔜 | Garage-Objektspeicher | — | @@ -474,13 +476,15 @@ nachmessen und dann entscheiden**. Blocker gibt es keine mehr. TP5 ist in der Na Ingress-Bilanz: `bf-mm` 6→4 · `bf-nas` 6→3 · `bf-pve` 9→2. Catch-all in allen dreien geprüft letzte. - **`pbs` und die SSH-Ziele standen nicht in der Kandidatenliste** — User-Entscheid 2026-08-30: beide mesh-only. PBS erreicht man über `10.40.20.135:8007`, SSH direkt per IP, jeweils mit WARP. -- 🔴 **Zwei Namen bewusst NICHT geschnitten: `gitea-mcp` und `n8n-mcp`.** Die TP16.3-Vorprüfung - („hängt Werkzeug am öffentlichen Namen?") schlägt hier an: `gitea-mcp.emsenhuber.net` steht in - **9 Dateien** — `~/dev/{bf-network-r6,bf-network-r6.opencode,blaueblueten-n8n,dachterrasse,ha, - ha-xstate,poulios-recherche,valamar}/.mcp.json` plus `bf-infra/opencode.jsonc` — und - `~/.claude.json` nutzt zusätzlich `n8n-mcp.emsenhuber.net`. **TP35 Schicht 1 hat nur die globale - `~/.config/opencode/opencode.jsonc` auf LAN-IP migriert**; Projekt-Ebene und `~/.claude.json` sind - zurückgeblieben. Erst migrieren, dann schneiden → Follow-up **F1** unten. +- ✅ **Zwei Namen zunächst NICHT geschnitten: `gitea-mcp` und `n8n-mcp` — am selben Tag per F1 nachgeholt.** + Die TP16.3-Vorprüfung („hängt Werkzeug am öffentlichen Namen?") schlug hier an: + `gitea-mcp.emsenhuber.net` stand in **11 Dateien** (nicht 9 — beim Edit kamen zwei + Worktree-Kopien dazu, s. F1) — `~/dev/{bf-network-r6,bf-network-r6.opencode,blaueblueten-n8n, + dachterrasse,ha,ha-xstate,poulios-recherche,valamar}/.mcp.json` plus `bf-infra/opencode.jsonc` — + und `~/.claude.json` nutzte zusätzlich `n8n-mcp.emsenhuber.net`. **TP35 Schicht 1 hatte nur die + globale `~/.config/opencode/opencode.jsonc` auf LAN-IP migriert**; Projekt-Ebene und + `~/.claude.json` waren zurückgeblieben. Regel „erst migrieren, dann schneiden" eingehalten: + **F1 hat migriert, danach fiel der Schnitt** (Ingress `bf-mm` 4→2, beide DNS-CNAMEs gelöscht). - ✅ **Abnahme (2026-08-30), beide Richtungen gemessen:** - **intern trägt weiter:** AdGuard löst alle neun Namen unverändert auf `10.40.20.40` (Split-Horizon, TP31 Schritt 4), Caddy antwortet über HTTPS mit **HTTP 200** (`pve` 0,08 s · `portainer` 0,03 s · @@ -511,9 +515,34 @@ und Letzteres verlangt die **physische Bestätigung am Gerät** — ap1 Technik → Runbook-Bedarf als Follow-up **F2**; bis dahin bleiben die drei Alt-Tunnel mit je 2 Connectoren stehen. #### 📌 Follow-ups aus dieser Session (2026-08-30) -- **F1 — `gitea-mcp`/`n8n-mcp` FQDN→LAN-IP in 10 Dateien** (8 fremde Projekte + `bf-infra/opencode.jsonc` - + `~/.claude.json`). Vollendet **TP35 Schicht 1**, entsperrt die letzten zwei CF-Hostnames. - ⚠️ Projektübergreifend → gehört ins **Announcement** (TP35 Schicht 4), eigene Session. +- ✅ **F1 — `gitea-mcp`/`n8n-mcp` FQDN→LAN-IP, DURCH 2026-08-30.** Statt der geschätzten 10 waren es + **12 Dateien**: `~/.claude.json` (beide Namen), `bf-infra/opencode.jsonc`, 8× `dev/*/.mcp.json` und + **zwei Worktree-Kopien** in `bf-network-r6{,.opencode}/.claude/worktrees/frosty-hermann-76f9cd/`, + die erst ein Sweep fand. Danach fiel der Schnitt (s. oben). Backups je Datei. + - 🔑 **Die zwei Clients haben verschiedene Konfigpfade — das ist die Stelle, an der man Dateien übersieht.** + **Claude Code** liest `/.mcp.json`, also **eine Datei pro Projekt**. **opencode** liest + **eine globale** `~/.config/opencode/opencode.jsonc`; projekt-lokal existiert nur + `bf-infra/opencode.jsonc`. Deshalb genügte für opencode die eine globale Migration (TP35 Schicht 1), + während Claude Code acht Einzeldateien brauchte. `.mcp.json` ist **kein** opencode-Pfad. + - 🔴 **`n8n-mcp` lässt sich NICHT ohne Bearer betreiben.** `dist/http-server.js` ruft + `process.exit(1)`, wenn `AUTH_TOKEN` fehlt („required for HTTP mode"). Damit ist er der **einzige + echte Zugriffs-Bearer** im Setup — `gitea-mcp` hat gar keine Auth, alles andere (`mikromcp`, + `hostinger`, `portainer`, `github`) sind Arbeits-Credentials der MCPs, kein Zugriffsschutz. + Der Wunsch „Bearer für alle weg" ist also faktisch schon erfüllt, bis auf den einen, der es nicht kann. + - 🔧 **`gitea-mcp` auf `10.40.20.167:3000` gebunden** (war `0.0.0.0:3000`). Zustandslos, kein Volume, + per `docker run` rekonstruiert; Token über die Prozessumgebung (`-e VAR` ohne Wert), **nicht** über + argv — dieselbe Klasse wie die `sshpass -p`-Falle. ⚠️ Der Nutzen ist klein: der macmini hat **nur + `en0`**, `0.0.0.0` war dort faktisch schon `.167`. `n8n-mcp` blieb deshalb auf `*:3001`. + - ⚪ **Tote Diagnose-Permissions entfernt:** `blaueblueten-n8n/.claude/settings.local.json` hatte 3× + `Bash(dig/host/curl … gitea-mcp.emsenhuber.net)` in der `allow`-Liste (10→7 Einträge). Das waren + **keine** MCP-Verbindungen — `enabledMcpjsonServers: ["gitea-mcp"]` gibt per **Name** frei und + blieb unberührt. Projektweit geprüft: nur dieses eine Projekt betroffen. + - 📌 **Nachweis-Korrektur zur Abnahme oben:** geschnittene Namen antworten öffentlich mit + **`NOERROR` + leerer Antwort**, nicht mit `NXDOMAIN` — gegengeprüft an `pve`/`portainer`/`ha-mcp`/`pbs` + aus dem großen Schnitt, die sich identisch verhalten. Gültiger Nachweis bleibt der zurückgelesene + Ingress plus die leere Antwort. + - ⚠️ Projektübergreifend → gehört ins **Announcement** (TP35 Schicht 4), eigene Session. + Dort mitnehmen: **„achte auf opencode"** sowie den neuen Pfad `~/dev/bf-infra` / Repo `admin/bf-infra`. - **F2 — Vor-Ort-Runbook ap1/ap2:** `container`-Paket + `device-mode`, cloudflared-Image als `.tar`, `bf-public`-Token, danach CNAME-Umhang der vier Public-Dienste und Abbau von `bf-mm`/`bf-nas`/`bf-pve` samt der **sechs** Container (LXC400 `.126`: `cloudflared-bfmm`+`cloudflared-bfnas` · macmini `.167`: @@ -522,6 +551,33 @@ und Letzteres verlangt die **physische Bestätigung am Gerät** — ap1 Technik Ebenso unberührt: Tunnel `fm.emsenhuber.net` (Standort FM). - **F3 — CF-Connectoren in Nautobot abbilden** (User-Wunsch 2026-08-30, „durchgehende Netzwerkdoku Stück für Stück"). Als **TP37** vorgeschlagen, noch nicht angelegt — wartet auf dein Okay. +- 🔜 **F4 — `n8n-mcp`-Compose versöhnen** (Befund aus F1, 2026-08-30; User-Entscheid: eigener Punkt, + nicht nebenbei). Der laufende Container stimmt mit **keiner** seiner Definitionsquellen überein — + ein `docker compose up -d` wäre deshalb **destruktiv**, es würde die interne n8n-Anbindung umstellen: + + | Quelle | `N8N_API_URL` | Netz | Port | + |---|---|---|---| + | `.env` (macmini) | `http://10.40.41.167:5678` ← **totes 41.x-Schema** | — | `3000` | + | `docker-compose.yml` | `https://n8n.emsenhuber.net` (hartkodiert, ignoriert die `.env`) | `web` | `${HOST_PORT:-3000}` | + | **laufender Container** | `http://n8n:5678` ← korrekt, Container-DNS | `n8n_default` | `3001` | + + Zu tun: Netz als `external: true` auf `n8n_default`, `N8N_API_URL` aus der Env statt hartkodiert, + Image auf den laufenden Digest pinnen (`sha256:2c8ff077…` = v2.57.1; heute `:latest` + + `pull_policy: always`, was bei jedem Recreate unkontrolliert hochzieht), Bind auf `10.40.20.167`. + ⚠️ **`N8N_API_KEY` ist in allen drei Quellen verschieden**; der laufende und der aus + `~/.secrets/credentials.env` wurden beide gegen die n8n-API getestet (**HTTP 200**), der `.env`-Wert + ist ungetestet. Der Bearer dagegen ist überall identisch. Volume `n8n-mcp-deploy_n8n-mcp-data` + überlebt einen Recreate, `gitea-mcp` hat gar kein Compose (reiner `docker run`). +- 🔜 **F5 — Secret-Verteilung auf Container-Hosts klären** (offen aus F1). `~/.secrets/credentials.env` + ist SSoT, liegt aber **nur auf dem MacBook**; auf dem macmini existiert **kein `~/.secrets`**, und + dort laufen die Container. Ein Symlink ist deshalb physisch unmöglich. Zu entscheiden: schlanke + Ableitung mit nur den nötigen Keys je Host, oder Vollspiegelung. Zusammen mit **TP30** lösen — dort + liegt der verwandte Posten: `~/.claude.json` hält **5 Secrets im Klartext** (4 Router-PW, + Hostinger-Token), wo die opencode-Configs an denselben Stellen `{env:…}` nutzen. + 🔴 **Falle beim Auslesen des Stores:** die Zeilen tragen **Inline-Kommentare** + (`CF_MM_TUNNEL_ID=7a32… # bf-mm …`). Naives `cut -d=` liefert einen 80-Zeichen-Wert, die CF-API + antwortet dann `7003 Could not route`. Ein globales `set -a; source` setzt die Variablen gar nicht + (`len=0`, Grund ungeklärt). Richtig ist gezieltes Lesen **mit** `sed -E 's/[[:space:]]+#.*$//'`. - 📌 **Ein Argument des TP ist entfallen:** die HA-Degradierung, die §7 als Nebeneffekt anführte, ist am **selben Tag repariert** (TP16 ✅). Der Fall steht damit allein auf dem eigentlichen Argument — **weniger bewegliche Teile für Dienste, die öffentlich nicht gebraucht werden.**