8 Commits

Author SHA1 Message Date
renovate 1422d7c09c chore(deps): update minor-and-patch-updates 2026-06-18 16:20:49 +00:00
Micha 5171059dd1 Ignore profiled services in runtime drift check 2026-06-17 22:33:15 +02:00
Micha 0ecb2aceca Refresh current homelab todo state 2026-06-17 22:30:12 +02:00
Micha 1160f50663 Clear completed Glance token todo 2026-06-17 22:04:52 +02:00
Micha 88c48faab1 Tidy AdGuard and DNS repo drift 2026-06-17 21:59:59 +02:00
Micha ec8e915a56 Classify cAdvisor startup noise 2026-06-17 21:51:55 +02:00
Micha 861f70da58 Fix operations report warnings 2026-06-17 21:49:33 +02:00
Micha fc9e4aad8e fix: raise influxdb3 query-file-limit (weather panels no data)
InfluxDB 3 Core kompaktiert nicht; haeufige HA-Writes liessen "°C"/"%"/"hPa"
ins 432-Dateien-Query-Limit laufen -> No data in Grafana. --query-file-limit
auf 20000 angehoben (Stopgap; langfristig Enterprise-Compaction oder weniger
Writes).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-16 22:19:24 +02:00
29 changed files with 205 additions and 77 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
mail-archiver: mail-archiver:
image: s1t5/mailarchiver@sha256:4ea7ecc47ad1dd2c523b85c3967574b61e39def1b6fd26edf874e21733c4018c image: s1t5/mailarchiver@sha256:9860b170040dc096aeedc47bdbb09e2913aa8742eec205e29edd0ab79f9dda7e
container_name: mail-archiver container_name: mail-archiver
restart: unless-stopped restart: unless-stopped
environment: environment:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
nextcloud: nextcloud:
image: nextcloud:33.0.5-apache@sha256:fe5166b04f217c9e3a263bfe76eef5e13de0dd3919966827de1b47bae2308b01 image: nextcloud:33.0.5-apache@sha256:56bdc45109067500fd0832fa64832b7c77a167d9394cbf5f0f4b59740b94194d
container_name: nextcloud container_name: nextcloud
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
super-productivity: super-productivity:
image: johannesjo/super-productivity:v18.9.1@sha256:773760107344e739f4c29409f7842db66a1b167d50eb2c40248cb5b5b328652e image: johannesjo/super-productivity:v18.10.0@sha256:cc548f3a1bdd31a270b195e6d2b3530689aca0db70b03d31dfcf9365d322f1f2
container_name: super-productivity container_name: super-productivity
restart: unless-stopped restart: unless-stopped
+8 -5
View File
@@ -1,14 +1,16 @@
# Authelia OIDC fuer Apps - Plan & Runbook # Authelia OIDC fuer Apps - Plan & Runbook
Stand: 2026-06-06. Authelia-Version: **v4.39.20**. Stand: 2026-06-17. Authelia-Version: **v4.39.20**.
Ziel: App-uebergreifendes Single-Sign-On ueber Authelia als OpenID-Connect-Provider Ziel: App-uebergreifendes Single-Sign-On ueber Authelia als OpenID-Connect-Provider
(`https://auth.kaleschke.info`). Statt pro App eigener Logins meldet man sich einmal (`https://auth.kaleschke.info`). Statt pro App eigener Logins meldet man sich einmal
bei Authelia an (inkl. 2FA) und wird per OIDC an die App durchgereicht. bei Authelia an (inkl. 2FA) und wird per OIDC an die App durchgereicht.
> **Status:** aktives Runbook. Grafana und Mealie sind seit 2026-06-06 live > **Status:** aktives Runbook. Grafana und Mealie sind seit 2026-06-06 live
> und per Login-Smoke verifiziert. Der weitere Rollout bleibt additiv: lokale > und per Login-Smoke verifiziert. Paperless ist seit 2026-06-17 technisch
> App-Logins bleiben als Fallback aktiv. > verdrahtet (Authelia-Client + Stack-ENV-Secret + Service-Smoke gruen);
> finaler Browser-Login mit Operator-Account bleibt offen. Der Rollout bleibt
> additiv: lokale App-Logins bleiben als Fallback aktiv.
--- ---
@@ -85,7 +87,7 @@ docker exec authelia authelia crypto hash generate pbkdf2 \
| 2 | Immich | `immich.kaleschke.info` | nativ (Admin-UI/Config-File) | s. u. (Familie) | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** nur `micha` hat Authelia-Account, Familien-SSO-Nutzen entsteht erst mit Familien-Accounts; Immich ist mobil-lastig (hoechste Stoeranfaelligkeit) und braucht UI/Config-File. Erst nach Onboarding gezielt. Runbook bereit. | | 2 | Immich | `immich.kaleschke.info` | nativ (Admin-UI/Config-File) | s. u. (Familie) | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** nur `micha` hat Authelia-Account, Familien-SSO-Nutzen entsteht erst mit Familien-Accounts; Immich ist mobil-lastig (hoechste Stoeranfaelligkeit) und braucht UI/Config-File. Erst nach Onboarding gezielt. Runbook bereit. |
| 3 | Nextcloud | `cloud.kaleschke.info` | App `user_oidc` (+occ) | s. u. | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** wie Immich; braucht `user_oidc`-App-Install + `occ`. Lokaler Login bleibt. Erst nach Onboarding. Runbook bereit. | | 3 | Nextcloud | `cloud.kaleschke.info` | App `user_oidc` (+occ) | s. u. | mittel | **GEPARKT bis Onboarding (Entscheidung 2026-06-06):** wie Immich; braucht `user_oidc`-App-Install + `occ`. Lokaler Login bleibt. Erst nach Onboarding. Runbook bereit. |
| **4 ERLEDIGT 2026-06-06** | Mealie | `mealie.kaleschke.info` | nativ | `one_factor` | niedrig | **Live + Login verifiziert.** OIDC-Env additiv (lokaler Login bleibt), Secret als Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}`, `extra_hosts` noetig (s. Gotchas) | | **4 ERLEDIGT 2026-06-06** | Mealie | `mealie.kaleschke.info` | nativ | `one_factor` | niedrig | **Live + Login verifiziert.** OIDC-Env additiv (lokaler Login bleibt), Secret als Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}`, `extra_hosts` noetig (s. Gotchas) |
| 5 | Paperless-ngx | `paperless.kaleschke.info` | `django-allauth` (Umgebungsvariablen) | `two_factor` | mittel | dokumentenlastig, Operator-nah | | **5 TEILWEISE ERLEDIGT 2026-06-17** | Paperless-ngx | `paperless.kaleschke.info` | `django-allauth` (Umgebungsvariablen) | `one_factor` (hostseitiger Ist-Stand; `two_factor` spaeter moeglich) | mittel | **Authelia-Client + `${PAPERLESS_OIDC_SECRET}` in Stack-ENV gesetzt, Authelia-Config validiert, Paperless HTTP-Smoke `200`.** Lokaler Login bleibt Fallback; finaler Browser-Login mit Operator-Account offen. |
**Nicht OIDC:** Vaultwarden hat kein Standard-Endnutzer-OIDC (SSO ist Enterprise/Bitwarden-Feature) -> bleibt eigener Login. ntfy bleibt wie gehabt. **Nicht OIDC:** Vaultwarden hat kein Standard-Endnutzer-OIDC (SSO ist Enterprise/Bitwarden-Feature) -> bleibt eigener Login. ntfy bleibt wie gehabt.
@@ -175,7 +177,8 @@ GF_AUTH_GENERIC_OAUTH_ALLOW_SIGN_UP=true
E-Mail-Claim. Stimmt die Authelia-E-Mail mit dem App-Account, wird verknuepft; E-Mail-Claim. Stimmt die Authelia-E-Mail mit dem App-Account, wird verknuepft;
sonst legt die App (bei aktivem Signup) einen neuen User an. sonst legt die App (bei aktivem Signup) einen neuen User an.
- **Secret-Mechanik je App verschieden:** Grafana `__FILE` (Docker-Secret), - **Secret-Mechanik je App verschieden:** Grafana `__FILE` (Docker-Secret),
Mealie Stack-ENV `${...}`. Hash immer in der Authelia-Host-Config, Klartext nie ins Repo. Mealie Stack-ENV `${MEALIE_OIDC_CLIENT_SECRET}`, Paperless Stack-ENV
`${PAPERLESS_OIDC_SECRET}`. Hash immer in der Authelia-Host-Config, Klartext nie ins Repo.
## Spaetere Feinschliffe vor breitem Rollout ## Spaetere Feinschliffe vor breitem Rollout
+5 -8
View File
@@ -1,6 +1,6 @@
# Master To-do - KalliLab CORE # Master To-do - KalliLab CORE
Typ: Status/To-do · Stand: 2026-06-12 · Status: aktiv Typ: Status/To-do · Stand: 2026-06-17 · Status: aktiv
Diese Liste ist die **einzige** Arbeitsliste fuer offene operative Punkte im Diese Liste ist die **einzige** Arbeitsliste fuer offene operative Punkte im
Homelab. Detailablaeufe stehen in den verlinkten Runbooks; Entscheidungen mit Homelab. Detailablaeufe stehen in den verlinkten Runbooks; Entscheidungen mit
@@ -23,10 +23,8 @@ Host-Reports (`/mnt/user/backups/restore-reports/`) und in der Git-Historie.
| Family-Onboarding erster Termin | Operator | Checkliste ist fertig (`docs/FAMILY_ONBOARDING.md` Abschnitt "Erster Onboarding-Termin"). Personen/Geraete festlegen, Reihenfolge Vaultwarden -> Immich -> Mealie pro Person abarbeiten | `docs/FAMILY_ONBOARDING.md` | | Family-Onboarding erster Termin | Operator | Checkliste ist fertig (`docs/FAMILY_ONBOARDING.md` Abschnitt "Erster Onboarding-Termin"). Personen/Geraete festlegen, Reihenfolge Vaultwarden -> Immich -> Mealie pro Person abarbeiten | `docs/FAMILY_ONBOARDING.md` |
| Restore-Test Unraid OS Flash (Stick-Boot) | Operator | Artefakt-Validierung 2026-06-05 erledigt (`ops/maintenance/check-unraid-flash-backup.sh`). **Verbleibt:** physischer Ersatzstick-Boot-Test, wenn ein Wegwerf-Stick bereitliegt | `ops/restore-tests/unraid-flash-runbook.md` | | Restore-Test Unraid OS Flash (Stick-Boot) | Operator | Artefakt-Validierung 2026-06-05 erledigt (`ops/maintenance/check-unraid-flash-backup.sh`). **Verbleibt:** physischer Ersatzstick-Boot-Test, wenn ein Wegwerf-Stick bereitliegt | `ops/restore-tests/unraid-flash-runbook.md` |
| Restore-Test Tailscale | Operator | State-Validierung + Reconnect nur auf Wegwerf-Host/VM, danach Geraet in Tailscale-Admin entfernen | `ops/restore-tests/tailscale-runbook.md` | | Restore-Test Tailscale | Operator | State-Validierung + Reconnect nur auf Wegwerf-Host/VM, danach Geraet in Tailscale-Admin entfernen | `ops/restore-tests/tailscale-runbook.md` |
| Authelia OIDC fuer Apps | Operator/Claude | Live: Grafana + Mealie (verifiziert), Paperless deployed (Login-Test offen). Immich + Nextcloud bewusst geparkt bis Family-Onboarding (siehe `docs/DECISIONS.md` 2026-06-06) | `docs/AUTHELIA_OIDC_PLAN.md` | | Authelia OIDC fuer Apps | Operator/Codex | Live: Grafana + Mealie login-verifiziert; Paperless Secret verdrahtet und Service-Smoke am 2026-06-17 gruen, finaler Browser-Login mit Operator-Account offen. Immich + Nextcloud bewusst geparkt bis Family-Onboarding (siehe `docs/DECISIONS.md` 2026-06-06) | `docs/AUTHELIA_OIDC_PLAN.md` |
| Glance-v2-Widgets: Tokens setzen | Operator | In Komodo Stack-ENV fuer `ops-glance` setzen: `GLANCE_KOMODO_API_KEY`/`_SECRET` (Komodo read-only API-Key), `GLANCE_GITEA_TOKEN` (read-only, scope `read:repository`), `GLANCE_PAPERLESS_TOKEN`, `GLANCE_MEALIE_TOKEN`; bis dahin zeigen die neuen Widgets Fehler/leer. Speedtest-Widget: falls weiter 0.0, API-Response pruefen | `ops/glance/config/` |
| Home Assistant Tibber | Operator/Codex | Tibber per HA-UI-Config-Flow verbinden. Danach Energy-Dashboard um echte Kosten/Preisquelle ergaenzen; SolarEdge-PV, Netz und Speicher sind bereits konfiguriert und validiert | `docs/runbooks/smart-home-bootstrap.md`, `docs/DECISIONS.md` | | Home Assistant Tibber | Operator/Codex | Tibber per HA-UI-Config-Flow verbinden. Danach Energy-Dashboard um echte Kosten/Preisquelle ergaenzen; SolarEdge-PV, Netz und Speicher sind bereits konfiguriert und validiert | `docs/runbooks/smart-home-bootstrap.md`, `docs/DECISIONS.md` |
| Audit-PDF aus `docs/` entfernen | Operator | `docs/KalliLab_CORE_Audit_2026-06-06.pdf` (untracked) extern ablegen (H:/ oder Documents-Share) und lokal loeschen; Binaerdateien gehoeren nicht ins GitOps-Repo | Doku-Regeln `docs/REPO_MAP.md` |
--- ---
@@ -50,7 +48,6 @@ Bewusst nicht jetzt - Begruendungen in `docs/DECISIONS.md`, hier nur Thema und T
| CrowdSec vor Traefik | breitere Attack Surface als nur `443/tcp` | `docs/DECISIONS.md` | | CrowdSec vor Traefik | breitere Attack Surface als nur `443/tcp` | `docs/DECISIONS.md` |
| Nextcloud 2FA (Operator-TOTP) | OIDC-/SSO-Block erreicht die App-Login-Ebene | `docs/DECISIONS.md` | | Nextcloud 2FA (Operator-TOTP) | OIDC-/SSO-Block erreicht die App-Login-Ebene | `docs/DECISIONS.md` |
| Hermes-Agent | Review-Deadline 2026-07-25; NAS-Stack bleibt deaktiviert | `docs/SERVICE_CATALOG.md` | | Hermes-Agent | Review-Deadline 2026-07-25; NAS-Stack bleibt deaktiviert | `docs/SERVICE_CATALOG.md` |
| Tailnet-Konsole aufraeumen (Rest) | trivial, bei Gelegenheit: tote Node-Eintraege (`kallilab-core`, alter `baerchen`) in der Tailscale-Admin-Konsole entfernen; optional State-Pfad `/mnt/user/appdata/tailscale` nach `_archive/` | `docs/NETWORK_INVENTORY.md` |
| Dedizierter SMB-User `veeam-baerchen` | nur wenn Unraid-User-/Share-Rechte bewusst angefasst werden | `ops/windows-reinstall/docs/windows-image-backup-baseline.md` | | Dedizierter SMB-User `veeam-baerchen` | nur wenn Unraid-User-/Share-Rechte bewusst angefasst werden | `ops/windows-reinstall/docs/windows-image-backup-baseline.md` |
| Filebrowser-Mount-Scope | naechster Hardening-Sprint | `docs/SERVICE_CATALOG.md` | | Filebrowser-Mount-Scope | naechster Hardening-Sprint | `docs/SERVICE_CATALOG.md` |
| Scrutiny Privileged-Ausnahme | nur mit klarer Begruendung aendern | `docs/SERVICE_CATALOG.md` | | Scrutiny Privileged-Ausnahme | nur mit klarer Begruendung aendern | `docs/SERVICE_CATALOG.md` |
@@ -71,11 +68,11 @@ Bewusst nicht jetzt - Begruendungen in `docs/DECISIONS.md`, hier nur Thema und T
## Zuletzt erledigt (Kurzlog, max. 5 Eintraege) ## Zuletzt erledigt (Kurzlog, max. 5 Eintraege)
- **2026-06-17** Offene TODOs gegen Live-Stand abgeglichen: Paperless-OIDC-Secret verdrahtet und Service-Smoke gruen; alter Tailscale-Docker-State nach `_archive/tailscale-removed-2026-06-06/` verschoben; Tailnet-Restpunkt geschlossen.
- **2026-06-17** Repo-Hygiene abgeschlossen: Glance-Widget-Tokens sind in Runtime gesetzt, Audit-PDF liegt extern unter `H:\kallilab-recovery\audits`, Worktree clean.
- **2026-06-17** Komodo/Gitea-Webhooks normalisiert: aktive Komodo-Hooks fuer `Micha/homelab-infra` nutzen Branch-Filter `master`; DB-Backup vor Host-Hotfix erstellt. Workflow-Regel nachgezogen.
- **2026-06-13** Home Assistant MQTT-Integration produktiv verbunden: Config-Entry `smarthome-mosquitto` ist `loaded`, Mosquitto sieht den HA-Client `homeassistant`; `check_config` gruen. - **2026-06-13** Home Assistant MQTT-Integration produktiv verbunden: Config-Entry `smarthome-mosquitto` ist `loaded`, Mosquitto sieht den HA-Client `homeassistant`; `check_config` gruen.
- **2026-06-13** HA Energy Dashboard konfiguriert: Netz, PV und Speicher aus SolarEdge Local gesetzt, `energy/validate` ohne Issues; HA-Backup danach erzeugt. - **2026-06-13** HA Energy Dashboard konfiguriert: Netz, PV und Speicher aus SolarEdge Local gesetzt, `energy/validate` ohne Issues; HA-Backup danach erzeugt.
- **2026-06-13** SolarEdge lokal angebunden: `solaredge_modbus_multi` v3.2.5 ueber `192.168.178.111:1502`, Device-ID `1`; 68 Entitaeten inkl. Inverter, Smart Meter und Batterie; HA-Backup danach erzeugt.
- **2026-06-13** Home Assistant Restore-Probe erfolgreich: isolierter Test aus HA-native Backup + Mosquitto-Appdata + Fachrepo-Clone, HA HTTP/API/check_config gruen, MQTT Publish/Subscribe und retained Topic nach Broker-Restart gruen. Report: `/mnt/user/backups/restore-reports/homeassistant-2026-06-13.md`.
- **2026-06-13** Home Assistant Foundation live: `smart-home` in Komodo angelegt, Gitea-Webhook aktiv, Authelia-Onboarding-Guard entfernt, HA-native Auth + Login-Ban aktiv, HA-Backup erzeugt/geprueft und MQTT-Broker-Smoke erfolgreich.
--- ---
+17 -18
View File
@@ -1,7 +1,7 @@
# Network Inventory - KalliLab CORE # Network Inventory - KalliLab CORE
Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI bereinigt; FRITZ!Box-Remote-Dienste aus; IPv6-Exposure technisch und per UI entschaerft; Tailscale-Inventar am 2026-06-05 real gemessen. Status: Host-Audit erfasst; Router-Baseline und Portfreigaben-UI bereinigt; FRITZ!Box-Remote-Dienste aus; IPv6-Exposure technisch und per UI entschaerft; Tailscale-Inventar am 2026-06-17 real gemessen.
Letzte Pruefung: 2026-06-05 (Tailscale-Inventar), 2026-06-01 (Router/Ports) Letzte Pruefung: 2026-06-17 (Tailscale-Inventar), 2026-06-01 (Router/Ports)
## Zweck ## Zweck
@@ -38,7 +38,7 @@ Dieses Dokument beschreibt Router, DNS, Tailscale, Portfreigaben und Netztrennun
| Komponente | Rolle | Adresse | Bemerkung | | Komponente | Rolle | Adresse | Bemerkung |
|---|---|---|---| |---|---|---|---|
| AdGuard Home | LAN DNS / Filter | Host `192.168.178.58`, Docker `172.23.0.3` | DNS auf Port 53; Admin soll nur via Tailscale-IP `100.80.98.33:8082` erreichbar sein | | AdGuard Home | LAN DNS / Filter | Host `192.168.178.58`, Docker `172.23.0.3` | DNS auf Port 53; Admin soll nur via Tailscale-IP `100.80.98.33:8082` erreichbar sein |
| Unbound | Rekursiver Resolver | Docker `dns_net` | Upstream fuer AdGuard | | Unbound | DNSSEC-validierender Forwarding-Resolver | Docker `dns_net` | Upstream fuer AdGuard; forwardet per DoT zu Cloudflare, keine Root-Rekursion |
| Cloudflare | Authoritative DNS | extern | DNS-Challenge fuer TLS | | Cloudflare | Authoritative DNS | extern | DNS-Challenge fuer TLS |
| Router | DHCP DNS-Verteilung | TBD | Muss auf AdGuard zeigen, falls so betrieben | | Router | DHCP DNS-Verteilung | TBD | Muss auf AdGuard zeigen, falls so betrieben |
@@ -57,18 +57,16 @@ Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`,
| Subnet Router | **Ja, aktiv.** Host advertised und ist Primary fuer `192.168.178.0/24` (`Self.PrimaryRoutes: ["192.168.178.0/24"]`, ebenfalls in `AllowedIPs`). Das LAN ist also fuer das gesamte Tailnet ueber diesen Subnet-Router erreichbar — bewusst gemessener Ist-Zustand, **kein** "keine Route" wie zuvor vermutet. | | Subnet Router | **Ja, aktiv.** Host advertised und ist Primary fuer `192.168.178.0/24` (`Self.PrimaryRoutes: ["192.168.178.0/24"]`, ebenfalls in `AllowedIPs`). Das LAN ist also fuer das gesamte Tailnet ueber diesen Subnet-Router erreichbar — bewusst gemessener Ist-Zustand, **kein** "keine Route" wie zuvor vermutet. |
| ACL-Policy extern dokumentiert | **Angewendet 2026-06-06** — restriktive Tag-basierte `grants`-Policy live (`tag:server`/`tag:operator`, `tag:family` schlafend). Default-Allow entfernt, verifiziert. Details im Block unten. | | ACL-Policy extern dokumentiert | **Angewendet 2026-06-06** — restriktive Tag-basierte `grants`-Policy live (`tag:server`/`tag:operator`, `tag:family` schlafend). Default-Allow entfernt, verifiziert. Details im Block unten. |
### Tailnet-Geraete (Snapshot 2026-06-05) ### Tailnet-Geraete (Snapshot 2026-06-17)
| Tailscale-IP | Node | OS | Status | | Tailscale-IP | Node | OS | Status |
|---|---|---|---| |---|---|---|---|
| `100.80.98.33` | kallilabcore | linux | aktiv (Host, Subnet-Router) | | `100.80.98.33` | kallilabcore | linux | aktiv (Host, Subnet-Router) |
| `100.78.133.37` | baerchen-1 | windows | aktiv (aktuelle Operator-Workstation, direct) | | `100.78.133.37` | baerchen-1 | windows | aktiv (aktuelle Operator-Workstation, direct) |
| `100.105.203.21` | baerchen | windows | offline, zuletzt vor ~1 Tag gesehen (Alt-Node) | | `100.73.83.55` | iphone-14 | iOS | bekannt, aktuell offline |
| `100.73.83.55` | iphone-14 | iOS | bekannt |
| `100.112.0.90` | kallilab-core | linux | **am 2026-06-06 entfernt.** War der redundante userspace-only `Tailscale-Docker`-Stack (`host-services/tailscale/`). Komodo-Stack gestoppt+destroyed, Repo-Pfad per `git rm` entfernt, Container weg (read-only verifiziert). Node-Eintrag in der Admin-Konsole noch zu entfernen. |
> **Befund 2026-06-06 (read-only auf dem Host ermittelt):** Der Host hat **zwei** > **Historischer Befund 2026-06-06 (read-only auf dem Host ermittelt):** Der Host
> `tailscaled`-Prozesse: > hatte damals **zwei** `tailscaled`-Prozesse:
> >
> 1. **Native Unraid-Plugin** = `kallilabcore` (100.80.98.33). Prozess > 1. **Native Unraid-Plugin** = `kallilabcore` (100.80.98.33). Prozess
> `/usr/local/sbin/tailscaled -statedir /boot/config/plugins/tailscale/state > `/usr/local/sbin/tailscaled -statedir /boot/config/plugins/tailscale/state
@@ -89,9 +87,10 @@ Gemessen am 2026-06-05 per read-only SSH auf den Host (`tailscale status`,
> (Operator), `git rm host-services/tailscale/`, Glance-Widget entfernt, und > (Operator), `git rm host-services/tailscale/`, Glance-Widget entfernt, und
> Architektur-/Service-Catalog-/DR-/CLAUDE-Doku auf "natives Plugin" nachgezogen. > Architektur-/Service-Catalog-/DR-/CLAUDE-Doku auf "natives Plugin" nachgezogen.
> Read-only verifiziert: Container weg, nur noch der native `tailscaled` mit > Read-only verifiziert: Container weg, nur noch der native `tailscaled` mit
> `tailscale1`, Subnet-Route + Operator-Zugriff intakt. Offen: Node-Eintraege > `tailscale1`, Subnet-Route + Operator-Zugriff intakt. Nachpruefung 2026-06-17:
> `kallilab-core` und alter `baerchen` in der Admin-Konsole entfernen; State-Pfad > `tailscale status --self=false` zeigt nur noch `baerchen-1` und `iphone-14`;
> `/mnt/user/appdata/tailscale` bei Gelegenheit nach `_archive/` (kein Sofort-Loeschen). > der alte State-Pfad `/mnt/user/appdata/tailscale` ist weg und liegt archiviert
> unter `/mnt/user/appdata/_archive/tailscale-removed-2026-06-06/`.
> >
> **Doku-Korrektur erledigt:** `docs/RESTORE_MATRIX.md` zeigt jetzt auf den > **Doku-Korrektur erledigt:** `docs/RESTORE_MATRIX.md` zeigt jetzt auf den
> funktionalen State `/boot/config/plugins/tailscale/state` (im Flash-Backup) > funktionalen State `/boot/config/plugins/tailscale/state` (im Flash-Backup)
@@ -155,8 +154,8 @@ erhalten.
``` ```
**Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14` **Geraete-Tags (live):** `kallilabcore` = `tag:server`; `baerchen-1` + `iphone-14`
= `tag:operator`; `kallilab-core` (Docker) + alter `baerchen` bewusst untagged -> = `tag:operator`. Alte Nodes `kallilab-core` und `baerchen` sind nicht mehr im
isoliert. aktuellen Tailnet-Status sichtbar.
**Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):** **Rollout-Protokoll 2026-06-06 (lockout-sicher, je Schritt read-only verifiziert):**
@@ -193,10 +192,10 @@ ist die vollstaendige Wahrheit.
- Familien-Dienste/Ports konkretisieren — erst wenn ein reales Familiengeraet dazukommt. - Familien-Dienste/Ports konkretisieren — erst wenn ein reales Familiengeraet dazukommt.
- **Zwei-Tailscale-Konsolidierung: ERLEDIGT 2026-06-06** — redundanter Docker-Stack - **Zwei-Tailscale-Konsolidierung: ERLEDIGT 2026-06-06** — redundanter Docker-Stack
abgebaut, nur noch die native Plugin-Instanz `kallilabcore` (Subnet-Router) aktiv. abgebaut, nur noch die native Plugin-Instanz `kallilabcore` (Subnet-Router) aktiv.
- **Tailnet-Konsole aufraeumen: ERLEDIGT 2026-06-06** — Node-Eintraege `kallilab-core` - **Tailnet-Konsole/Altstate aufraeumen: ERLEDIGT 2026-06-17** — Node-Eintraege
und alter Offline-`baerchen` aus der Admin-Konsole entfernt. `kallilab-core` und alter Offline-`baerchen` sind im aktuellen Tailnet-Status
- State-Pfad `/mnt/user/appdata/tailscale` (vom entfernten Docker-Stack) bei nicht mehr sichtbar; State-Pfad `/mnt/user/appdata/tailscale` vom entfernten
Gelegenheit nach `_archive/tailscale-removed-2026-06-06/` (kein Sofort-Loeschen). Docker-Stack liegt unter `_archive/tailscale-removed-2026-06-06/`.
- Optionaler Off-LAN-Routentest: von einem Operator-Geraet im Mobilfunk - Optionaler Off-LAN-Routentest: von einem Operator-Geraet im Mobilfunk
(nicht im Heim-LAN) ein LAN-Ziel ueber `192.168.178.0/24` erreichen, um die (nicht im Heim-LAN) ein LAN-Ziel ueber `192.168.178.0/24` erreichen, um die
Subnet-Route end-to-end zu bestaetigen (im Heim-LAN nicht sauber isolierbar). Subnet-Route end-to-end zu bestaetigen (im Heim-LAN nicht sauber isolierbar).
+2 -2
View File
@@ -29,7 +29,7 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`.
| Unraid OS Flash | Borg-Artefakt + optional Unraid Connect | `/boot/config` aus `unraid-flash-config.tar.gz` | `unraid-flash-config.tar.gz`, `.sha256`, Manifest | enthaelt sensible Host-Konfiguration, wie Secret-Material behandeln | Unraid USB Flash Creator / neuer Boot-Stick | Unraid bootet, Array-Zuordnung und Shares sind sichtbar | | Unraid OS Flash | Borg-Artefakt + optional Unraid Connect | `/boot/config` aus `unraid-flash-config.tar.gz` | `unraid-flash-config.tar.gz`, `.sha256`, Manifest | enthaelt sensible Host-Konfiguration, wie Secret-Material behandeln | Unraid USB Flash Creator / neuer Boot-Stick | Unraid bootet, Array-Zuordnung und Shares sind sichtbar |
| Traefik | Share / Borg | `/mnt/user/appdata/traefik`, besonders `dynamic/`, `letsencrypt`, `secrets` | keine eigene DB | `cloudflare_dns_api_token` | `frontend_net`, `backend_net` | `https://traefik.kaleschke.info` erreichbar, Dashboard ueber Authelia | | Traefik | Share / Borg | `/mnt/user/appdata/traefik`, besonders `dynamic/`, `letsencrypt`, `secrets` | keine eigene DB | `cloudflare_dns_api_token` | `frontend_net`, `backend_net` | `https://traefik.kaleschke.info` erreichbar, Dashboard ueber Authelia |
| AdGuard Home | Share / Borg | `/mnt/user/appdata/adguard/conf` | keine | keine zusaetzlichen Repo-Secrets dokumentiert | `dns_net`, `frontend_net` | DNS-Aufloesung funktioniert; Restore-Smoke am 2026-06-06 erfolgreich | | AdGuard Home | Share / Borg | `/mnt/user/appdata/adguard/conf` | keine | keine zusaetzlichen Repo-Secrets dokumentiert | `dns_net`, `frontend_net` | DNS-Aufloesung funktioniert; Restore-Smoke am 2026-06-06 erfolgreich |
| Tailscale | Flash-Backup (funktional) / Share | **Funktional: `/boot/config/plugins/tailscale/state`** (native Unraid-Plugin-Instanz `kallilabcore`, Subnet-Router, im Flash-Backup gesichert). Der frueher hier genannte Pfad `/mnt/user/appdata/tailscale` gehoert zum **userspace-only Docker-Stack** `kallilab-core` (redundant, Abbau geplant — siehe `docs/NETWORK_INVENTORY.md`) | keine | Tailscale-State im jeweiligen State-Pfad | Host-Netz | Tailscale verbunden, Subnet-Route `192.168.178.0/24` aktiv | | Tailscale | Flash-Backup (funktional) | **Funktional: `/boot/config/plugins/tailscale/state`** (native Unraid-Plugin-Instanz `kallilabcore`, Subnet-Router, im Flash-Backup gesichert). Der frueher genannte Pfad `/mnt/user/appdata/tailscale` gehoerte zum entfernten userspace-only Docker-Stack `kallilab-core` und ist seit 2026-06-17 nach `/mnt/user/appdata/_archive/tailscale-removed-2026-06-06/` verschoben; nicht mehr als aktive Restore-Quelle behandeln | keine | Tailscale-State im Flash-Backup; Archivpfad nur fuer Altanalyse | Host-Netz | Tailscale verbunden, Subnet-Route `192.168.178.0/24` aktiv |
| PostgreSQL 18 | Share + Dumps | `/mnt/user/appdata/postgresql18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/postgresql17`) | `postgresql17-globals.sql`, `postgresql17-mailarchiver.dump`, `postgresql17-paperless.dump`, optional `postgresql17-authelia.dump` | `postgres_password.txt`, App-Rollen-Passwoerter aus den jeweiligen Stack-ENV/Secret-Dateien | `backend_net` | DB startet, Ziel-Datenbanken vorhanden; `SHOW data_checksums` ist `on` | | PostgreSQL 18 | Share + Dumps | `/mnt/user/appdata/postgresql18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/postgresql17`) | `postgresql17-globals.sql`, `postgresql17-mailarchiver.dump`, `postgresql17-paperless.dump`, optional `postgresql17-authelia.dump` | `postgres_password.txt`, App-Rollen-Passwoerter aus den jeweiligen Stack-ENV/Secret-Dateien | `backend_net` | DB startet, Ziel-Datenbanken vorhanden; `SHOW data_checksums` ist `on` |
| Redis 8 | Share / Host | `/mnt/user/appdata/redis`; Rollback-Backup unter `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-<ts>` | RDB/AOF-Dateien im Datenpfad | `redis_password.txt` | `backend_net` | Redis startet, `redis_version` ist 8.x, Apps verbinden sich; Restore-Smoke am 2026-06-06 erfolgreich | | Redis 8 | Share / Host | `/mnt/user/appdata/redis`; Rollback-Backup unter `/mnt/user/backups/borg/dumps/latest/shared-redis-pre-redis8-<ts>` | RDB/AOF-Dateien im Datenpfad | `redis_password.txt` | `backend_net` | Redis startet, `redis_version` ist 8.x, Apps verbinden sich; Restore-Smoke am 2026-06-06 erfolgreich |
| Authelia | Borg | `/mnt/user/appdata/authelia/config`, `/mnt/user/appdata/secrets/*authelia*` | Shared PostgreSQL 18, optional Dump `postgresql17-authelia.dump` | JWT/Session/Storage/Postgres-/SMTP-Secret-Dateien | PostgreSQL 18, Traefik, GMX SMTP | Login-Seite und ForwardAuth funktionieren; SMTP-Notifier startet; aktive Sessions werden nach Restart neu aufgebaut; Restore-Smoke am 2026-06-03 erfolgreich: Config aus Borg, minimale Test-Config, frisches Test-Postgres, HTTP `/api/health` 200, Report `/mnt/user/backups/restore-reports/authelia-2026-06-03.md` | | Authelia | Borg | `/mnt/user/appdata/authelia/config`, `/mnt/user/appdata/secrets/*authelia*` | Shared PostgreSQL 18, optional Dump `postgresql17-authelia.dump` | JWT/Session/Storage/Postgres-/SMTP-Secret-Dateien | PostgreSQL 18, Traefik, GMX SMTP | Login-Seite und ForwardAuth funktionieren; SMTP-Notifier startet; aktive Sessions werden nach Restart neu aufgebaut; Restore-Smoke am 2026-06-03 erfolgreich: Config aus Borg, minimale Test-Config, frisches Test-Postgres, HTTP `/api/health` 200, Report `/mnt/user/backups/restore-reports/authelia-2026-06-03.md` |
@@ -52,7 +52,7 @@ Sie ist die fachliche Ergaenzung zu `docs/DISASTER_RECOVERY.md`.
| Dienst | Fuehrende Quelle | Datei-Restore | Dump / DB | Secrets / ENV | Abhaengigkeiten | Smoke-Test | | Dienst | Fuehrende Quelle | Datei-Restore | Dump / DB | Secrets / ENV | Abhaengigkeiten | Smoke-Test |
|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|
| Paperless-ngx | Borg + Dumps | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/paperless/export`, `/mnt/user/documents/scans_inbox` | `postgresql17-paperless.dump` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS`, `borg_repo_passphrase.txt` fuer Restore-Tests | PostgreSQL 18, Redis, Traefik | Web-UI startet, Dokumente vorhanden; Restore-Test am 2026-05-31 erfolgreich: Borg-Archiv `Tägliche-Sicherung-2026-05-31T04:30:13.181`, isolierter PostgreSQL-18-/Redis-8-Testpfad, HTTP `200`, `32` Dokumente im Test-DB-Check, Report `/mnt/user/backups/restore-reports/paperless-2026-05-31.md` | | Paperless-ngx | Borg + Dumps | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/paperless/export`, `/mnt/user/documents/scans_inbox` | `postgresql17-paperless.dump` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS`, `PAPERLESS_OIDC_SECRET`, `borg_repo_passphrase.txt` fuer Restore-Tests | PostgreSQL 18, Redis, Traefik, Authelia OIDC | Web-UI startet, Dokumente vorhanden; Restore-Test am 2026-05-31 erfolgreich: Borg-Archiv `Tägliche-Sicherung-2026-05-31T04:30:13.181`, isolierter PostgreSQL-18-/Redis-8-Testpfad, HTTP `200`, `32` Dokumente im Test-DB-Check, Report `/mnt/user/backups/restore-reports/paperless-2026-05-31.md`; OIDC-Secret am 2026-06-17 verdrahtet, lokaler Login bleibt Fallback |
| Mealie | Borg + Dump | `/mnt/user/appdata/mealie/data`, `/mnt/user/appdata/mealie/postgres18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`) | `mealie.dump` | `mealie_postgres_password.txt` | `mealie-postgres`, Traefik | UI startet, Rezepte vorhanden | | Mealie | Borg + Dump | `/mnt/user/appdata/mealie/data`, `/mnt/user/appdata/mealie/postgres18` (archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/mealie-postgres17`) | `mealie.dump` | `mealie_postgres_password.txt` | `mealie-postgres`, Traefik | UI startet, Rezepte vorhanden |
| Immich | Borg + Dump | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`, `/mnt/user/appdata/immich_postgres_vectorchord`; archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs` | `immich.dump`; nach VectorChord braucht ein Restore ein Postgres-Image mit VectorChord | `IMMICH_DB_PASSWORD`, `immich_postgres_password.txt`, `borg_repo_passphrase.txt` fuer Restore-Tests | `immich_postgres`, `immich_redis`, Traefik | DB- und UI-Smoke gegen produktives Borg-Archiv am 2026-05-27 erfolgreich validiert; VectorChord-Migration am 2026-05-31: `11977` Assets, `11107` Smart-Search-Zeilen, `7092` Face-Search-Zeilen, `vchord 0.4.3`, `vector 0.8.1`, HTTP/API-Smoke 200. Voll-Restore der Foto-Dateien bleibt separater DR-Drill | | Immich | Borg + Dump | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive`, `/mnt/user/appdata/immich_postgres_vectorchord`; archivierter Rollback-Altstand: `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs` | `immich.dump`; nach VectorChord braucht ein Restore ein Postgres-Image mit VectorChord | `IMMICH_DB_PASSWORD`, `immich_postgres_password.txt`, `borg_repo_passphrase.txt` fuer Restore-Tests | `immich_postgres`, `immich_redis`, Traefik | DB- und UI-Smoke gegen produktives Borg-Archiv am 2026-05-27 erfolgreich validiert; VectorChord-Migration am 2026-05-31: `11977` Assets, `11107` Smart-Search-Zeilen, `7092` Face-Search-Zeilen, `vchord 0.4.3`, `vector 0.8.1`, HTTP/API-Smoke 200. Voll-Restore der Foto-Dateien bleibt separater DR-Drill |
| Mail-Archiver | Borg + Shared Dump | `/mnt/user/appdata/mailarchiver/data-protection-keys` | `postgresql17-mailarchiver.dump` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | PostgreSQL 18, Traefik, Authelia | Authelia-Weiterleitung greift; nach Login startet die Web-UI und das Archiv laesst sich oeffnen | | Mail-Archiver | Borg + Shared Dump | `/mnt/user/appdata/mailarchiver/data-protection-keys` | `postgresql17-mailarchiver.dump` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | PostgreSQL 18, Traefik, Authelia | Authelia-Weiterleitung greift; nach Login startet die Web-UI und das Archiv laesst sich oeffnen |
+3 -2
View File
@@ -25,6 +25,7 @@ Dieses Dokument listet sensible Daten, deren Ablageorte und die vorgesehene Einb
| mealie-postgres | DB Password | `/mnt/user/appdata/secrets/mealie_postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | aktiv | | mealie-postgres | DB Password | `/mnt/user/appdata/secrets/mealie_postgres_password.txt` -> `POSTGRES_PASSWORD_FILE` | aktiv |
| Paperless-ngx | DB Password | Stack ENV `${PAPERLESS_DBPASS}` | aktiv | | Paperless-ngx | DB Password | Stack ENV `${PAPERLESS_DBPASS}` | aktiv |
| Paperless-ngx | Redis URL | Stack ENV `${PAPERLESS_REDIS}` | aktiv | | Paperless-ngx | Redis URL | Stack ENV `${PAPERLESS_REDIS}` | aktiv |
| Paperless OIDC (Authelia) | Client Secret | Stack ENV `${PAPERLESS_OIDC_SECRET}` in `/mnt/user/services/stacks/paperless/apps/paperless/.env` (Komodo-Stack-ENV); pbkdf2-Hash im Authelia-Host-Config-Client `paperless` (kein Wert im Repo) | aktiv (2026-06-17) |
| Paperless-GPT | OpenAI API Key | Stack ENV `${OPENAI_API_KEY}`; nicht im Repo, nicht in Logs | aktiv | | Paperless-GPT | OpenAI API Key | Stack ENV `${OPENAI_API_KEY}`; nicht im Repo, nicht in Logs | aktiv |
| code-server | Passwort | `/mnt/user/appdata/code-server/secrets/password` -> `FILE__PASSWORD` | aktiv | | code-server | Passwort | `/mnt/user/appdata/code-server/secrets/password` -> `FILE__PASSWORD` | aktiv |
| Filebrowser | Admin Password | `/mnt/user/appdata/secrets/filebrowser_admin_password.txt` -> initialisierte SQLite-DB | aktiv | | Filebrowser | Admin Password | `/mnt/user/appdata/secrets/filebrowser_admin_password.txt` -> initialisierte SQLite-DB | aktiv |
@@ -116,7 +117,7 @@ Weitere dokumentierte Secret-Pfade:
- Borg UI verwaltet Session-Secret, Admin-Login, SSH-Keys und Repo-Credentials in seiner persistenten `/data`-Struktur. Diese Daten liegen nicht im Git, muessen aber gesichert werden. - Borg UI verwaltet Session-Secret, Admin-Login, SSH-Keys und Repo-Credentials in seiner persistenten `/data`-Struktur. Diese Daten liegen nicht im Git, muessen aber gesichert werden.
- Die Borg-Repo-Passphrase liegt zusaetzlich als Host-Secret-Datei fuer Restore-Tests und Notfallzugriff vor. Der Wert ist laut Operator-Bestaetigung vom 2026-05-26 offline gesichert; Ablageort und Wert werden nicht im Repo dokumentiert. - Die Borg-Repo-Passphrase liegt zusaetzlich als Host-Secret-Datei fuer Restore-Tests und Notfallzugriff vor. Der Wert ist laut Operator-Bestaetigung vom 2026-05-26 offline gesichert; Ablageort und Wert werden nicht im Repo dokumentiert.
- Gitea verwaltet den GitHub-Push-Mirror-PAT in den Repository-Mirror-Settings. Der Wert wird nicht dokumentiert und nicht in Dateien unter `docs/` oder `core/gitea/` geschrieben. - Gitea verwaltet den GitHub-Push-Mirror-PAT in den Repository-Mirror-Settings. Der Wert wird nicht dokumentiert und nicht in Dateien unter `docs/` oder `core/gitea/` geschrieben.
- `paperless-ngx` ist eine bewusste Ausnahme: DB-Passwort und Redis-URL bleiben aktuell als Komodo Stack Environment Variables hinterlegt, um den stabil laufenden Produktionsstand nicht fuer eine reine Secret-Mechanik-Migration zu riskieren. - `paperless-ngx` ist eine bewusste Ausnahme: DB-Passwort, Redis-URL und OIDC-Client-Secret bleiben aktuell als Komodo Stack Environment Variables hinterlegt, um den stabil laufenden Produktionsstand nicht fuer eine reine Secret-Mechanik-Migration zu riskieren.
- `baerchen` nutzt fuer das Veeam-Backup aktuell den bestehenden SMB-User - `baerchen` nutzt fuer das Veeam-Backup aktuell den bestehenden SMB-User
`micha`. Ein dedizierter SMB-User `veeam-baerchen` ist nur ein spaeteres `micha`. Ein dedizierter SMB-User `veeam-baerchen` ist nur ein spaeteres
Hardening-Ziel, solange keine Unraid-User-/Share-Aenderungen gewuenscht sind. Hardening-Ziel, solange keine Unraid-User-/Share-Aenderungen gewuenscht sind.
@@ -139,7 +140,7 @@ Einige Secrets liegen bewusst nur als Komodo Stack Environment Variables vor, we
| Stack | Stack-ENV-Variablen | Restore-Quelle (Reihenfolge) | Folgen bei Verlust aller Quellen | | Stack | Stack-ENV-Variablen | Restore-Quelle (Reihenfolge) | Folgen bei Verlust aller Quellen |
|---|---|---|---| |---|---|---|---|
| `paperless-ngx` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | App-DB ist im Postgres-Cluster, Passwort muss in Postgres und Stack-ENV synchron neu gesetzt werden; Redis-URL ist deterministisch rekonstruierbar (Host, Port, Passwort), wenn Redis-Passwort-Datei vorliegt | | `paperless-ngx` | `PAPERLESS_DBPASS`, `PAPERLESS_REDIS`, `PAPERLESS_OIDC_SECRET` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | App-DB ist im Postgres-Cluster, Passwort muss in Postgres und Stack-ENV synchron neu gesetzt werden; Redis-URL ist deterministisch rekonstruierbar (Host, Port, Passwort), wenn Redis-Passwort-Datei vorliegt; OIDC-Client-Secret kann mit passendem Authelia-Client neu rotiert werden |
| `paperless-gpt` | `PAPERLESS_API_TOKEN`, `OPENAI_API_KEY` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | Paperless-Token kann in Paperless neu erzeugt werden; OpenAI-Key muss im OpenAI-Projekt rotiert/neu erstellt werden | | `paperless-gpt` | `PAPERLESS_API_TOKEN`, `OPENAI_API_KEY` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | Paperless-Token kann in Paperless neu erzeugt werden; OpenAI-Key muss im OpenAI-Projekt rotiert/neu erstellt werden |
| `immich-server` | `IMMICH_DB_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | analog Paperless: Postgres-User-Passwort in `immich_postgres` und Stack-ENV gemeinsam zuruecksetzen | | `immich-server` | `IMMICH_DB_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | analog Paperless: Postgres-User-Passwort in `immich_postgres` und Stack-ENV gemeinsam zuruecksetzen |
| `mail-archiver` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | DB-Connection-String enthaelt Postgres-Pass; App-Auth-Password fuer Web-UI | | `mail-archiver` | `MAILARCHIVER_DB_CONNECTION`, `MAILARCHIVER_AUTH_PASSWORD` | Komodo-Mongo-Dump -> Vaultwarden -> externe Notiz | DB-Connection-String enthaelt Postgres-Pass; App-Auth-Password fuer Web-UI |
+1 -1
View File
@@ -35,7 +35,7 @@ Secret-Werte sind nicht enthalten. Es werden nur Secret-Namen, Env-Key-Namen und
| Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs | | Service | Zweck | Autoritativer Pfad | URL / Zugang | Abhaengigkeiten | Datenpfade | Backup / Restore | Traefik | Besonderheiten / TODOs |
|---|---|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|---|---|
| `paperless-ngx` | Dokumentenmanagement | `apps/paperless/docker-compose.yml` | `https://paperless.kaleschke.info` | PostgreSQL 18, Redis 8, Traefik | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/scans_inbox` | Tier 2, Borg + `postgresql17-paperless.dump` | ja | DB/Redis Secrets bleiben bewusst Stack ENV; Dump-Dateiname behaelt den historischen Cluster-Namen | | `paperless-ngx` | Dokumentenmanagement | `apps/paperless/docker-compose.yml` | `https://paperless.kaleschke.info` | PostgreSQL 18, Redis 8, Traefik, Authelia OIDC | `/mnt/user/appdata/paperless-ngx/data`, `/mnt/user/documents/paperless`, `/mnt/user/documents/scans_inbox` | Tier 2, Borg + `postgresql17-paperless.dump` | ja + Authelia | DB/Redis/OIDC Secrets bleiben bewusst Stack ENV; OIDC ist additiv via Authelia konfiguriert, lokaler Login bleibt Fallback; Dump-Dateiname behaelt den historischen Cluster-Namen |
| `paperless-gpt` | KI-Ergaenzung fuer Paperless | `apps/paperless-gpt/docker-compose.yml` | `https://paperless-gpt.kaleschke.info` | Paperless API, OpenAI API, Traefik | `/mnt/user/appdata/paperless-gpt/data`, `/mnt/user/appdata/paperless-gpt/prompts` | Tier 2 | ja + Authelia | `PAPERLESS_API_TOKEN` und `OPENAI_API_KEY` als Stack ENV; LLM und Vision-OCR laufen ueber `gpt-5.4-mini`, kein Zugriff mehr auf lokale Ollama-VM. **Behalten-Entscheidung 2026-05-28:** Container bleibt aktiv, auch wenn aktuell keine Traefik-Zugriffe in der Woche; Ablouseplanung erst mit Paperless-NGX 3.0 (eigene KI-Features erwartet) - dann neu bewerten. | | `paperless-gpt` | KI-Ergaenzung fuer Paperless | `apps/paperless-gpt/docker-compose.yml` | `https://paperless-gpt.kaleschke.info` | Paperless API, OpenAI API, Traefik | `/mnt/user/appdata/paperless-gpt/data`, `/mnt/user/appdata/paperless-gpt/prompts` | Tier 2 | ja + Authelia | `PAPERLESS_API_TOKEN` und `OPENAI_API_KEY` als Stack ENV; LLM und Vision-OCR laufen ueber `gpt-5.4-mini`, kein Zugriff mehr auf lokale Ollama-VM. **Behalten-Entscheidung 2026-05-28:** Container bleibt aktiv, auch wenn aktuell keine Traefik-Zugriffe in der Woche; Ablouseplanung erst mit Paperless-NGX 3.0 (eigene KI-Features erwartet) - dann neu bewerten. |
| `immich_server` | Foto-/Video-App | `apps/immich/docker-compose.yml` | `https://immich.kaleschke.info` | Immich Postgres, Immich Redis, ML, Traefik | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | Tier 2, Borg + `immich.dump` | ja | native App-Auth; externes Fotoarchiv gemountet | | `immich_server` | Foto-/Video-App | `apps/immich/docker-compose.yml` | `https://immich.kaleschke.info` | Immich Postgres, Immich Redis, ML, Traefik | `/mnt/user/photos/immich`, `/mnt/user/photos/family_archive` | Tier 2, Borg + `immich.dump` | ja | native App-Auth; externes Fotoarchiv gemountet |
| `immich_postgres` | Immich-Datenbank | `apps/immich/docker-compose.yml` | intern | `immich_default` | `/mnt/user/appdata/immich_postgres_vectorchord`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs`, `immich_postgres_password.txt` | Dump `immich.dump`; Restore braucht ein Image mit VectorChord/pgvector | nein | PG14 bleibt bewusst; Immich-DB-Image `ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0`; nie ins `frontend_net` | | `immich_postgres` | Immich-Datenbank | `apps/immich/docker-compose.yml` | intern | `immich_default` | `/mnt/user/appdata/immich_postgres_vectorchord`, archivierter Rollback-Altstand `/mnt/user/appdata/_archive/pg18-immich-rollback-volumes-20260602/immich-postgres-pgvecto-rs`, `immich_postgres_password.txt` | Dump `immich.dump`; Restore braucht ein Image mit VectorChord/pgvector | nein | PG14 bleibt bewusst; Immich-DB-Image `ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0`; nie ins `frontend_net` |
+9 -3
View File
@@ -124,14 +124,20 @@ Pflichtschritte beim Anlegen:
1. Stack in Komodo aus Gitea anlegen 1. Stack in Komodo aus Gitea anlegen
2. `webhook_enabled` in Komodo aktivieren 2. `webhook_enabled` in Komodo aktivieren
3. passenden Gitea-Webhook fuer die aktuelle Stack-ID anlegen 3. passenden Gitea-Webhook fuer die aktuelle Stack-ID anlegen
4. Gitea-Hook gegen `http://komodo-core:9120/listener/github/stack/<stack-id>/deploy` pruefen 4. Branch-Filter im Gitea-Hook auf den produktiven Branch setzen, aktuell `master`
5. einen Push oder Test-Delivery ausloesen und `last_status`/Komodo-Deploy pruefen 5. Gitea-Hook gegen `http://komodo-core:9120/listener/github/stack/<stack-id>/deploy` pruefen
6. Ausnahmen explizit dokumentieren 6. einen Push oder Test-Delivery ausloesen und `last_status`/Komodo-Deploy pruefen
7. Ausnahmen explizit dokumentieren
**Regel:** Kein neuer produktiver GitOps-Stack ohne funktionierenden Gitea->Komodo-Webhook. Bewusste Ausnahmen muessen im selben Aenderungsblock dokumentiert werden, inklusive Grund und Alternativ-Deploy-Weg. **Regel:** Kein neuer produktiver GitOps-Stack ohne funktionierenden Gitea->Komodo-Webhook. Bewusste Ausnahmen muessen im selben Aenderungsblock dokumentiert werden, inklusive Grund und Alternativ-Deploy-Weg.
Der Standardfall nutzt den globalen `KOMODO_WEBHOOK_SECRET` aus der Komodo-Host-`.env`, ausser Komodo zeigt fuer den Stack explizit ein eigenes per-Stack-Secret. Der Standardfall nutzt den globalen `KOMODO_WEBHOOK_SECRET` aus der Komodo-Host-`.env`, ausser Komodo zeigt fuer den Stack explizit ein eigenes per-Stack-Secret.
Der Gitea-Branch-Filter darf nicht leer oder `*` bleiben, solange der Komodo-Stack
einen konkreten Repo-Branch erwartet. Sonst triggern Feature-/Arbeitsbranches alle
Stack-Listener, Komodo verwirft sie mit `request branch does not match expected`
und der Operations-Report bekommt unnuetzes Komodo-/Traefik-Rauschen.
### Ausnahme: Komodo-Zugangsmodell ### Ausnahme: Komodo-Zugangsmodell
Komodo bleibt **bewusst** ohne zentrale Traefik-ForwardAuth-Middleware. Komodo bleibt **bewusst** ohne zentrale Traefik-ForwardAuth-Middleware.
+9 -3
View File
@@ -25,7 +25,7 @@ services:
- cadvisor - cadvisor
alertmanager: alertmanager:
image: prom/alertmanager:v0.32.2@sha256:b85533a2eb45865835315810315f6951331b2dbc8c93a6cf9a51e156a006a706 image: prom/alertmanager:v0.33.0@sha256:af26fbe4dd1886ac0efd7bd55cd9027da262e105b137a376522b7c14c3626e4a
container_name: monitoring-alertmanager container_name: monitoring-alertmanager
restart: unless-stopped restart: unless-stopped
command: command:
@@ -42,7 +42,7 @@ services:
- no-new-privileges:true - no-new-privileges:true
alertmanager-ntfy-bridge: alertmanager-ntfy-bridge:
image: python:3.14-alpine@sha256:5a824eb82cc75361f98611f3cfc5091ea33f10a6ccea4d4ebdabbc523b9a1614 image: python:3.14-alpine@sha256:26730869004e2b9c4b9ad09cab8625e81d256d1ce97e72df5520e806b1709f92
container_name: monitoring-alertmanager-ntfy-bridge container_name: monitoring-alertmanager-ntfy-bridge
restart: unless-stopped restart: unless-stopped
dns: dns:
@@ -337,7 +337,7 @@ services:
- no-new-privileges:true - no-new-privileges:true
influxdb3-core: influxdb3-core:
image: influxdb:3.9.3-core@sha256:c27c9b2ca2625b5b6966f0b09baa448102310e63a471fd60dff22646a2522e29 image: influxdb:3.10.0-core@sha256:b3e577f38c19963597170d8850a3a7f77af8f0cfa866c64cd13e5de0f238e114
container_name: monitoring-influxdb3-core container_name: monitoring-influxdb3-core
user: "0" user: "0"
restart: unless-stopped restart: unless-stopped
@@ -351,6 +351,12 @@ services:
- --data-dir=/var/lib/influxdb3/data - --data-dir=/var/lib/influxdb3/data
- --plugin-dir=/var/lib/influxdb3/plugins - --plugin-dir=/var/lib/influxdb3/plugins
- --admin-token-file=/run/secrets/influxdb3_admin_token - --admin-token-file=/run/secrets/influxdb3_admin_token
# InfluxDB 3 Core kompaktiert Parquet-Dateien nicht (nur Enterprise).
# HA schreibt viele Sensoren haeufig -> Tabellen wie "°C"/"%"/"hPa" liefen
# ins Default-Limit von 432 Dateien/Query ("No data" in Grafana).
# Stopgap: Limit anheben. Langfristig: Enterprise (Auto-Compaction, frei
# fuer Home) oder weniger/seltener nach InfluxDB schreiben.
- --query-file-limit=20000
volumes: volumes:
- /mnt/user/appdata/influxdb3/data:/var/lib/influxdb3/data - /mnt/user/appdata/influxdb3/data:/var/lib/influxdb3/data
- /mnt/user/appdata/influxdb3/plugins:/var/lib/influxdb3/plugins - /mnt/user/appdata/influxdb3/plugins:/var/lib/influxdb3/plugins
+2 -2
View File
@@ -1,6 +1,6 @@
# Borg Backup Scope for KalliLabcore # Borg Backup Scope for KalliLabcore
Stand: 2026-05-31 Stand: 2026-06-17
This file defines the target state for replacing Backrest with Borg in this homelab. This file defines the target state for replacing Backrest with Borg in this homelab.
@@ -38,7 +38,7 @@ The Unraid flash configuration archive is intentional as well and must be treate
| Traefik | file data | `/local/appdata/traefik` | | Traefik | file data | `/local/appdata/traefik` |
| ntfy | file data | `/local/appdata/ntfy` | | ntfy | file data | `/local/appdata/ntfy` |
| Paperless-GPT | file data | `/local/appdata/paperless-gpt` | | Paperless-GPT | file data | `/local/appdata/paperless-gpt` |
| Tailscale | file data | `/local/appdata/tailscale` | | Tailscale | Flash config artifact | covered by `/local/borg-dumps/unraid-flash-config.tar.gz`; no active `/local/appdata/tailscale` path |
| AdGuard | config only | `/local/appdata/adguard/conf` | | AdGuard | config only | `/local/appdata/adguard/conf` |
| Borg UI | SQLite dump + self-backup | `/local/borg-dumps`, `/local/appdata/borg-ui/data` | | Borg UI | SQLite dump + self-backup | `/local/borg-dumps`, `/local/appdata/borg-ui/data` |
| Komodo | config + Mongo dump | `/local/borg-dumps`, `/local/appdata/komodo/periphery`, `/local/appdata/komodo/core` | | Komodo | config + Mongo dump | `/local/borg-dumps`, `/local/appdata/komodo/periphery`, `/local/appdata/komodo/core` |
-1
View File
@@ -14,7 +14,6 @@
/local/appdata/traefik /local/appdata/traefik
/local/appdata/ntfy /local/appdata/ntfy
/local/appdata/paperless-gpt /local/appdata/paperless-gpt
/local/appdata/tailscale
/local/appdata/adguard/conf /local/appdata/adguard/conf
/local/appdata/borg-ui/data /local/appdata/borg-ui/data
/local/appdata/komodo/periphery /local/appdata/komodo/periphery
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
borg-ui: borg-ui:
image: ainullcode/borg-ui@sha256:0922157e8f77a1b2bd23cd09366a458ea6de07fd9306aa1485f9cfe623eca17f image: ainullcode/borg-ui@sha256:e51b3d2e6cb38d1ba127ef60ba442c1e157965327196e6f7afb69f30c0ba99d1
container_name: borg-ui container_name: borg-ui
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
code-server: code-server:
image: lscr.io/linuxserver/code-server:4.123.0@sha256:cb261a7f87674b445e0fd66d87d55900c1b823d276c727ab0d168a75e69e9992 image: lscr.io/linuxserver/code-server:4.125.0@sha256:7e9523734c003b6336781942df7b48aa6936a9df6931c12a19a1f7ad7858eeba
container_name: code-server container_name: code-server
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
filebrowser: filebrowser:
image: filebrowser/filebrowser:v2.63.14@sha256:1ec9b0c68297550c92f4a93feed432850c2993b261706cc3cc2e808f94a95e76 image: filebrowser/filebrowser:v2.63.15@sha256:9805b21cf910f3ef6f4a1c8f441f1dd6cc4197136f9541fe2a1ab6d050706e4b
container_name: filebrowser container_name: filebrowser
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
glances: glances:
image: nicolargo/glances:latest-full@sha256:60872a1af0e40a3150975617c7e811ad7ad48f95bc45d033fb0c1737a037e4d2 image: nicolargo/glances:latest-full@sha256:58651aabedf62db8bfc1d252f8d3889675dfcdb5d0ad1c177ae5879c21626f3a
container_name: glances container_name: glances
restart: unless-stopped restart: unless-stopped
pid: host pid: host
+4 -4
View File
@@ -45,13 +45,13 @@
"description": "VPN / Remote-Zugang", "description": "VPN / Remote-Zugang",
"tier": 1, "tier": 1,
"category": "core", "category": "core",
"container_name": "tailscale", "container_name": null,
"dependencies": [], "dependencies": [],
"url": null, "url": null,
"dump_file": null, "dump_file": null,
"data_paths": ["/mnt/user/appdata/tailscale"], "data_paths": ["/boot/config/plugins/tailscale/state"],
"first_check": "Tailscale Status auf Host pruefen; State-Datei fuer Key-Renewal vorhanden?", "first_check": "Tailscale Status auf Host pruefen; native Unraid-Plugin-Instanz und Subnet-Route aktiv?",
"notes": "network_mode: host; NET_ADMIN, NET_RAW, /dev/net/tun — dokumentierte VPN-Ausnahmen" "notes": "Natives Unraid-Plugin, nicht Docker/Komodo-verwaltet; State liegt im Flash-Backup. Alter Docker-State ist archiviert unter /mnt/user/appdata/_archive/tailscale-removed-2026-06-06/"
}, },
"gitea": { "gitea": {
"description": "Git-Server — operative Quelle der Wahrheit fuer GitOps", "description": "Git-Server — operative Quelle der Wahrheit fuer GitOps",
+4 -4
View File
@@ -75,14 +75,14 @@ services:
description: VPN / Remote-Zugang description: VPN / Remote-Zugang
tier: 1 tier: 1
category: core category: core
container_name: tailscale container_name: null
dependencies: [] dependencies: []
url: null url: null
dump_file: null dump_file: null
data_paths: data_paths:
- /mnt/user/appdata/tailscale - /boot/config/plugins/tailscale/state
first_check: "Tailscale Status auf Host pruefen; State-Datei fuer Key-Renewal vorhanden?" first_check: "Tailscale Status auf Host pruefen; native Unraid-Plugin-Instanz und Subnet-Route aktiv?"
notes: "network_mode: host; NET_ADMIN, NET_RAW, /dev/net/tun — dokumentierte VPN-Ausnahmen" notes: "Natives Unraid-Plugin, nicht Docker/Komodo-verwaltet; State liegt im Flash-Backup. Alter Docker-State ist archiviert unter /mnt/user/appdata/_archive/tailscale-removed-2026-06-06/"
gitea: gitea:
description: Git-Server — operative Quelle der Wahrheit fuer GitOps description: Git-Server — operative Quelle der Wahrheit fuer GitOps
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
restoretest-adguard: restoretest-adguard:
image: adguard/adguardhome:v0.107.76@sha256:7157eb1dc3b26c7af1d6898759a7b3f7d0fa09891fbd2d3caa6abc1057a9179b image: adguard/adguardhome:v0.107.77@sha256:e6f2b8bcda06064ab055b44933a4f0e983c35558b9cdb8d2e7ab1efcee36d890
container_name: restoretest-adguard container_name: restoretest-adguard
restart: "no" restart: "no"
ports: ports:
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
scrutiny: scrutiny:
image: ghcr.io/starosdev/scrutiny:latest-omnibus@sha256:228483f16a6236d2fa9b2fbfca2e76dc861e648fbc6ae6e680d23e5d00211a5d image: ghcr.io/starosdev/scrutiny:latest-omnibus@sha256:d79e6f1bc299ab28fbd95c9e05fa5a8c565332d2cb9091a91e42d84d4d939989
container_name: scrutiny container_name: scrutiny
restart: unless-stopped restart: unless-stopped
privileged: true privileged: true
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
speedtest-tracker: speedtest-tracker:
image: lscr.io/linuxserver/speedtest-tracker:1.14.3@sha256:c3750c40948a9360000ce62d694da92e85584b4ab6d3d9a9d1432d76fa5e0726 image: lscr.io/linuxserver/speedtest-tracker:1.14.4@sha256:f99dfd097709016dfb4387d65bfdc0419bde99cf1dce7e26e70ca616c86f1281
container_name: speedtest-tracker container_name: speedtest-tracker
restart: unless-stopped restart: unless-stopped
security_opt: security_opt:
+2 -1
View File
@@ -39,10 +39,11 @@
"labels": ["dependencies", "minor-patch"] "labels": ["dependencies", "minor-patch"]
}, },
{ {
"description": "Kritische Kerninfra (Traefik=Public-Entrypoint, Unbound=DNS, n8n, Nextcloud): nicht im Sammel-PR, eigene einzeln reviewbare PRs, kein Auto-Merge", "description": "Kritische Kerninfra (Traefik=Public-Entrypoint, AdGuard/Unbound=DNS, n8n, Nextcloud): nicht im Sammel-PR, eigene einzeln reviewbare PRs, kein Auto-Merge",
"matchManagers": ["docker-compose", "dockerfile"], "matchManagers": ["docker-compose", "dockerfile"],
"matchPackageNames": [ "matchPackageNames": [
"traefik", "traefik",
"adguard/adguardhome",
"shaanmajid/unbound", "shaanmajid/unbound",
"docker.n8n.io/n8nio/n8n", "docker.n8n.io/n8nio/n8n",
"nextcloud" "nextcloud"
@@ -30,7 +30,7 @@ parse_compose() {
return value return value
} }
function emit() { function emit() {
if (service && image) { if (service && image && !has_profile) {
print clean(container) "\t" clean(image) print clean(container) "\t" clean(image)
} }
} }
@@ -40,6 +40,7 @@ parse_compose() {
sub(/:$/, "", service) sub(/:$/, "", service)
image="" image=""
container=service container=service
has_profile=0
next next
} }
service && /^ image:/ { service && /^ image:/ {
@@ -52,6 +53,10 @@ parse_compose() {
sub(/^[[:space:]]*container_name:[[:space:]]*/, "", container) sub(/^[[:space:]]*container_name:[[:space:]]*/, "", container)
next next
} }
service && /^ profiles:/ {
has_profile=1
next
}
END { emit() } END { emit() }
' "$compose" ' "$compose"
} }
+90 -1
View File
@@ -13,6 +13,7 @@ CERT_MAX_ROWS="${CERT_MAX_ROWS:-12}"
IMAGE_AGE_WARN_DAYS="${IMAGE_AGE_WARN_DAYS:-180}" IMAGE_AGE_WARN_DAYS="${IMAGE_AGE_WARN_DAYS:-180}"
IMAGE_AGE_ALLOW_FILE="${IMAGE_AGE_ALLOW_FILE:-/mnt/user/services/homelab-infra/services/posture-check/image-age-allow.patterns}" IMAGE_AGE_ALLOW_FILE="${IMAGE_AGE_ALLOW_FILE:-/mnt/user/services/homelab-infra/services/posture-check/image-age-allow.patterns}"
LOG_VOLUME_TOP_N="${LOG_VOLUME_TOP_N:-10}" LOG_VOLUME_TOP_N="${LOG_VOLUME_TOP_N:-10}"
LOG_VOLUME_OBSERVE_THRESHOLD="${LOG_VOLUME_OBSERVE_THRESHOLD:-100000}"
DISK_USAGE_WARN_PCT="${DISK_USAGE_WARN_PCT:-85}" DISK_USAGE_WARN_PCT="${DISK_USAGE_WARN_PCT:-85}"
CERT_WARN_DAYS="${CERT_WARN_DAYS:-21}" CERT_WARN_DAYS="${CERT_WARN_DAYS:-21}"
BACKUP_DRIFT_FACTOR="${BACKUP_DRIFT_FACTOR:-2.0}" BACKUP_DRIFT_FACTOR="${BACKUP_DRIFT_FACTOR:-2.0}"
@@ -217,6 +218,73 @@ derive_report_status() {
set_summary "report_status" "$REPORT_STATUS" set_summary "report_status" "$REPORT_STATUS"
} }
print_status_reasons() {
local count=0
add_reason() {
printf '%s\n' "- $1"
count=$((count + 1))
}
[ "${borg_status:-unknown}" != "completed" ] && add_reason "Borg Backup ist \`${borg_status:-unknown}\` statt \`completed\`."
[ "${prometheus_alerts:-0}" = "unknown" ] && add_reason "Prometheus Alerts konnten nicht sicher gelesen werden."
[ "${cert_warnings:-0}" != "0" ] && add_reason "Zertifikatswarnungen: \`${cert_warnings:-0}\`."
[ "${disk_warnings:-0}" != "0" ] && add_reason "Storage-Warnungen: \`${disk_warnings:-0}\`."
if [ "${image_warnings:-0}" != "0" ]; then
if [ -n "${image_warning_names:-}" ]; then
add_reason "Image-Warnungen: \`${image_warnings:-0}\` (${image_warning_names})."
else
add_reason "Image-Warnungen: \`${image_warnings:-0}\`."
fi
fi
[ "${containers_exited_nonzero:-0}" != "0" ] && add_reason "Container exited non-zero: \`${containers_exited_nonzero:-0}\`."
[ "${host_recent_boot:-0}" = "1" ] && add_reason "Host-Reboot innerhalb der letzten 24 Stunden."
[ "${backup_duration_drift:-0}" = "1" ] && add_reason "Backup-Dauer-Drift erkannt."
[ "${noise_threshold_exceeded:-0}" != "0" ] && add_reason "Noise-Pattern ueber Eskalations-Schwelle: \`${noise_threshold_exceeded:-0}\`."
if [ "${prometheus_alerts_pending:-0}" != "0" ] && [ "${prometheus_alerts_pending:-0}" != "unknown" ]; then
add_reason "Prometheus pending Alerts: \`${prometheus_alerts_pending:-0}\`."
fi
if [ "${prometheus_alerts_firing:-0}" != "0" ] && [ "${prometheus_alerts_firing:-0}" != "unknown" ]; then
add_reason "Prometheus firing Alerts: \`${prometheus_alerts_firing:-0}\`."
fi
[ "${containers_unhealthy:-0}" != "0" ] && add_reason "Unhealthy Container: \`${containers_unhealthy:-0}\`."
if [ "$count" -eq 0 ]; then
printf '%s\n' "- Keine direkten Ampel-Ausloeser im Summary-Set gefunden."
fi
}
print_notable_observations() {
local count=0
add_observation() {
printf '%s\n' "- $1"
count=$((count + 1))
}
if [ "${traefik_5xx:-0}" != "0" ] && [ "${traefik_5xx:-0}" != "unknown" ]; then
if [ -n "${traefik_5xx_top:-}" ] && [ "${traefik_5xx_top:-none}" != "none" ]; then
add_observation "Traefik 5xx: \`${traefik_5xx:-0}\` (Top-Gruppe: \`${traefik_5xx_top}\`)."
else
add_observation "Traefik 5xx: \`${traefik_5xx:-0}\`."
fi
fi
if [ "${log_highlights:-0}" != "0" ] && [ "${log_highlights:-0}" != "unknown" ]; then
add_observation "Log-Highlights: \`${log_highlights:-0}\` handlungsrelevante Treffer; Beispiele stehen in der Log-Auswertung."
fi
if printf '%s' "${log_volume_total:-0}" | grep -Eq '^[0-9]+$' && [ "${log_volume_total:-0}" -ge "$LOG_VOLUME_OBSERVE_THRESHOLD" ]; then
add_observation "Log-Volumen: \`${log_volume_total:-0}\` Zeilen im Zeitraum; Top-Verursacher stehen im Log-Volumen-Abschnitt."
fi
if [ "${docker_events:-0}" != "0" ] && [ "${docker_events:-0}" != "unknown" ]; then
add_observation "Docker Critical Events: \`${docker_events:-0}\`."
fi
if [ "$count" -eq 0 ]; then
printf '%s\n' "- Keine zusaetzlichen auffaelligen Beobachtungen im Management-Summary."
fi
}
collect_borg() { collect_borg() {
append "## Borg Backup" append "## Borg Backup"
append "" append ""
@@ -584,6 +652,7 @@ collect_image_freshness() {
local image_file="$TMP_DIR/images.tsv" local image_file="$TMP_DIR/images.tsv"
local image_warnings=0 local image_warnings=0
local image_allowed=0 local image_allowed=0
local image_warning_names=""
local now_epoch local now_epoch
: > "$image_file" : > "$image_file"
now_epoch="$(date +%s)" now_epoch="$(date +%s)"
@@ -630,6 +699,7 @@ collect_image_freshness() {
else else
note="ueberaltert" note="ueberaltert"
image_warnings=$((image_warnings + 1)) image_warnings=$((image_warnings + 1))
image_warning_names="${image_warning_names:+$image_warning_names,}$name:${age_days}d"
fi fi
fi fi
printf '%d\t%s\t%s\t%s\n' "$age_days" "$name" "$image_tag" "$note" >> "$image_file" printf '%d\t%s\t%s\t%s\n' "$age_days" "$name" "$image_tag" "$note" >> "$image_file"
@@ -637,6 +707,7 @@ collect_image_freshness() {
set_summary "image_warnings" "$image_warnings" set_summary "image_warnings" "$image_warnings"
set_summary "image_allowed" "$image_allowed" set_summary "image_allowed" "$image_allowed"
set_summary "image_warning_names" "$image_warning_names"
if [ ! -s "$image_file" ]; then if [ ! -s "$image_file" ]; then
append "- Keine Image-Daten verfuegbar." append "- Keine Image-Daten verfuegbar."
@@ -781,8 +852,16 @@ collect_traefik_5xx() {
set_summary "traefik_5xx" "$count" set_summary "traefik_5xx" "$count"
if [ "$count" -eq 0 ]; then if [ "$count" -eq 0 ]; then
set_summary "traefik_5xx_top" "none"
append "- Keine 5xx-Antworten." append "- Keine 5xx-Antworten."
else else
local top_group
top_group="$(awk '{ code=$9; service=$12; gsub(/"/, "", service); counts[service " " code]++ } END { for (k in counts) print counts[k], k }' "$file" \
| sort -nr \
| head -n 1 \
| awk '{ print $2 ":" $3 ":" $1 }' \
| sed -E 's#[^A-Za-z0-9_.:@/-]+#_#g')"
set_summary "traefik_5xx_top" "${top_group:-none}"
append "- 5xx-Antworten: $count" append "- 5xx-Antworten: $count"
append "" append ""
append "### Gruppiert nach Service/Code" append "### Gruppiert nach Service/Code"
@@ -1181,10 +1260,20 @@ write_report() {
if [ "$REPORT_STATUS" = "OK" ]; then if [ "$REPORT_STATUS" = "OK" ]; then
printf 'Im betrachteten Zeitraum zeigt das Homelab eine stabile Betriebslage. Das letzte Borg-Backup ist erfolgreich abgeschlossen, Prometheus meldet keine firing Alerts, keine unhealthy Container, Zertifikate und Storage im erwarteten Bereich.\n\n' printf 'Im betrachteten Zeitraum zeigt das Homelab eine stabile Betriebslage. Das letzte Borg-Backup ist erfolgreich abgeschlossen, Prometheus meldet keine firing Alerts, keine unhealthy Container, Zertifikate und Storage im erwarteten Bereich.\n\n'
elif [ "$REPORT_STATUS" = "WARNUNG" ]; then elif [ "$REPORT_STATUS" = "WARNUNG" ]; then
printf 'Im betrachteten Zeitraum gibt es Punkte, die Aufmerksamkeit verdienen. Der Betrieb ist nicht automatisch als kompromittiert zu bewerten, aber mindestens ein Signal (Backup, Pending Alert, Zertifikat, Storage, Image-Alter, Drift oder Reboot) weicht vom Normalzustand ab.\n\n' printf 'Im betrachteten Zeitraum gibt es Punkte, die Aufmerksamkeit verdienen. Der Betrieb ist nicht automatisch als kompromittiert zu bewerten; die konkreten Ampel-Ausloeser stehen direkt darunter.\n\n'
else else
printf 'Im betrachteten Zeitraum liegt ein kritisches Betriebssignal vor. Der Bericht sollte zeitnah gelesen und die betroffenen Komponenten priorisiert geprueft werden.\n\n' printf 'Im betrachteten Zeitraum liegt ein kritisches Betriebssignal vor. Der Bericht sollte zeitnah gelesen und die betroffenen Komponenten priorisiert geprueft werden.\n\n'
fi fi
printf '### Warum dieser Status?\n\n'
if [ "$REPORT_STATUS" = "OK" ]; then
printf '%s\n\n' "- Keine Ampel-Ausloeser im Summary-Set."
else
print_status_reasons
printf '\n'
fi
printf '### Weitere auffaellige Beobachtungen\n\n'
print_notable_observations
printf '\n'
printf '### Management-Bewertung\n\n' printf '### Management-Bewertung\n\n'
printf '%s\n' "- Status: \`$REPORT_STATUS\`" printf '%s\n' "- Status: \`$REPORT_STATUS\`"
printf '%s\n' "- Borg Backup: \`${borg_status:-unknown}\`" printf '%s\n' "- Borg Backup: \`${borg_status:-unknown}\`"
@@ -28,3 +28,9 @@ immich_postgres 2026-09-10
# (Dez 2025). Das Image-Alter ist nur Build-Alter, keine veraltete Version. # (Dez 2025). Das Image-Alter ist nur Build-Alter, keine veraltete Version.
# Re-check: ob eine blackbox_exporter-Version > v0.28.0 erschienen ist. # Re-check: ob eine blackbox_exporter-Version > v0.28.0 erschienen ist.
monitoring-blackbox-exporter 2026-09-10 monitoring-blackbox-exporter 2026-09-10
# glance-docker-socket-proxy: v0.4.2 ist am 2026-06-17 weiterhin der neueste
# stabile Tag / latest. Neuere Tags sind nur master/nightly und werden fuer den
# lesenden Glance-Socket-Proxy bewusst nicht produktiv eingesetzt.
# Re-check: ob ein stabiler Tag > v0.4.2 erschienen ist.
glance-docker-socket-proxy 2026-09-17
+16
View File
@@ -87,3 +87,19 @@ adguard.*bad question section.*only 1 question allowed
# this lookup is harmless and does not affect any dashboard. # this lookup is harmless and does not affect any dashboard.
# Re-check: only if Amazon Prometheus is added as a datasource. # Re-check: only if Amazon Prometheus is added as a datasource.
monitoring-grafana.*grafana-amazonprometheus-datasource not found monitoring-grafana.*grafana-amazonprometheus-datasource not found
# cAdvisor stale container filesystem stats on Unraid.
# Why: cAdvisor can keep reporting an already removed Docker container path in
# fsHandler even though the container and path no longer exist. This is a
# collector bookkeeping issue, not a failed workload or missing data path.
# Re-check: if the message references an existing/running container, if
# Prometheus target health fails, or if broader cAdvisor errors appear.
monitoring-cadvisor.*failed to collect filesystem stats.*var/lib/docker/containers/[0-9a-f]{64}
# cAdvisor startup lines that match the generic "oom" / "failed" grep.
# Why: "oom_event" is a metric name printed during startup, and Unraid loop
# devices can disappear while cAdvisor enumerates block devices.
# Re-check: if cAdvisor target health fails or these messages appear outside
# container startup together with missing container metrics.
monitoring-cadvisor.*enabled metrics:.*oom_event
monitoring-cadvisor.*stat failed on /dev/loop[0-9]+ with error: no such file or directory
@@ -431,24 +431,24 @@ def render_summary_grid(entries):
status = classify(label, value) status = classify(label, value)
theme = STATUS_THEMES.get(status, STATUS_THEMES["UNKNOWN"]) theme = STATUS_THEMES.get(status, STATUS_THEMES["UNKNOWN"])
cards.append( cards.append(
'<td style="padding:6px;width:33.33%;vertical-align:top">' '<td style="padding:6px;width:50%;vertical-align:top">'
f'<div style="background:{theme["card_bg"]};' f'<div style="background:{theme["card_bg"]};'
f'border:1px solid {theme["card_border"]};' f'border:1px solid {theme["card_border"]};'
'border-radius:8px;padding:12px 14px">' 'border-radius:8px;padding:11px 12px;min-height:74px">'
f'<div style="font-size:11px;color:#1e293b;' f'<div style="font-size:11px;color:#1e293b;'
'text-transform:uppercase;letter-spacing:0.08em;font-weight:700;' 'text-transform:uppercase;letter-spacing:0.04em;font-weight:700;'
f'line-height:1.3;opacity:0.78">{html.escape(label)}</div>' f'line-height:1.35;opacity:0.78;overflow-wrap:anywhere">{html.escape(label)}</div>'
f'<div style="font-size:17px;font-weight:700;' f'<div style="font-size:16px;font-weight:700;'
f'color:{theme["card_text"]};margin-top:5px;line-height:1.25;' f'color:{theme["card_text"]};margin-top:5px;line-height:1.25;'
f'word-break:break-word;font-variant-numeric:tabular-nums">' f'word-break:normal;overflow-wrap:anywhere;font-variant-numeric:tabular-nums">'
f'{html.escape(value)}</div>' f'{html.escape(value)}</div>'
'</div></td>' '</div></td>'
) )
rows_html = [] rows_html = []
for chunk_start in range(0, len(cards), 3): for chunk_start in range(0, len(cards), 2):
chunk = cards[chunk_start:chunk_start + 3] chunk = cards[chunk_start:chunk_start + 2]
while len(chunk) < 3: while len(chunk) < 2:
chunk.append('<td style="padding:6px;width:33.33%"></td>') chunk.append('<td style="padding:6px;width:50%"></td>')
rows_html.append("<tr>" + "".join(chunk) + "</tr>") rows_html.append("<tr>" + "".join(chunk) + "</tr>")
return ( return (
'<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" ' '<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" '
+1 -1
View File
@@ -1,6 +1,6 @@
services: services:
homeassistant: homeassistant:
image: ghcr.io/home-assistant/home-assistant:2026.6.1@sha256:59aa8824955c9db491b75d2eebe42bd68494f80c2ec69ec0d66d9dae37d37514 image: ghcr.io/home-assistant/home-assistant:2026.6.3@sha256:aed891b8f801072302815b4b0fab5adb714182967e9d2e2d4a2be558241c73ad
container_name: homeassistant container_name: homeassistant
restart: unless-stopped restart: unless-stopped
environment: environment: