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>
This commit is contained in:
@@ -75,7 +75,13 @@ ab jetzt bei jeder Änderung mitgezogen, nicht nur die TP-Abschnitte.)*
|
||||
|
||||
</details>
|
||||
|
||||
**Nächster Schritt (Stand 2026-08-23): Christoph entscheidet — der kritische Pfad ist LEER.**
|
||||
**Nächster Schritt (Stand 2026-08-25): [TP31](#tp31) — Caddy als Reverse Proxy für innen und außen.**
|
||||
> 🆕 **Neu am 2026-08-24/25:** [TP31](#tp31) löst **TP16** und **TP16.2** ab und dampft cloudflared
|
||||
> von **sechs Containern auf einen** ein; [TP32](#tp32) gibt die Nummern- und Adress-Systematik vor
|
||||
> (und hat nebenbei die **falsche Startreihenfolge auf pve repariert** — HA startete vor seiner
|
||||
> Datenbank). **TP16 ✅, TP25 ✅ und TP16.3 (Pilot) ✅** sind am 24./25. durchgezogen worden.
|
||||
|
||||
**Vorherige Fassung (Stand 2026-08-23): Christoph entscheidet — der kritische Pfad ist LEER.**
|
||||
> 🎯 **Das Projekt ist in seinem Kern fertig.** deny-by-default steht (TP5), Golden Config steht und
|
||||
> meldet **104/104 compliant bei 0 Drifts** (live geprüft 2026-08-23), WLAN steht über CAPsMAN auf dem
|
||||
> Core (TP28), VLAN1 ist leer (TP19) — und **TP6 ist beantwortet statt offengelassen**: CAKE gebaut,
|
||||
@@ -1324,6 +1330,183 @@ unabhängig vom gebündelten Durchgang.**
|
||||
**Blockiert nichts.** Die frühere Kopplung „erst TP17.1, dann rotieren" ist **gegenstandslos** —
|
||||
TP17.1 ist am 2026-08-23 verworfen, die Geräte bleiben WLAN-Clients.
|
||||
|
||||
|
||||
<a id="tp31"></a>
|
||||
### TP31 — Reverse Proxy für innen und außen; cloudflared von sechs Knoten auf einen ▸ 🔜 **GEPLANT 2026-08-25**
|
||||
> **Auslöser (User 2026-08-24):** „ich weigere mich, für public applications 2 cloudflare container zu
|
||||
> installieren. … ich habe [den Core] unter der prämisse gekauft, dass über diesen dann auch die public
|
||||
> apps laufen können. wir wollten doch den core als single point of failure platzieren."
|
||||
|
||||
#### Der Vorwurf, fair geprüft
|
||||
Eine schriftliche Zusage, dass die Public-Apps auf den Core wandern, existiert **nicht** —
|
||||
[TP16.1](teilprojekte-archiv.md#tp16-1) ist durchgehend auf den *privaten* Zugang zugeschnitten und hält
|
||||
mehrfach fest, dass „der cloudflared-Public-Teil unberührt blieb". **Aber der Vorwurf trifft trotzdem
|
||||
etwas Richtiges:** dasselbe Dokument begründet die gesamte Auswahl mit **Christophs** Prinzip —
|
||||
*„Router = einziger SPOF, keine Abhängigkeit zu anderen Rechnern"* — und **niemand hat je geprüft, ob der
|
||||
öffentliche Strang ohne sechs Container auskommt.** Keine Täuschung, aber eine **ungeprüfte Annahme**.
|
||||
|
||||
#### Die Lösung ist nicht „raus aus Cloudflare", sondern „ein Knoten statt sechs"
|
||||
**Caddy** als Reverse Proxy für **innen und außen**, `emsenhuber.net` in beiden Richtungen, plus **ein**
|
||||
cloudflared als Tunnel-Endpunkt.
|
||||
|
||||
- ⚖️ **Erst geprüft, dann verworfen: der Weg über `dst-nat`.** Der Core hält `90.146.33.177` direkt ohne
|
||||
CGNAT, Liwest lässt eingehend alles durch (User: „hatte früher schon nginx hier laufen"), und
|
||||
Origin Rules (Ziel-Port, **Free = 10 Regeln**), die CF-HTTPS-Ports (`443, 2053, 2083, 2087, 2096, 8443`)
|
||||
sowie Authenticated Origin Pulls sind alle im Free-Tarif enthalten. Es **ginge** also ohne jeden Container.
|
||||
- 🎯 **Christophs Einwand ist der bessere Weg:** *„caddy muss so oder so. nachdem dieser vorhanden ist,
|
||||
fahren wir natürlich über zero trust apps. noch etwas sicherer, aber kein zusätzlicher knotenpunkt,
|
||||
der ausfallen kann."* Der Tunnel spart drei Risiken auf einmal: **keine angreifbare Origin-IP, keine
|
||||
CF-IP-Allowlist, kein DDNS als Voraussetzung** (der TP10-Updater bliebe sonst zwingend).
|
||||
|
||||
#### Zielbild
|
||||
```
|
||||
Internet ─► Cloudflare (Access, WAF) ─► Tunnel »bf-public« ─► cloudflared auf ap1/ap2
|
||||
WARP ─► cf-mesh (nativ am Core, kein Container) ─┐
|
||||
LAN ─► Split-Horizon-DNS ───────────────────────┴─► Caddy (LXC 130, 10.40.20.40)
|
||||
└─► alle Dienste per Host-Header
|
||||
```
|
||||
**Öffentlich bleiben vier:** `vw` (Bitwarden-Clients), `hass` (Companion-App), `n8n` (Webhooks Dritter),
|
||||
`gitea` (Access **nur für die Web-UI**, Git-/API-Pfade daran vorbei ⇒ **Push ohne WARP bleibt**).
|
||||
Alles andere ist intern; **19 Ingress-Zeilen über drei Tunnel werden EINE Catch-all-Regel auf Caddy.**
|
||||
|
||||
#### Wo cloudflared läuft — und warum die APs (live gemessen 2026-08-24/25)
|
||||
|
||||
| Gerät | Arch | Flash frei | RAM frei | Container? |
|
||||
|---|---|---|---|---|
|
||||
| **ap1 / ap2** (hAP ax²) | **arm64** | **95 MB / 128 MB** | **690 MB / 1 GB** | ✅ ja |
|
||||
| **crs326-core** | arm **32-bit** | **2,9 MB / 16 MB** | 512 MB | ❌ **nie** |
|
||||
|
||||
- ✅ **Christophs Argument, das den Ausschlag gibt:** *„cf auf den aps hat den vorteil, dass wir gegenüber
|
||||
unseren hosts/container nicht blind sind."* — Der AP ist eine **eigene Maschine**, kein Docker-Host;
|
||||
die macvlan/ipvlan-Blindheit kann dort **prinzipiell** nicht auftreten. Kein anderer Ort hat das.
|
||||
💡 Daraus folgt eine Reserve: fällt Caddy aus, kann derselbe Connector über eine zweite Ingress-Regel
|
||||
**direkt** auf ein, zwei kritische Backends zeigen.
|
||||
- 🔴 **Ehrliche Einschränkung:** cloudflareds einziges Origin ist Caddy. Solange Caddy auf pve liegt,
|
||||
kauft ein Connector auf dem AP **Hardware-Diversität, aber keine Verfügbarkeit** — fällt pve aus, ist
|
||||
alles weg. Der echte Gewinn kommt erst mit `caddy-bf2` (LXC 131).
|
||||
- **Caddy oder AGH zusätzlich auf die APs? Nein.** 95 MB minus RouterOS-Reserve fürs eigene `.npk`
|
||||
(~20 MB) = **ein Container pro AP**. Kriterium, das auch künftig trägt: **auf die Infrastruktur darf,
|
||||
was sich selten ändert und wenig schreibt** — cloudflared ja (Config liegt in Cloudflare, schreibt
|
||||
nichts); **Caddy nein** (Caddyfile ändert sich bei jedem neuen Dienst); **AGH nein** (Query-Log
|
||||
schreibt dauernd → NAND-Verschleiß).
|
||||
- ⚠️ **Preis:** `container` verlangt eine **`device-mode`-Änderung mit physischer Bestätigung** am Gerät
|
||||
(ap1 Technik UG, ap2 Technik OG). Und der AP bekommt eine zweite Rolle neben dem WLAN.
|
||||
|
||||
#### Umsetzung
|
||||
1. **Leichen löschen:** `120 adguard-bf1`, `121 adguard-bf2`, `128 nginx-proxy-manager`, `129 caddy`,
|
||||
`130 pihole1`, `131 pihole2` — alle `stopped`, alle auf **totem VLAN1** (`10.40.41.116/.117`,
|
||||
GW `.41.254`), `onboot: 0`. ⚠️ `130`/`131` **müssen** weg, bevor die neuen Nummern vergeben werden.
|
||||
**Alte Backups radieren** (Job `backup-6dcf5c10-610f`, So 01:00, Storage `pbs`, führt heute `120`
|
||||
und `128`), **`130` neu aufnehmen — derselbe Job.**
|
||||
2. **LXC 130 `caddy-bf1`** neu anlegen: VLAN20 `tag=20`, `10.40.20.40/24`, GW/DNS `10.40.20.1`,
|
||||
**`onboot: 1`**, ~4 GB / 512 MB. *(Neu bauen statt umkonfigurieren — die Altlasten sind
|
||||
Helper-Script-AdGuard-Container und würden auf Jahre eine falsche Identität führen.)*
|
||||
3. **Caddy mit Cloudflare-DNS-Modul** → **DNS-01**, damit auch rein interne Namen echte Zertifikate
|
||||
bekommen. 🔑 **Eigenes, eng geschnittenes Token** (`Zone:DNS:Edit` nur auf `emsenhuber.net`), **nicht**
|
||||
das account-weite `CF_API_TOKEN` ⇒ neuer Posten für **TP30**.
|
||||
4. **Split-Horizon**: Service-FQDNs → Caddy. 🔗 **Vorher entscheiden: Core (`/ip dns static`) oder
|
||||
AdGuard?** Sobald AGH nach **TP23 Stufe 2** scharf ist, gehören die Einträge dorthin — sonst zweimal gebaut.
|
||||
5. **Tunnel `bf-public`** + Connectoren auf ap1/ap2, CNAMEs umhängen (`n8n` → `gitea` → `hass` → `vw`).
|
||||
6. **Abbau:** `bf-nas`/`bf-pve`/`bf-mm` löschen, sechs Container weg, SSH-Browser-Rendering entfällt,
|
||||
**MCP-Clients auf FQDN umstellen** (`~/.claude.json` spricht heute `10.40.20.105:9583` und
|
||||
`10.40.20.173:3000` roh; `n8n-mcp`/`gitea-mcp` kommen dabei wieder in Betrieb).
|
||||
|
||||
🎯 **Kernabnahme: WAN trennen, dann alle Dienste per FQDN.** Das ist die Autarkie, um die es geht.
|
||||
⚠️ **Preis, offen benannt:** mit Split-Horizon greift **Access innerhalb des Netzes nicht mehr**; dort
|
||||
tragen TP5-Segmentierung und die App-eigene Auth.
|
||||
|
||||
#### HA-Ausblick (nicht Teil der Umsetzung)
|
||||
**Es bleibt bei Caddy** — zustandslos bis auf den Zertifikatsspeicher, identisches Caddyfile je Instanz,
|
||||
versionierbar; NPM hätte eine Datenbank, die man mitreplizieren müsste.
|
||||
🔴 **Prinzip für `vw`: der Eingang darf nicht klüger sein als die Datenbank.** [TP20.1](#tp20-1) sieht
|
||||
**manuelles Promote** vor. Zwei Connectoren auf **verschiedene** Caddys an verschiedenen Standorten
|
||||
würden die Hälfte der **Schreib**zugriffe auf einen read-only Standby schicken — das #1033-Muster,
|
||||
diesmal mit Datenverlust statt 530ern. **Automatisches Ingress-Failover erst, wenn der DB-Teil es trägt**
|
||||
(User: vertagt bis TP20.1 Phase 1+2 laufen).
|
||||
|
||||
- **Abh.:** [TP32](#tp32) (Nummern/IPs — vergibt `130`/`.40`), TP16.1 ✅ (Mesh), **TP23 Stufe 2**
|
||||
(Split-Horizon-Ort). **Löst ab:** TP16 (reziprokes HA) und **TP16.2** (der `vw`-bypass-Strang bekommt
|
||||
mit Caddy + CF davor einen anderen Schutz). **TP16.3 ist der Pilot dieses TP.**
|
||||
- 📋 **Vollständiger Plan mit allen Abwägungen:** `~/.claude/plans/expressive-pondering-clarke.md`
|
||||
|
||||
<a id="tp32"></a>
|
||||
### TP32 — Nummern- und Adress-Systematik ▸ 🟢 **KONZEPT STEHT (2026-08-25), Startreihenfolge bereits repariert**
|
||||
> **User-Auftrag 2026-08-24:** „du/ich sollst in der lage sein, selbstständig nach einem vorgegebenen
|
||||
> system freie ips vergeben zu können … und diese systematik findet sich in anderen netzen künftig auch
|
||||
> wieder" · „ich meine 100 sollte künftig für die core services stehen."
|
||||
>
|
||||
> **Eigener TP, weil es eine Konvention ist, kein Bauteil** — TP31 ist ihr erster Kunde.
|
||||
> **Regel: Bestand bleibt, wo er ist; jeder NEUE Gast folgt der Systematik.**
|
||||
|
||||
🔑 **Ein gemeinsamer VMID-Raum für VMs *und* LXCs.** `100 haos` und `330 RaspberryMatic` sind **VMs** —
|
||||
die Klasse bestimmt die Nummer, nicht die Virtualisierungsart.
|
||||
|
||||
| Kreis | Klasse | heute dort (VM *kursiv*) |
|
||||
|---|---|---|
|
||||
| **100–199** | **Core / Infrastruktur** | `108 mcast-relay` |
|
||||
| **200–299** | **Daten / DBs** (Precious-Tier) | *(`105`, `106`, `107`, `302` → später hierher)* |
|
||||
| **300–399** | **Security / Identity** | — |
|
||||
| **400–499** | **Platform / Runtime** | ✅ `400 docker` passt bereits |
|
||||
| **500–599** | **App-Services / Smart Home** | `101`, `102`, `112`, `150`, *`100`*, *`330`* → später hierher |
|
||||
| **600–699** | **Business / ERP** | `201 openproject` |
|
||||
| **700–799** | **KI / ML** | — |
|
||||
| **800–899** | **Dev / R&D / Test** | — |
|
||||
| **900–999** | **Ephemeral / Scratch** | wird ungefragt gelöscht |
|
||||
|
||||
**Zehnerschritte innerhalb eines Kreises** („Respektabstand", User), damit Instanzen und Nachbarn Platz
|
||||
haben: `100–109` netznah · **`110–119` DNS** · **`130–139` Reverse Proxy** · `150–159` Monitoring ·
|
||||
`170–179` PKI/Zeit. ⇒ **AGH `110`, Caddy `130`.**
|
||||
|
||||
**Letztes Oktett je /24 — gilt in jedem VLAN, an jedem Standort:**
|
||||
|
||||
| Oktett | Rolle | Anker heute |
|
||||
|---|---|---|
|
||||
| `.1–.9` | Gateways / L3 | `.1` je VLAN ✅ · `99.1` core, `99.2` branch ✅ |
|
||||
| `.10–.29` | physische Hosts (Storage, Hypervisor, APs) | NAS `20.10` ✅ · APs `99.11/.12` ✅ |
|
||||
| `.30–.99` | virtuelle Core-Services, Zehnergruppen wie oben | DNS `.3x` · Ingress `.4x` · DBs `.5x` · Security `.6x` · Monitoring `.7x` |
|
||||
| `.100–.199` | App-Services | |
|
||||
| `.200–.249` | DHCP-Pool | |
|
||||
| `.250–.254` | VIPs / Relays | |
|
||||
|
||||
🔑 **Der Merk-Trick: die Zehnergruppe im Oktett spiegelt die der VMID.** `110 agh` → `.3x`,
|
||||
`130 caddy` → `.4x`. Wer eine Zahl kennt, kennt die Klasse der anderen.
|
||||
|
||||
#### Warum der Bestand anders aussieht — er war nicht falsch, nur auf einer anderen Achse
|
||||
**User 2026-08-25:** „zuerst war haos, welches mit 100 den nummernkreis für iot eröffnet hat. und die
|
||||
anderen … gehörten zu ha, daher 1xx. erst später habe ich erfahren, dass die nummer die
|
||||
startreihenfolge definiert."
|
||||
⇒ Der Bestand gruppiert nach **Zugehörigkeit**, die neue Systematik nach **Klasse**. Beide Achsen sind
|
||||
legitim; die zweite ist die, die das System auswertet. Der alte `1xx`-Block ist der **Smart-Home-Block**
|
||||
und wandert später als Gruppe nach `5xx`.
|
||||
|
||||
#### ✅ ERLEDIGT 2026-08-25: die Startreihenfolge war nachweislich falsch
|
||||
🔴 **Und der Hebel ist NICHT die VMID.** Drei Gäste hatten ein explizites `startup: order=`
|
||||
(`101 iob-master` 110, `102 mqtt5` 120, `100 haos` 125), alle übrigen keines. **Proxmox startet erst
|
||||
alle Gäste mit `order=`, dann den Rest nach VMID** — real lief also `iob-master → mqtt5 → haos` und
|
||||
**erst danach** `platform-pg`, `mariadb`, `z2m25`, `docker`.
|
||||
⇒ **Home Assistant startete vor seiner eigenen Datenbank.**
|
||||
|
||||
**Repariert (wirkt beim nächsten pve-Neustart):**
|
||||
|
||||
| `order=` | Stufe | Gäste |
|
||||
|---|---|---|
|
||||
| 10 | Core | `108 mcast-relay` |
|
||||
| 20 | Daten | `105 platform-pg` (`up=15`), `302 mariadb` (`up=15`), `106 influxdb2`, `107 redis` |
|
||||
| 30 | Platform | `400 docker` (`up=20`) |
|
||||
| 40 | Broker / Funk | `102 mqtt5` (`up=10`), `112 z2m25`, `330 RaspberryMatic` |
|
||||
| 50 / 51 | Anwendungen | `101 iob-master`, **`100 haos`**, `150 iob-exposed` |
|
||||
|
||||
🎯 **Die wichtigste Erkenntnis des TP: VMID = Klassifikation, `startup: order=` = Abhängigkeitsreihenfolge.**
|
||||
Die Umnummerierung muss die Startreihenfolge gar nicht reparieren — das ist bereits erledigt, ohne eine
|
||||
einzige ID zu ändern. **Die Nummernkreise sind damit reine Ordnung und Lesbarkeit**, und der Bestand
|
||||
kann in Ruhe nachziehen.
|
||||
|
||||
- **Offen:** Migration des Bestands (Tabelle oben) — *am Ende der Reise, nicht jetzt*. Und die
|
||||
Kollision **AGH will `.30`, dort sitzt Nautobot** (`.31` = nautobot-worker) ⇒ Vorschlag `.36` als
|
||||
Interim, `.30` erst nach dem Nautobot-Umzug in den App-Bereich. **Fällt vor dem AGH-Neubau an.**
|
||||
- **Abh.:** keine. **Blockiert nichts**, aber TP31 vergibt bereits danach.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Abgeschlossene Teilprojekte ▸ [`teilprojekte-archiv.md`](teilprojekte-archiv.md)
|
||||
|
||||
Reference in New Issue
Block a user