diff --git a/HOMELAB_ARCHITECTURE_MASTER_V2.md b/HOMELAB_ARCHITECTURE_MASTER_V2.md index a1b7521..6fa1c1a 100644 --- a/HOMELAB_ARCHITECTURE_MASTER_V2.md +++ b/HOMELAB_ARCHITECTURE_MASTER_V2.md @@ -93,6 +93,7 @@ Jeder produktive Container nutzt `restart: unless-stopped`, außer eine Ausnahme | `monitoring_net` | Compose-intern, bridge | zentraler Observability-Stack fuer Prometheus, Loki, Grafana, Promtail, Exporter und InfluxDB | Zielzustand | | `monitoring_influx_lan` | Compose-intern, bridge | nicht-oeffentliches Zusatznetz nur fuer Docker Host-Port-Publishing von InfluxDB 8181 | Zielzustand | | `glance_socket_net` | Compose-intern, `internal: true` | interner Zugriff von Glance auf den Docker-Socket-Proxy | umgesetzt | +| `smarthome_net` | bridge, `internal: true` | interne Smart-Home-Kommunikation zwischen Home Assistant, Mosquitto, spaeter Zigbee2MQTT/ESPHome | vorbereitet | | `host` | host | nur für echte Sonderfälle | begründet | ### 3.2 Finales Diagramm (vereinfacht) @@ -123,7 +124,8 @@ App-interne Netze ├── immich_default (internal: true) ✅ ├── nextcloud_internal (internal: true) ✅ ├── monitoring_net (zentraler Observability-Stack) -└── monitoring_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route) +├── monitoring_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route) +└── smarthome_net (HA, Mosquitto, spaeter Zigbee2MQTT/ESPHome) Host-Sonderfälle ├── tailscale @@ -146,6 +148,7 @@ Diese Dienste sind über echte `*.kaleschke.info`-Domains erreichbar: - `immich_server` — immich.kaleschke.info - `nextcloud` — cloud.kaleschke.info - `plex` — plex.kaleschke.info (Traefik, native Plex-Auth; Plex Remote Access/Port 32400 bleibt aus) +- `homeassistant` — home.kaleschke.info (Traefik, native Home-Assistant-Auth) ### 4.2 Nicht öffentlich / nur Tailscale oder Traefik + Middleware Diese Dienste sind **keine Public Apps**: @@ -261,6 +264,7 @@ Legende Status: | `immich_redis` | ⏳ | `immich_default` | intern | intern-only | anonymes Volume → named volume | | `nextcloud-postgres` | ✅ | `nextcloud_internal` | intern | app-eigene Nextcloud-Datenbank mit `_FILE`-Secret | — | | `nextcloud-redis` | ✅ | `nextcloud_internal` | intern | app-eigener Cache fuer File Locking / Sessions | — | +| `smarthome-mosquitto` | ✅ vorbereitet | `smarthome_net` | intern `1883`, kein Host-Port in Phase 1 | MQTT-Datenbus fuer Home Assistant, spaeter ESPHome und Zigbee2MQTT; Passwortdatei und ACLs in `/mnt/user/appdata/mosquitto/config` | LAN-Port erst in ESPHome-Phase mit ACLs/per-Device-Usern | ### 7.4 Produktive Apps @@ -274,6 +278,7 @@ Legende Status: | `immich_server` | ✅ | `immich_default`, `frontend_net` | Traefik | aktiv via `immich.kaleschke.info` | — | | `immich_machine_learning` | ✅ | `immich_default` | intern | bleibt intern | — | | `nextcloud` | ✅ | `frontend_net`, `nextcloud_internal` | Traefik | aktiv via `cloud.kaleschke.info`, nativer Nextcloud-Login, WebDAV/CardDAV faehig | CalDAV/CardDAV-Redirect via Traefik-Labels | +| `homeassistant` | ✅ vorbereitet | `frontend_net`, `smarthome_net` | Traefik via `home.kaleschke.info`, native HA-Auth | Home Assistant Container im GitOps-Stack `smart-home/`; kein HAOS, kein Supervised; Fach-YAML kommt aus `smart-home-kalli`, `.storage` bleibt in `/mnt/user/appdata/homeassistant` | Deploy, Onboarding, Restore-Probe, Cloud-Integrationen | | `plex` | ✅ | `host` | Traefik via `plex.kaleschke.info` + Plex native Auth; LAN direkt `:32400` | Compose-Stack unter `host-services/plex/`; Host-Netz bleibt fuer Discovery / Plex GDM dokumentierte Ausnahme; Traefik routet per File-Provider-Ausnahme auf `http://192.168.178.58:32400`, weil Docker-Labels Host-Netz-Container aus Traefik heraus auf `127.0.0.1` routen wuerden; kein direkter WAN-Port 32400 und Plex Remote Access bleibt aus; Server geclaimt von `Xeridos`; Smart-TVs (Schlafzimmer, Wohnzimmer) ueber WLAN-LAN per mDNS | — | | `super-productivity` | ✅ vorbereitet | `frontend_net` | Traefik + Middleware | Persoenliche Task-PWA des Operators; Issues kommen aus Gitea `Micha/mails` via n8n-Mail-Workflow | Deploy + Webhook + DNS-Eintrag offen | | `n8n` | ✅ vorbereitet | `frontend_net` | Traefik, native Auth (keine pauschale Authelia) | Workflow-Automation; erster Workflow: GMX-Mail -> OpenAI-Extraktion -> Gitea-Issue in `Micha/mails`; `N8N_ENCRYPTION_KEY` ist Stack-ENV-Pflichtsecret | Deploy + Webhook + Owner-Setup offen | @@ -389,10 +394,12 @@ Die Blockmigration aus der Portainer-/Dockerman-Phase ist abgeschlossen: Traefik | `mail-archiver` | `frontend_net` + `backend_net` | braucht Internetzugang für IMAP-Abruf (GMX, Gmail) und DB-Zugang | | `traefik/dynamic/*` | manueller Host-Sync trotz GitOps | File-Provider bleibt bewusst fuer `middlewares.yml`, `tls.yml` und `dashboards.yml`; Komodo deployed diese Dateien nicht automatisch | | `nextcloud` | keine zentrale ForwardAuth-Middleware | Nextcloud bringt eigene Auth, Clients und WebDAV/CardDAV-Endpunkte mit; Traefik bleibt Reverse Proxy, Auth bleibt app-nativ | -| `monitoring-influxdb3-core` | Host-Port 8181 auf LAN-IP; `user: "0"` | Home Assistant laeuft in einer VM ausserhalb des Compose-Netzes und muss Metriken schreiben koennen; keine Traefik-Route, kein `frontend_net`, Zugriff nur ueber Token und LAN-IP `INFLUXDB_BIND_IP`; InfluxDB 3 Core benoetigt im aktuellen Container-Setup Root-Rechte fuer den lokalen Object-Store-Pfad im named volume | +| `monitoring-influxdb3-core` | Host-Port 8181 auf LAN-IP; `user: "0"` | Home Assistant schreibt spaeter Langzeitdaten. Nach der HA-Container-Entscheidung muss der Writer-Pfad in der Influx-Phase explizit gewaehlt werden: entweder LAN-Bind via `INFLUXDB_BIND_IP` oder gezieltes gemeinsames internes Netz. Keine Traefik-Route, Zugriff nur ueber Token; InfluxDB 3 Core benoetigt im aktuellen Container-Setup Root-Rechte fuer den lokalen Object-Store-Pfad im named volume | | `monitoring-promtail` | Docker-Socket read-only | Docker-Log-Discovery fuer Loki; keine Schreibrechte, keine Appdaten-Persistenz ueber den Socket | | `n8n` | keine pauschale Authelia-Middleware | Webhook-Endpunkte (`/webhook/*`, `/webhook-test/*`) muessen ohne ForwardAuth erreichbar bleiben; n8n bringt eigene Owner-/Login-Auth mit (analog Komodo/Nextcloud) | | `plex` | Traefik ohne Authelia, File-Provider-Ausnahme trotz Host-Netz | Plex bringt native Konto-/Client-Auth mit; vorgeschaltete ForwardAuth wuerde Plex Web, Apps und Client-Flows stoeren. Docker-Labels sind fuer diesen Host-Netz-Container ungeeignet, weil Traefik sonst `127.0.0.1:32400` nutzt; daher `traefik/dynamic/plex.yml` mit Ziel `192.168.178.58:32400`. Route nur ueber Traefik/443 (`plex.kaleschke.info`), direkter Plex-WAN-Port 32400 und Plex Remote Access bleiben deaktiviert. | +| `homeassistant` | Traefik ohne Authelia, Fach-YAML aus separatem Repo | Home Assistant bringt eigene Auth, mobile Apps, Webhooks und Integrationsfluesse mit. Der Container haengt in `frontend_net` fuer Traefik und in `smarthome_net` fuer MQTT/Zigbee2MQTT/ESPHome. `.storage` und Secrets bleiben in Appdata und werden per Borg gesichert, nicht versioniert. | +| `Ecowitt` | spaetere HTTP-Ausnahme offen | Ecowitt kann nur HTTP. Wegen globalem Traefik-HTTP-Redirect wird in Phase 2 entschieden, ob Traefik eine selektive Webhook-Ausnahme bekommt oder ob ein LAN-only HA-Port `8123` als dokumentierte Host-Port-Ausnahme noetig wird. | --- diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index 0f3d795..badb49f 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -11,6 +11,45 @@ in `HOMELAB_ARCHITECTURE_MASTER_V2.md` §13, `docs/MASTER_TODO.md` (Geparkt), --- +## 2026-06-12 - Home Assistant als Container im GitOps-Stack + +**Entscheidung:** Home Assistant laeuft neu als `homeassistant` Container im +Stack `smart-home/`, nicht als HAOS-VM und nicht als Supervised-Installation. +Mosquitto laeuft als eigener Container im selben Stack; Zigbee2MQTT und ESPHome +werden spaeter ebenfalls als eigenstaendige Container ergaenzt. HA haengt in +`frontend_net` fuer Traefik und in `smarthome_net` fuer MQTT/Zigbee2MQTT/ESPHome. +Das Fachrepo `smart-home-kalli` liefert versionierte HA-YAML-Dateien read-only; +`.storage`, `secrets.yaml` und Integrations-State bleiben in +`/mnt/user/appdata/homeassistant`. + +**Kontext:** Das fruehere HAOS-VM-Setup ging bei einem Crash ohne brauchbares +Backup verloren. Das Homelab betreibt produktive Dienste inzwischen ueber +Gitea, Komodo, Compose, Renovate und Borg. HA Container passt in dieses +Betriebsmodell und vermeidet eine zweite Update-/Backup-Welt. Supervised ist +kein Zielpfad mehr; HAOS bleibt die Alternative, falls Add-on-Komfort, +Matter/Thread/HomeKit-Discovery oder Host-nahe HA-Funktionen wichtiger werden +als GitOps-Konformitaet. + +**Review-Trigger:** Viele mDNS-/SSDP-abhaengige lokale Integrationen +(HomeKit, Cast, Matter/Thread), Bedarf an HA-Add-ons als Betriebsstandard, +oder wiederholte Probleme durch Bridge-Netzwerkbetrieb. + +## 2026-06-12 - Ecowitt-Ingress bleibt bewusste Phase-2-Entscheidung + +**Entscheidung:** In Phase 1 wird kein Host-Port `8123` fuer Home Assistant +veroeffentlicht. Ecowitt wird spaeter entweder ueber eine gezielte +Traefik-HTTP-Ausnahme fuer den Webhook-Pfad angebunden oder, falls der globale +HTTP-zu-HTTPS-EntryPoint-Redirect nicht sauber selektiv abloesbar ist, ueber +einen dokumentierten LAN-only Host-Port `8123`. + +**Kontext:** Ecowitt kann nur HTTP und kein HTTPS. Traefik hat aktuell einen +globalen `web` -> `websecure` Redirect auf EntryPoint-Ebene. Ein normaler +HTTP-Router kann diese Regel voraussichtlich nicht umgehen, ohne Traefik selbst +umzubauen. Deshalb wird die Entscheidung nicht vorgezogen. + +**Review-Trigger:** Start der Ecowitt-/InfluxDB-Phase oder Umbau der Traefik +HTTP-Redirect-Architektur. + ## 2026-06-11 — Host-DNS-Fallback aktiv (AdGuard-SPOF entschaerft) **Entscheidung:** Unraid-Host nutzt `eth0` DNS server 1 = `192.168.178.58` (AdGuard) und **DNS server 2 = `192.168.178.1`** (FRITZ!Box) als Failover. diff --git a/docs/RESTORE_MATRIX.md b/docs/RESTORE_MATRIX.md index 3036473..95deebc 100644 --- a/docs/RESTORE_MATRIX.md +++ b/docs/RESTORE_MATRIX.md @@ -60,6 +60,9 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`. | Glance | Git / Borg-Repo | Repo-Konfiguration unter `ops/glance/config/glance.yml`; keine kritische Datenpersistenz | keine | `GLANCE_IMMICH_API_KEY`, `GLANCE_ADGUARD_USERNAME`, `GLANCE_ADGUARD_PASSWORD`, `GLANCE_SPEEDTEST_API_KEY` | Traefik, Authelia, optional interne API-Ziele | Dashboard startet, Widgets laden, Docker-Status laeuft nur ueber `glance-docker-socket-proxy` | | ntfy | Borg / Share | `/mnt/user/appdata/ntfy` | keine | keine besonderen Secret-Dateien dokumentiert | Traefik | UI und Push-Endpunkt erreichbar | | Paperless-GPT | Borg / Share | `/mnt/user/appdata/paperless-gpt` | keine eigene DB | `PAPERLESS_API_TOKEN`, `OPENAI_API_KEY` | Traefik, Paperless, OpenAI API | UI startet, Konfiguration vorhanden; LLM-Provider zeigt `openai` / `gpt-5.4-mini` | +| Home Assistant | Borg + HA-native Backups + Fachrepo | `/mnt/user/appdata/homeassistant` inkl. `.storage`, `secrets.yaml`, `trusted_proxies.yaml`; Fach-YAML aus `/mnt/user/services/smart-home-kalli/home-assistant` | HA-native Backup-Artefakte unter `/mnt/user/appdata/homeassistant/backups` falls vorhanden; keine externe DB in Phase 1 | HA-Secrets in `secrets.yaml`, Integrations-Tokens in `.storage`, MQTT-Credentials, spaeter InfluxDB-Token | Traefik, `frontend_net`, `smarthome_net`, Mosquitto, Fachrepo-Clone | `https://home.kaleschke.info` zeigt Login, MQTT-Integration verbindet sich, `backup.create` funktioniert, Energy-Dashboard-Konfiguration bleibt erhalten | +| Smart-Home MQTT / Mosquitto | Borg / Share | `/mnt/user/appdata/mosquitto/config`, `/mnt/user/appdata/mosquitto/data`, `/mnt/user/appdata/mosquitto/log` | Mosquitto persistiert retained messages/subscriptions dateibasiert | `passwordfile`, `aclfile`, spaeter per-Device-User | `smarthome_net`, Home Assistant, spaeter ESPHome/Zigbee2MQTT | Container startet, HA kann sich authentifiziert verbinden, retained Testtopic bleibt nach Restart erhalten | +| Smart-Home Fachrepo | Gitea + Borg-Repo-Clone | `/mnt/user/services/smart-home-kalli` | keine | keine echten Secrets im Repo; `secrets-template/` nur Beispiele | Gitea, Home Assistant Mounts | `git status` sauber, HA liest `configuration.yaml` und `packages/` aus dem Clone | --- @@ -77,6 +80,8 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`. | InfluxDB 3 Core | historischer Altstand / Datenuebernahme | `/mnt/user/appdata/influxdb3/data`, `/mnt/user/appdata/influxdb3/plugins` | dateibasierter Object Store | `influxdb3_admin_token.json` | `monitoring-influxdb3-core` | Datenpfad wird vom Monitoring-Zielstack weitergenutzt und darf nicht blind geloescht werden | | Loki / Alloy | historischer Altstand | `/mnt/user/appdata/loki/config`, `/mnt/user/appdata/loki/data`, `/mnt/user/appdata/alloy/config` | keine primaere DB; Loki-Dateispeicher war transient | keine zusaetzlichen Secrets | nicht aktiv | Compose-Pfad aus aktivem Repo entfernt; aktuelle Logsammlung laeuft ueber `monitoring-loki`/`monitoring-promtail` | | Monitoring Stack | Rebuild + named volumes + InfluxDB-Appdata | `prometheus_data`, `loki_data`, `promtail_positions`, `grafana_data`; InfluxDB unter `/mnt/user/appdata/influxdb3/data` und `/mnt/user/appdata/influxdb3/plugins`; Provisioning aus `monitoring/grafana/provisioning` | Prometheus-TSDB, Loki-Dateispeicher und InfluxDB-Dateistore; Diagnose-/Langzeitdaten, keine Tier-1-Restore-Quelle | `monitoring_grafana_admin_password.txt`, `monitoring_grafana_influxdb_token.txt`, `influxdb3_admin_token.json` | `monitoring_net`, `monitoring_influx_lan`, `frontend_net`, Traefik, Authelia, Docker socket read-only fuer Promtail, Host-Mounts fuer node-exporter/cAdvisor | `https://monitoring.kaleschke.info` leitet zu Authelia; Prometheus Targets sind up; Grafana-Datasources `Prometheus`, `Loki` und `InfluxDB 3 Core` funktionieren | +| Zigbee2MQTT (geplant) | Borg + Fachrepo | `/mnt/user/appdata/zigbee2mqtt` inkl. `configuration.yaml`, `database.db`, `coordinator_backup.json`, `state.json`; Fach-Doku im Repo `smart-home-kalli` | keine externe DB | `network_key`, MQTT-Credentials, LAN-Koordinator-IP/Firmwarestand | Mosquitto, LAN-PoE-Koordinator, `smarthome_net` | Z2M startet, Coordinator verbindet sich, geraete bleiben gepairt, Testgeraet sendet MQTT-State | +| ESPHome (geplant) | Fachrepo + Borg fuer Build-/Runtime-State | `/mnt/user/appdata/esphome` falls Dashboard/Build-Cache genutzt wird; YAML unter `/mnt/user/services/smart-home-kalli/esphome` | keine | ESPHome-Secrets ausserhalb Git, API-/OTA-Keys | WLAN/LAN, Mosquitto falls MQTT genutzt wird | Dashboard startet, ein Testgeraet kompiliert/validiert, OTA/API-Verbindung funktioniert | | Hermes Agent | VM-seitig offen | `/mnt/user/appdata/hermes-agent/data`, `/mnt/user/appdata/hermes-agent/ssh` | keine eigene DB | Host-`.env` fuer Provider-/API-/Home-Assistant-Tokens, `hermes_runner_id_ed25519`, `HERMES_DASHBOARD_HOST` | separate Hermes-VM/Runner, Traefik, Authelia, `hermes_net` | NAS-Stack nicht starten, solange Runner-VM und echte `.env` fehlen | | ddns-updater | Rebuildbar | geringe Persistenzrelevanz | keine | Provider-Zugang ueber Stack ENV | Internetzugang | Update-Job laeuft | @@ -180,4 +185,4 @@ Verbleibende offene Restore-Pfade ohne vollstaendigen Test: Die Ablaeufe je Dienst liegen als Runbooks und automatisierte Skripte unter `ops/restore-tests/` (Einstieg: `ops/restore-tests/README.md`). Fuer die noch offenen Pfade: `ops/restore-tests/unraid-flash-runbook.md` und -`ops/restore-tests/tailscale-runbook.md`. \ No newline at end of file +`ops/restore-tests/tailscale-runbook.md`. diff --git a/docs/SERVICE_CATALOG.md b/docs/SERVICE_CATALOG.md index e788cef..f49ece3 100644 --- a/docs/SERVICE_CATALOG.md +++ b/docs/SERVICE_CATALOG.md @@ -75,11 +75,18 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und | `monitoring-promtail` | Docker-Log-Collector fuer Monitoring-Loki | `monitoring/docker-compose.yml`, `monitoring/promtail/promtail-config.yml` | intern | Docker socket read-only, Docker json-file Logs, Loki | named volume `promtail_positions` | rebuildbar | nein | Dokumentierte Host-Observability-Ausnahme: `/var/run/docker.sock:/var/run/docker.sock:ro` und `/var/lib/docker/containers:ro`; keine Appdaten, nur Log-Discovery | | `monitoring-node-exporter` | Host-Metriken fuer Prometheus | `monitoring/docker-compose.yml` | intern `:9100` | Host `/proc`, `/sys`, `/` read-only, Prometheus | kein kritischer Zustand | rebuildbar | nein | Host-Observability-Ausnahme mit read-only Rootfs/Proc/Sys-Mounts | | `monitoring-cadvisor` | Container-Metriken fuer Prometheus | `monitoring/docker-compose.yml` | intern `:8080` | Docker/Host read-only Mounts, Prometheus | kein kritischer Zustand | rebuildbar | nein | Host-Observability-Ausnahme fuer Container-Metriken; keine direkten Ports | -| `monitoring-influxdb3-core` | InfluxDB 3 Core fuer Home-Assistant-/Ecowitt-Langzeitdaten | `monitoring/docker-compose.yml` | Host-Port `8181` je `INFLUXDB_BIND_IP`, keine Public URL | Monitoring-Grafana, Home Assistant Writer | `/mnt/user/appdata/influxdb3/data`, `/mnt/user/appdata/influxdb3/plugins` | Tier 3 | nein | 2026-05-31 effektiv auf `127.0.0.1:8181` gebunden, also nicht LAN-exponiert; `user: "0"` ist fuer den lokalen Object-Store-Pfad dokumentiert; uebernimmt den bisherigen InfluxDB-Daten-/Token-Katalog; `401 Unauthorized` beim Curl ohne Token ist erwarteter Reachability-Test | +| `monitoring-influxdb3-core` | InfluxDB 3 Core fuer Home-Assistant-/Ecowitt-Langzeitdaten | `monitoring/docker-compose.yml` | Host-Port `8181` je `INFLUXDB_BIND_IP`, keine Public URL | Monitoring-Grafana, Home Assistant Writer | `/mnt/user/appdata/influxdb3/data`, `/mnt/user/appdata/influxdb3/plugins` | Tier 3 | nein | 2026-05-31 effektiv auf `127.0.0.1:8181` gebunden, also nicht LAN-exponiert; vor dem HA-Writer muss entschieden werden, ob `INFLUXDB_BIND_IP` auf eine LAN-IP geht oder HA gezielt ein gemeinsames internes Netz mit InfluxDB bekommt. `user: "0"` ist fuer den lokalen Object-Store-Pfad dokumentiert; `401 Unauthorized` beim Curl ohne Token ist erwarteter Reachability-Test | | `hermes-gateway` | Hermes Agent Gateway/API intern | `ops/hermes-agent/docker-compose.yml` | intern `8642` auf `hermes_net` | SSH Runner (VM 192.168.178.143), LLM Provider, optional Home Assistant | `/mnt/user/appdata/hermes-agent/data`, SSH key path | Tier 3, Borg/Share | nein | NAS-Stack bleibt deaktiviert, solange die separate Hermes-VM/Runner-Seite nicht wiederhergestellt ist; kein Docker-Socket | | `hermes-dashboard` | Hermes Dashboard | `ops/hermes-agent/docker-compose.yml` | `https://hermes.kaleschke.info` via `${HERMES_DASHBOARD_HOST}` | `hermes-gateway`, Traefik + Authelia | shared read-only data mount | Tier 3, Borg/Share | ja + Authelia | Compose-Profil `dashboard`; aktuell VM-seitig offen, nicht Teil des NAS-Finalstarts | | `n8n` | Workflow-Automation; aktuell genutzt fuer Mail->LLM->Gitea-Issue (Inbox `Micha/mails`) | `apps/n8n/docker-compose.yml`, `apps/n8n/workflows/*.json` | `https://n8n.kaleschke.info` | Traefik (ohne pauschale Authelia, analog Komodo/Nextcloud), GMX IMAP, OpenAI API, Gitea API | `/mnt/user/appdata/n8n/data` (SQLite, Credentials, Workflows) | Tier 2, Borg + `n8n-data` (Credentials sind nur mit `N8N_ENCRYPTION_KEY` entschluesselbar) | ja, native Auth | Wegen Webhook-Endpunkten (`/webhook/*`) bewusst ohne `authelia@file`; eigene Login-/Owner-Auth bleibt Pflicht; `N8N_ENCRYPTION_KEY` ist Stack-ENV-Pflichtsecret, Verlust macht Credentials unbrauchbar. | +## Smart Home + +| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs | +|---|---|---|---|---|---|---|---|---| +| `homeassistant` | Zentrale Smart-Home-Steuerung, Energy Dashboard, Integrations-Hub | Runtime: `smart-home/docker-compose.yml`; Fachkonfiguration: Repo `smart-home-kalli` | `https://home.kaleschke.info`; kein direkter Host-Port in Phase 1 | Traefik, `frontend_net`, `smarthome_net`, `smarthome-mosquitto`, Fachrepo unter `/mnt/user/services/smart-home-kalli` | `/mnt/user/appdata/homeassistant` inkl. `.storage`, `secrets.yaml`, `trusted_proxies.yaml`; YAML-Fachdateien read-only aus `/mnt/user/services/smart-home-kalli/home-assistant` | Tier 2, Borg + HA-native Backups; Restore-Probe Pflicht vor produktiven Energie-Automationen | ja, native HA-Auth | HA Container statt HAOS-VM; keine Add-ons, keine Supervised-Installation. `configuration.yaml` kommt aus dem Fachrepo, `.storage` wird nicht versioniert. `http.use_x_forwarded_for` und `trusted_proxies` muessen zur Traefik-Route passen. Ecowitt-HTTP bleibt Phase-2-Entscheidung wegen globalem Traefik-Redirect. | +| `smarthome-mosquitto` | MQTT-Broker fuer HA, spaeter ESPHome und Zigbee2MQTT | `smart-home/docker-compose.yml`, `smart-home/mosquitto/config/mosquitto.conf` | intern `smarthome_net:1883`; kein LAN-Port in Phase 1 | `smarthome_net`, Passwort-/ACL-Dateien in Appdata | `/mnt/user/appdata/mosquitto/config`, `/mnt/user/appdata/mosquitto/data`, `/mnt/user/appdata/mosquitto/log` | Tier 2, Borg; Passwortdatei, ACLs und persistente Broker-Daten relevant | nein | LAN-Port `1883` erst in ESPHome-Phase mit ACLs und per-Device-Usern. | + ## Host Operations | Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs | diff --git a/docs/runbooks/smart-home-bootstrap.md b/docs/runbooks/smart-home-bootstrap.md new file mode 100644 index 0000000..1fc36af --- /dev/null +++ b/docs/runbooks/smart-home-bootstrap.md @@ -0,0 +1,85 @@ +# Smart-Home Bootstrap + +Ziel: Den Stack `smart-home/` auf Kallilabcore initial startklar machen, ohne +Secrets oder UI-State ins Git zu schreiben. + +## 1. Fachrepo auf dem Host bereitstellen + +```sh +cd /mnt/user/services +git clone https://git.kaleschke.info/Micha/smart-home-kalli.git smart-home-kalli +cd smart-home-kalli +git checkout main +``` + +Der Home-Assistant-Container mountet daraus einzelne YAML-Dateien read-only nach +`/config`. + +## 2. Home-Assistant-Appdata vorbereiten + +```sh +mkdir -p /mnt/user/appdata/homeassistant +cp /mnt/user/services/smart-home-kalli/secrets-template/secrets.yaml.example \ + /mnt/user/appdata/homeassistant/secrets.yaml +cp /mnt/user/services/smart-home-kalli/secrets-template/trusted_proxies.yaml.example \ + /mnt/user/appdata/homeassistant/trusted_proxies.yaml +``` + +Danach `trusted_proxies.yaml` auf das echte Traefik-/`frontend_net`-Subnetz +anpassen: + +```sh +docker network inspect frontend_net +``` + +## 3. Mosquitto vorbereiten + +```sh +mkdir -p /mnt/user/appdata/mosquitto/config \ + /mnt/user/appdata/mosquitto/data \ + /mnt/user/appdata/mosquitto/log + +docker run --rm -it \ + -v /mnt/user/appdata/mosquitto/config:/mosquitto/external_config \ + eclipse-mosquitto:2.0.22 \ + mosquitto_passwd -c /mosquitto/external_config/passwordfile homeassistant + +cat > /mnt/user/appdata/mosquitto/config/aclfile <<'EOF' +user homeassistant +topic readwrite # +EOF +``` + +Das initiale Passwort anschliessend in +`/mnt/user/appdata/homeassistant/secrets.yaml` eintragen. LAN-Port `1883` bleibt +in Phase 1 geschlossen. + +## 4. Stack deployen + +Komodo-Stack: + +- Repo: `homelab-infra` +- Pfad: `smart-home/docker-compose.yml` +- Branch: nach Review `master` + +Nach dem Start pruefen: + +```sh +docker ps --filter name=homeassistant +docker ps --filter name=smarthome-mosquitto +docker logs --tail=100 homeassistant +docker logs --tail=100 smarthome-mosquitto +``` + +## 5. Smoke-Test + +- `https://home.kaleschke.info` zeigt die Home-Assistant-Oberflaeche. +- Keine Trusted-Proxy-Fehler im HA-Log. +- MQTT-Integration verbindet sich mit Host `smarthome-mosquitto`, Port `1883`. +- HA-native Backup-Erstellung funktioniert. + +## 6. Abnahmebedingung + +Vor produktiven Energie-Automationen muss ein Restore-Test fuer +`/mnt/user/appdata/homeassistant`, `/mnt/user/appdata/mosquitto` und den Clone +`/mnt/user/services/smart-home-kalli` dokumentiert sein. diff --git a/ops/borg-ui/BACKUP_SCOPE.md b/ops/borg-ui/BACKUP_SCOPE.md index 35c788a..c3b0b0a 100644 --- a/ops/borg-ui/BACKUP_SCOPE.md +++ b/ops/borg-ui/BACKUP_SCOPE.md @@ -48,6 +48,10 @@ The Unraid flash configuration archive is intentional as well and must be treate | Grafana | SQLite dump from `monitoring_grafana_data` + provisioned config in Git | `/local/borg-dumps`, `monitoring/grafana/provisioning`, `monitoring/grafana/dashboards` | | Filebrowser | file-backed state dump + file data | `/local/borg-dumps`, `/local/appdata/filebrowser` | | InfluxDB 3 Core | file data | `/local/appdata/influxdb3/data`, `/local/appdata/influxdb3/plugins` | +| Home Assistant | HA-native backup + file state | `/local/appdata/homeassistant`, `/local/services/smart-home-kalli` | +| Smart-Home MQTT / Mosquitto | file data | `/local/appdata/mosquitto/config`, `/local/appdata/mosquitto/data`, `/local/appdata/mosquitto/log` | +| Zigbee2MQTT (planned) | file data + coordinator state | `/local/appdata/zigbee2mqtt`, `/local/services/smart-home-kalli` | +| ESPHome (planned) | Fachrepo + optional build/runtime cache | `/local/services/smart-home-kalli/esphome`, optional `/local/appdata/esphome` | | Hermes Agent | file data + SSH key | `/local/appdata/hermes-agent/data`, `/local/secrets/hermes_runner_id_ed25519` | | BentoPDF | rebuildable | no critical persistence in compose | @@ -87,6 +91,7 @@ The live Unraid User Scripts execute repo scripts from `/mnt/user/services/homel - SQLite: `gitea`, `vaultwarden`, `speedtest-tracker`, `borg-ui`, `grafana` - File-backed state: `filebrowser.bolt.dump` - Unraid flash config: `unraid-flash-config.tar.gz` plus `unraid-flash-config.tar.gz.sha256` +- Home Assistant native backups: created by HA under `/mnt/user/appdata/homeassistant/backups` and captured as file state ## Explicitly Not Backed Up as Raw Live DB Files diff --git a/ops/borg-ui/all-important-sources.txt b/ops/borg-ui/all-important-sources.txt index 413a06c..2ca955b 100644 --- a/ops/borg-ui/all-important-sources.txt +++ b/ops/borg-ui/all-important-sources.txt @@ -20,5 +20,9 @@ /local/appdata/komodo/periphery /local/appdata/komodo/core /local/services/homelab-infra +/local/services/smart-home-kalli /local/services/stacks /local/services/posture-check +/local/appdata/homeassistant +/local/appdata/mosquitto/config +/local/appdata/mosquitto/data diff --git a/smart-home/README.md b/smart-home/README.md new file mode 100644 index 0000000..d35cc6b --- /dev/null +++ b/smart-home/README.md @@ -0,0 +1,58 @@ +# Smart Home Runtime Stack + +Runtime-Zustand fuer Home Assistant auf Kallilabcore. Dieser Ordner gehoert zu +`homelab-infra`, weil Komodo den Stack deployt und Renovate die Images pflegt. + +## Dienste + +- `homeassistant`: Home Assistant Container, erreichbar ueber Traefik unter + `https://home.kaleschke.info` +- `smarthome-mosquitto`: interner MQTT-Broker fuer Home Assistant, spaeter + Zigbee2MQTT und ESPHome + +## Abhaengigkeiten + +- `frontend_net` existiert bereits und wird von Traefik genutzt. +- `smarthome_net` wird durch diesen Stack angelegt und ist `internal: true`. +- Das Fachrepo `smart-home-kalli` muss auf dem Unraid-Host unter + `/mnt/user/services/smart-home-kalli` liegen. Nur ausgewählte YAML-Dateien + werden read-only nach `/config` gemountet; `.storage` bleibt in + `/mnt/user/appdata/homeassistant`. +- Vor dem ersten Start muessen diese Dateien hostseitig angelegt werden: + - `/mnt/user/appdata/homeassistant/secrets.yaml` + - `/mnt/user/appdata/homeassistant/trusted_proxies.yaml` + - `/mnt/user/appdata/mosquitto/config/passwordfile` + - `/mnt/user/appdata/mosquitto/config/aclfile` + +Das detaillierte Host-Bootstrap-Runbook liegt unter +`docs/runbooks/smart-home-bootstrap.md`. + +## MQTT Bootstrap + +Beispiel fuer den initialen Home-Assistant-MQTT-User auf dem Unraid-Host: + +```sh +mkdir -p /mnt/user/appdata/mosquitto/config +docker run --rm -it \ + -v /mnt/user/appdata/mosquitto/config:/mosquitto/external_config \ + eclipse-mosquitto:2.0.22 \ + mosquitto_passwd -c /mosquitto/external_config/passwordfile homeassistant +cat > /mnt/user/appdata/mosquitto/config/aclfile <<'EOF' +user homeassistant +topic readwrite # +EOF +``` + +LAN-Port `1883` bleibt in Phase 1 geschlossen. Eine Portfreigabe fuer externe +MQTT-Clients wird erst in der ESPHome-Phase mit ACLs und per-Device-Usern +ergaenzt. + +## Ecowitt + +Ecowitt wird nicht in Phase 1 exponiert. Wegen des globalen Traefik +HTTP-zu-HTTPS-Redirects bleibt die Ingress-Entscheidung offen: + +1. Traefik-HTTP-Ausnahme nur fuer den Ecowitt-Webhook, falls der globale + EntryPoint-Redirect gezielt abloesbar ist. +2. Dokumentierter LAN-only Host-Port `8123` als Fallback, wenn Option 1 den + bestehenden Traefik-Standard zu stark verbiegt. diff --git a/smart-home/docker-compose.yml b/smart-home/docker-compose.yml new file mode 100644 index 0000000..b2a43bc --- /dev/null +++ b/smart-home/docker-compose.yml @@ -0,0 +1,56 @@ +services: + homeassistant: + image: ghcr.io/home-assistant/home-assistant:2026.6.1@sha256:59aa8824955c9db491b75d2eebe42bd68494f80c2ec69ec0d66d9dae37d37514 + container_name: homeassistant + restart: unless-stopped + environment: + TZ: Europe/Berlin + volumes: + - /mnt/user/appdata/homeassistant:/config + - /mnt/user/services/smart-home-kalli/home-assistant/configuration.yaml:/config/configuration.yaml:ro + - /mnt/user/services/smart-home-kalli/home-assistant/automations.yaml:/config/automations.yaml:ro + - /mnt/user/services/smart-home-kalli/home-assistant/scripts.yaml:/config/scripts.yaml:ro + - /mnt/user/services/smart-home-kalli/home-assistant/scenes.yaml:/config/scenes.yaml:ro + - /mnt/user/services/smart-home-kalli/home-assistant/packages:/config/packages:ro + networks: + - frontend_net + - smarthome_net + expose: + - "8123" + security_opt: + - no-new-privileges:true + depends_on: + - mosquitto + labels: + - traefik.enable=true + - traefik.docker.network=frontend_net + - traefik.http.routers.homeassistant.rule=Host(`home.kaleschke.info`) + - traefik.http.routers.homeassistant.entrypoints=websecure + - traefik.http.routers.homeassistant.tls=true + - traefik.http.routers.homeassistant.tls.certresolver=le + - traefik.http.services.homeassistant.loadbalancer.server.port=8123 + + mosquitto: + image: eclipse-mosquitto:2.0.22@sha256:914f529386804c8278a4e581526b9be5e1604df44b30daabc70aa97dcefe5268 + container_name: smarthome-mosquitto + restart: unless-stopped + volumes: + - ./mosquitto/config/mosquitto.conf:/mosquitto/config/mosquitto.conf:ro + - /mnt/user/appdata/mosquitto/config:/mosquitto/external_config + - /mnt/user/appdata/mosquitto/data:/mosquitto/data + - /mnt/user/appdata/mosquitto/log:/mosquitto/log + networks: + - smarthome_net + expose: + - "1883" + security_opt: + - no-new-privileges:true + +networks: + frontend_net: + external: true + + smarthome_net: + name: smarthome_net + driver: bridge + internal: true diff --git a/smart-home/mosquitto/config/mosquitto.conf b/smart-home/mosquitto/config/mosquitto.conf new file mode 100644 index 0000000..68ee7c9 --- /dev/null +++ b/smart-home/mosquitto/config/mosquitto.conf @@ -0,0 +1,15 @@ +per_listener_settings true + +listener 1883 0.0.0.0 +allow_anonymous false +password_file /mosquitto/external_config/passwordfile +acl_file /mosquitto/external_config/aclfile + +persistence true +persistence_location /mosquitto/data/ + +log_dest stdout +log_type error +log_type warning +log_type notice +connection_messages true