35 KiB
HOMELAB_ARCHITECTURE — MASTER v2
Single Source of Truth für Docker-Netzwerkarchitektur, Sicherheitsregeln, Zielbild und Migration des Kallilabcore-Homelabs. Arbeitsregel für KI-Assistenten: Dieses Dokument immer zuerst lesen, bevor Fragen zu Containern, Netzwerken, Traefik, Tailscale, Migration oder Security beantwortet werden.
Stand: 2026-05-16 | Aktueller Schwerpunkt: GitOps / Doku-Synchronisierung / Reproduzierbare Deployments
Inhaltsverzeichnis
- Systemüberblick
- Architektur-Prinzipien
- Finales Netzwerk-Zielbild
- Zugangsmodell: Traefik vs. Tailscale
- Globale Sicherheitsregeln
- Einordnungsschema für neue Container
- Container-Zielbild (vollständig)
- Traefik-Label-Standard
- Historische Migration (abgeschlossen)
- Bekannte Ausnahmen und Begründungen
- Projektorganisation und Arbeitsmodus
- Nutzung mit KI / Kontext-Regel
- Betriebserfahrungen und Entscheidungs-Log
1. Systemüberblick
| Eigenschaft | Wert |
|---|---|
| Host-OS | Unraid |
| Hostname | Kallilabcore |
| Reverse Proxy | Traefik v3 (Service-Routing via Docker-Labels, File-Provider fuer Middlewares, TLS und Dashboards) |
| VPN / Remote-Zugang | Tailscale (tailscale, host-Netz, Git-Stack) |
| DNS-Stack | AdGuard Home (dns_net + frontend_net) → Unbound (dns_net) |
| Basis-Domain | kaleschke.info |
| TLS | Let's Encrypt via Cloudflare DNS Challenge |
| Certresolver | le |
| Compose-Standard | Komodo (GitOps, Stack aus Gitea) |
| Legacy | Portainer CE entfernt; Komodo ist alleiniger Stack-Manager |
| Homelab-Compose-Pfad | /mnt/user/services/homelab/ |
| Secrets-Pfad | /mnt/user/appdata/secrets/ |
| Grundsatz | Keine neuen Dockerman-Einzelcontainer |
2. Architektur-Prinzipien
P1 — Traefik ist der einzige öffentliche HTTP(S)-Einstiegspunkt
Kein Webdienst veröffentlicht finale direkte Host-Ports außer traefik selbst. Begründete Ausnahmen: gitea-SSH (Port 222), AdGuard Home (Port 53/DNS + 8082/Admin), Tailscale, Plex-Media-Server und monitoring-influxdb3-core Port 8181 als LAN-only Writer-Endpunkt fuer Home Assistant.
P2 — Das Setup bleibt bewusst einfach: frontend_net + backend_net + app-interne Netze
frontend_net= Proxy-/Web-Netzbackend_net= intern für DB/Cache/App-Kommunikation- zusätzliche Netze nur app-intern, wenn technisch nötig (
mealie_internal,immich_default,dns_net)
Es gibt keine künstlichen globalen Zusatznetze wie admin_net oder media_net. monitoring_net ist die dokumentierte Ausnahme fuer den zentralen Observability-Stack.
P3 — Datenbanken gehören nie ins frontend_net
Postgres, Redis und ähnliche Dienste laufen ausschließlich in backend_net oder einem eigenen internen Compose-Netz.
P4 — Admin-UIs sind nicht öffentlich
filebrowser, scrutiny, UptimeKuma, code-server, Traefik-Dashboard und borg-ui sind standardmaessig Tailscale-only oder hinter Traefik mit zentraler Middleware abgesichert. Komodo ist die dokumentierte Ausnahme und bleibt bewusst bei nativer Authentifizierung ohne pauschal vorgeschaltete ForwardAuth-Middleware.
P5 — Compose-first
Alle produktiven Container werden als Compose verwaltet. Bestehende Dockerman-/Ad-hoc-Container werden schrittweise migriert.
P6 — Secrets nie im Klartext
Passwörter, Tokens und API-Keys gehören in Secret-Dateien unter /mnt/user/appdata/secrets/ oder als Komodo Stack Environment Variables mit ${VARIABLE} in der Compose.
P7 — restart: unless-stopped ist Pflichtstandard
Jeder produktive Container nutzt restart: unless-stopped, außer eine Ausnahme ist dokumentiert.
P8 — Least Privilege
security_opt: ["no-new-privileges:true"]standardmäßig ergänzenprivileged: truenur mit dokumentierter Begründung- Docker-Socket standardmäßig vorsichtig behandeln; Komodo ist dokumentierte Ausnahme
3. Finales Netzwerk-Zielbild
3.1 Netz-Logik
| Netzwerk | Typ | Zweck | Status |
|---|---|---|---|
frontend_net |
bridge, external | einziges Traefik-/Web-Netz | Standard |
backend_net |
bridge, internal: true |
interne App-/DB-/Cache-Kommunikation | Standard |
dns_net |
bridge | Resolver-Schicht: AdGuard Home + Unbound | bleibt |
mealie_internal |
bridge, internal: true |
internes Netz nur für mealie + mealie-postgres |
✅ umgesetzt |
immich_default |
Compose-intern, internal: true |
internes Immich-Netz | ✅ umgesetzt |
nextcloud_internal |
bridge, internal: true |
internes Netz nur fuer nextcloud + nextcloud-postgres + nextcloud-redis |
✅ vorbereitet |
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 |
grafana_influx_internal |
Compose-intern, internal: true |
alte Grafana-zu-InfluxDB-Kommunikation | abgeloester Altstand |
grafana_influx_lan |
Compose-intern, bridge | altes Docker Host-Port-Publishing von InfluxDB 8181 | abgeloester Altstand |
host |
host | nur für echte Sonderfälle | begründet |
3.2 Finales Diagramm (vereinfacht)
Internet
│
▼
traefik (80/443)
│
└── frontend_net
├── öffentliche Apps (vaultwarden, mealie, paperless, immich, gitea, ntfy, mail-archiver, nextcloud)
├── geschützte UIs mit Middleware (homepage, paperless-gpt, uptime-kuma, filebrowser, scrutiny, code-server, borg-ui, glances, speedtest, bentopdf, grafana)
├── Admin-UI mit nativer Auth (komodo)
└── Dienste mit Internetbedarf ohne öffentliche UI (ddns-updater)
backend_net (internal: true)
├── postgresql17
├── Redis
├── mail-archiver
└── paperless-ngx
dns_net
├── AdGuard Home (+ frontend_net, feste IP 172.23.0.3)
└── unbound
App-interne Netze
├── mealie_internal (internal: true) ✅
├── immich_default (internal: true) ✅
├── nextcloud_internal (internal: true) ✅
├── monitoring_net (zentraler Observability-Stack)
├── monitoring_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route)
├── grafana_influx_internal (Altstand)
└── grafana_influx_lan (Altstand)
Host-Sonderfälle
├── tailscale
└── Plex-Media-Server
4. Zugangsmodell: Traefik vs. Tailscale
4.1 Öffentlich über Traefik
Diese Dienste sind über echte *.kaleschke.info-Domains erreichbar:
vaultwarden— vault.kaleschke.infomealie— mealie.kaleschke.infopaperless-ngx— paperless.kaleschke.infontfy— ntfy.kaleschke.infogitea(Web) — git.kaleschke.infoimmich_server— immich.kaleschke.infonextcloud— cloud.kaleschke.info
4.2 Nicht öffentlich / nur Tailscale oder Traefik + Middleware
Diese Dienste sind keine Public Apps:
Komodo— komodo.kaleschke.info (Traefik, aber bewusst ohne zentrale Middleware; native Auth bleibt aktiv)UptimeKuma— uptime.kaleschke.info (Middleware)filebrowser— files.kaleschke.info (Middleware)scrutiny— scrutiny.kaleschke.info (Middleware)code-server— Traefik + Middlewareborg-ui— borg.kaleschke.info (Middleware)homepage— home.kaleschke.info (Middleware)paperless-gpt— paperless-gpt.kaleschke.info (Middleware)mail-archiver— mail.kaleschke.info (Middleware + App-Auth)glances— glances.kaleschke.info (Middleware)speedtest-tracker— speedtest.kaleschke.info (Middleware)bentopdf— pdf.kaleschke.info (Middleware)monitoring-grafana— monitoring.kaleschke.info (Middleware)hermes-dashboard— hermes.kaleschke.info (Middleware)Traefik-DashboardAdGuard Home— Port 8082 direkt auf die Admin-UI (80im Container), kein Traefik, nur LAN-Zugang
4.3 Regel
Wenn ein Dienst im frontend_net hängt, heißt das nicht automatisch öffentlich. Admin-Dienste dürfen im frontend_net liegen, wenn:
- Traefik sie routet
- zentrale Middleware aktiv ist
- keine direkten Host-Ports bestehen
- Zugriff durch Tailscale bzw. Auth begrenzt ist
Komodo ist hiervon die dokumentierte Ausnahme: Traefik ja, aber keine pauschale ForwardAuth-Middleware, damit Webhooks, API und Periphery-Kommunikation nicht versehentlich beeintraechtigt werden.
5. Globale Sicherheitsregeln
- Keine produktiven Dienste im Docker-Default-
bridge - Keine direkten Host-Ports für Web-UIs außer dokumentierte Ausnahmen
restart: unless-stoppedals Standard- Secrets als Datei /
_FILEoder Komodo Stack Environment Variables mit${VAR} no-new-privileges:trueergänzen, wo praktikabeltraefik.docker.network=frontend_netimmer explizit setzen- Admin- und interne Web-Dienste standardmaessig mit zentraler Middleware absichern (
authelia@file,secure-headers@fileoder dokumentierte Ausnahme) - Placeholder-Domains (
yourdomain.tld) sind verboten privileged: truenur mit Begründung- Volume-Mounts so klein und so read-only wie möglich
- Neue Dienste nur via Compose / Git-Stack
- Änderungen immer gegen dieses Dokument prüfen
6. Einordnungsschema für neue Container
Schritt 1 — Hat der Dienst eine Web-UI?
- Ja →
frontend_net - Nein → weiter zu Schritt 2
Schritt 2 — Braucht der Dienst externe Internetverbindungen?
- Ja →
frontend_net(auch ohne Web-UI) - Nein → weiter zu Schritt 3
Schritt 3 — Braucht der Dienst eine DB / Redis / interne Backends?
- Ja → zusätzlich
backend_netoder eigenes app-internes Netz - Nein → nur das funktional nötige Netz
Schritt 4 — Ist es eine Datenbank oder ein Cache?
- Ja → niemals
frontend_net, nurbackend_netoder internes Compose-Netz
Schritt 5 — Ist es ein Admin-/Monitoring-Dienst?
- Ja → wenn Web-UI vorhanden trotzdem
frontend_net, aber nur mit Middleware und ohne direkte Portfreigabe
Schritt 6 — Braucht der Dienst Host-/Discovery-/L2-Sicht?
- Ja →
hostnur mit dokumentierter Begründung
Schritt 7 — Braucht die App ein eigenes internes App-Netz?
- Ja → Compose-internes Netz mit
internal: true
7. Container-Zielbild (vollständig)
Legende Status:
✅= umgesetzt und in Git-Stack✅ (Dockerman)= Traefik/Netz korrekt konfiguriert, noch kein Git-Stack⏳= noch zu migrieren / zu korrigieren⚠️ Legacy= läuft, wird abgelöst❌= entfernt
7.1 Infrastruktur / Core
| Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte |
|---|---|---|---|---|---|
traefik |
✅ | frontend_net, backend_net |
öffentlich 80/443 | zentraler Ingress, Service-Routing via Docker-Labels | — |
AdGuard Home |
✅ | dns_net (172.23.0.3), frontend_net |
Port 53 DNS direkt, Port 8082 Admin (LAN) | DNS-Server + Upstream zu unbound; kein Traefik (DNS-Sonderfall) | Admin-Port per Traefik + Middleware absichern (Block F) |
unbound |
✅ | dns_net |
intern | Upstream-Resolver für AdGuard, isoliert | — |
ddns-updater |
✅ | frontend_net |
intern | Cloudflare DNS API; bleibt in frontend_net |
Dokumentierte Ausnahme |
tailscale |
✅ | host |
VPN-Zugang | Git-Stack (host-services/tailscale/) |
nutzt NET_ADMIN, NET_RAW und /dev/net/tun als dokumentierte VPN-Ausnahme |
homepage |
✅ | frontend_net |
Traefik + Middleware | geschuetztes Start-Dashboard via home.kaleschke.info |
— |
7.2 Sicherheit / Identity
| Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte |
|---|---|---|---|---|---|
vaultwarden |
✅ | frontend_net |
Traefik | kein Host-Port, ADMIN_TOKEN_FILE |
— |
authelia |
✅ | frontend_net, backend_net |
Traefik via auth.kaleschke.info |
aktiver ForwardAuth-Provider, Secrets via _FILE, PostgreSQL Storage; bewusst ohne Redis-Session-Backend |
— |
7.3 Datenbanken / Caches
| Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte |
|---|---|---|---|---|---|
postgresql17 |
✅ | backend_net |
intern | kein Host-Port, POSTGRES_PASSWORD_FILE |
— |
Redis |
✅ | backend_net |
intern | intern-only Cache | optional named volume |
mealie-postgres |
✅ | mealie_internal |
intern | isoliert, nie frontend_net |
— |
immich_postgres |
✅ | immich_default |
intern | intern-only | — |
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 | — |
7.4 Produktive Apps
| Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte |
|---|---|---|---|---|---|
paperless-ngx |
✅ | frontend_net, backend_net |
Traefik | aktiv via paperless.kaleschke.info |
— |
mail-archiver |
✅ | frontend_net, backend_net |
Traefik + Middleware | aktiv via mail.kaleschke.info; IMAP-Abruf + DB-Zugang; App-eigene Auth bleibt zusaetzliche Schutzschicht |
— |
mealie |
✅ | frontend_net, mealie_internal |
Traefik | sauber getrennte App/DB-Struktur | — |
ntfy |
✅ | frontend_net |
Traefik | aktiv via ntfy.kaleschke.info, Git-Stack |
— |
gitea |
✅ | frontend_net |
Traefik + SSH-Port 222 | Web via Traefik, SSH direkt gebunden | — |
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 |
7.5 Admin / Operations
| Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte |
|---|---|---|---|---|---|
komodo |
✅ | frontend_net |
Traefik, native Auth | primaerer GitOps-Stack-Manager | bewusste Ausnahme: keine pauschale ForwardAuth-Middleware vor UI/API/Webhooks/Periphery |
code-server |
✅ | frontend_net |
Traefik + Middleware | PASSWORD_FILE aktiv |
— |
PortainerCE |
❌ entfernt | - | - | 2026-03-29 abgeschaltet | historisch; nicht mehr deployen |
filebrowser |
✅ | frontend_net |
Traefik + Middleware | aktiv via files.kaleschke.info |
Appdata-Breitmount entfernt; nur Documents/Photos/Projekte plus eigener App-State |
borg-ui |
✅ | frontend_net |
Traefik + Middleware | produktiver Borg-/Restore-Dienst; /local/secrets ist bewusst Teil des Restore-Scopes |
BorgBase-Repo und Key laufend pflegen |
paperless-gpt |
✅ | frontend_net |
Traefik + Middleware | aktiv via paperless-gpt.kaleschke.info |
— |
bentopdf |
✅ vorbereitet | frontend_net |
Traefik + Middleware | PDF-Tooling via pdf.kaleschke.info; browserseitige Verarbeitung, COOP/COEP fuer Office-Konvertierung |
Deploy und fachliche Abnahme offen |
hermes-dashboard |
✅ | frontend_net, hermes_net |
Traefik + Middleware | aktiv via hermes.kaleschke.info; Dashboard bindet intern mit --insecure auf 0.0.0.0, externe Absicherung ueber Authelia |
— |
7.6 Monitoring / Status
| Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte |
|---|---|---|---|---|---|
UptimeKuma |
✅ | frontend_net |
Traefik + Middleware | aktiv via uptime.kaleschke.info |
— |
glances |
✅ | frontend_net |
Traefik + Middleware | aktiv via glances.kaleschke.info |
— |
scrutiny |
✅ | frontend_net |
Traefik + Middleware | aktiv via scrutiny.kaleschke.info, Git-Stack |
privileged später prüfen |
speedtest-tracker |
✅ | frontend_net |
Traefik + Middleware | aktiv via speedtest.kaleschke.info |
— |
monitoring-grafana |
Ziel | frontend_net, monitoring_net |
Traefik + Middleware | zentrale UI via monitoring.kaleschke.info; Datasources fuer Prometheus, Loki und InfluxDB |
nach Deploy testen |
monitoring-influxdb3-core |
Ziel | monitoring_net, monitoring_influx_lan + LAN-Bind |
LAN-Port nur fuer interne Writer | InfluxDB 3 Core fuer Home-Assistant-/Ecowitt-Langzeitdaten; keine Traefik-/Public-Freigabe; Port 8181 nur via INFLUXDB_BIND_IP |
HA-Write-Token und Sensor-Export finalisieren |
loki |
✅ | backend_net |
intern | interner Container-Logspeicher ohne Public Route; Grafana greift ueber Loki-Datasource zu | Retention/Storage nach erstem Produktivlauf beobachten |
monitoring-promtail |
Ziel | monitoring_net |
intern | Docker-Log-Collector mit read-only Docker-Socket-Ausnahme; schreibt nach Loki | Socket-Ausnahme regelmaessig pruefen |
grafana / influxdb3-core / loki / alloy |
Altstand | diverse | abgeloest | nicht parallel zum monitoring/-Zielstack betreiben |
nach erfolgreicher Migration stoppen |
7.7 Noch offene Sonderfälle
| Container | Status | Ziel |
|---|---|---|
Plex-Media-Server |
⏳ Dockerman | Compose-Migration, host-Netz bleibt (Discovery) |
7.8 Entfernte Container
| Container | Entfernt am | Begründung |
|---|---|---|
scanopy-server |
2026-03-26 | nicht genutzt, durch paperless-ngx ersetzt |
scanopy-postgres |
2026-03-26 | zusammen mit scanopy entfernt |
scanopy-daemon |
2026-03-26 | zusammen mit scanopy entfernt |
diun |
2026-03-28 | Update-Monitoring via Komodo; Stack + Netz diun_diun_default + Repo-Eintrag entfernt |
binhex-official-pihole |
2026-03-28 | ersetzt durch AdGuard Home + Unbound |
gotify |
2026-03-28 | nicht mehr aktiv; Push-Notifications via ntfy abgedeckt |
Dozzle |
2026-03-28 | nicht mehr aktiv |
dashdot |
2026-03-28 | nicht mehr aktiv |
netdata |
2026-03-28 | nicht mehr aktiv |
netalertx |
2026-03-28 | nicht mehr aktiv |
luckyBackup |
2026-03-28 | nicht mehr aktiv; Backup via Borg |
backrest |
2026-05-15 | entfernt; Borg ist die alleinige Backup-Technologie, WD MyBookLive ist kein Backup-Ziel mehr |
Stash |
2026-03-28 | nicht mehr aktiv |
PortainerCE |
2026-03-29 | abgeschaltet; Komodo ist alleiniger Stack-Manager |
beszel |
nicht dokumentiert | bereits entfernt; nicht mehr Teil des Zielbilds |
beszel-agent |
nicht dokumentiert | bereits entfernt; nicht mehr Teil des Zielbilds |
8. Traefik-Label-Standard
Jeder Dienst mit Traefik-Routing nutzt dieses Muster:
labels:
- traefik.enable=true
- traefik.docker.network=frontend_net
- traefik.http.routers.<name>.rule=Host(`<subdomain>.kaleschke.info`)
- traefik.http.routers.<name>.entrypoints=websecure
- traefik.http.routers.<name>.tls=true
- traefik.http.routers.<name>.tls.certresolver=le
- traefik.http.services.<name>.loadbalancer.server.port=<interner-port>
Zusatz fuer Admin-Dienste (Standard)
- traefik.http.routers.<name>.middlewares=authelia@file,secure-headers@file
Regeln
traefik.docker.networkimmer explizit auffrontend_net- keine
yourdomain.tld-Platzhalter - certresolver immer
le tls=trueimmer explizit setzen- wenn Traefik aktiv ist, werden direkte Host-Ports entfernt
- Admin-Dienste standardmaessig nicht ohne Middleware veroeffentlichen
- Das Traefik-Dashboard nutzt ebenfalls
authelia@file; dokumentierte Ausnahmen wieKomodobleiben moeglich - File-Provider nur noch für:
middlewares.yml,tls.yml,dashboards.yml— keine Service-Routen mehr via File-Provider - dokumentierte Ausnahmen muessen in Abschnitt 10 begruendet werden
9. Historische Migration (abgeschlossen)
Die frühere Blockmigration aus der Portainer-/Dockerman-Phase ist fachlich abgeschlossen.
Dieser Abschnitt dient nur noch als historischer Vermerk:
- Traefik läuft labelbasiert ohne Service-Routen im File-Provider.
- Komodo ist der einzige aktive Stack-Manager.
- Portainer CE ist entfernt.
- Borg/Borg UI, Dump-Automatisierung und Restore-Test sind produktiv eingeführt.
- Frühere Sprint-/Block-Checklisten werden hier nicht mehr operativ gepflegt.
Für den laufenden Betrieb gilt stattdessen:
- Zielbild und Architektur in diesem Dokument
- Git-/Komodo-Ablauf in
docs/WORKFLOW.md - fachliche Änderungen in der jeweils betroffenen Stack-Doku
- Entscheidungen und besondere Umstellungen im Entscheidungs-Log unten
10. Bekannte Ausnahmen und Begründungen
| Container | Ausnahme | Begründung |
|---|---|---|
traefik |
Host-Ports 80/443 | zentraler Reverse Proxy |
tailscale |
host, NET_ADMIN, NET_RAW, /dev/net/tun |
VPN-Zugang benoetigt Kernel-Netzwerkfunktionen; Umstellung nur kontrolliert moeglich |
AdGuard Home |
Port 53 (TCP/UDP) direkt + Port 8082 auf Container-Port 80 | DNS benötigt direkten Port 53; kein HTTP-Proxy für DNS möglich |
Plex-Media-Server |
host |
Discovery / mDNS / Plex GDM |
scrutiny |
privileged: true |
SMART-Datenzugriff auf Laufwerke |
Komodo |
Docker-Socket Zugriff | Stack-Deployments benötigen Socket |
Komodo |
keine pauschale zentrale Middleware | Webhooks (/listener), API und Periphery-WebSocket (/ws/periphery) sollen nicht durch vorgeschaltete ForwardAuth gebrochen werden |
gitea |
SSH-Port 222 direkt gebunden | Git-SSH-Zugang; kein HTTP-Proxy für SSH möglich |
ddns-updater |
bleibt in frontend_net statt backend_net |
braucht Cloudflare-API-Zugang; backend_net ist internal: true |
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-promtail |
Docker-Socket read-only | Docker-Log-Discovery fuer Loki; keine Schreibrechte, keine Appdaten-Persistenz ueber den Socket |
11. Projektorganisation und Arbeitsmodus
11.1 Unser Arbeitsprinzip
Dieses Projekt wird heute nicht mehr sprintweise im Dokument gesteuert, sondern über einen stabilen GitOps-Betrieb.
11.2 Operativer Ablauf
- Zielbild prüfen
- lokal synchronisieren
- gezielt ändern
- Commit + Push
- Komodo-Webhook und Ergebnis prüfen
- Dokumentation nachziehen
11.3 Regel für jede Änderung
- Zielbild in diesem Dokument prüfen
- nur den betroffenen Bereich anfassen
- Änderung lokal vorbereiten
- nach Gitea pushen
- automatische Reaktion von Komodo beachten
- testen
- dokumentieren
11.4 Source-of-Truth-Hierarchie
- Gitea Online (
origin/master) - lokaler Clone / GitHub Desktop
- Compose-Dateien im Git-Repo
- Komodo als Deploy-Consumer
- operative Checklisten und Notizen
11.5 Operativer Git-Workflow
- Gitea Online ist der verbindliche Sollzustand.
- Lokal wird standardmäßig über GitHub Desktop gearbeitet.
- Komodo deployt aus Gitea und ist kein Bearbeitungsort.
- Webhooks sind aktiv: Ein Push kann unmittelbar einen Komodo-Deploy auslösen.
- Wenn online in Gitea editiert wurde, muss vor der nächsten lokalen Änderung zuerst
Fetch originund danachPull originerfolgen.
12. Nutzung mit KI / Kontext-Regel
Wenn mit einer KI gearbeitet wird, gilt immer:
„Lies zuerst
HOMELAB_ARCHITECTURE_MASTER_V2.md, dann beantworte meine Frage."
Damit ist sofort klar:
- welche Netze Standard sind
- welche Container wohin gehören
- welche Dienste öffentlich sein dürfen
- welche Dienste nur intern/VPN-only sind
- welche Migrationen noch offen sind
- welche Ausnahmen bewusst dokumentiert sind
13. Betriebserfahrungen und Entscheidungs-Log
Traefik — Wechsel zu reinen Docker-Labels (2026-03-28)
Die statischen File-Provider-Konfigurationen in /mnt/user/appdata/traefik/dynamic/ wurden vollständig bereinigt:
- Gelöscht:
immich.yml,gitea.yml,mealie.yml,scrutiny.yml,vaultwarden.yml.bak - Verbleibend (notwendig):
middlewares.yml,tls.yml,dashboards.yml
Hintergrund: Die alten File-Provider-Configs haben @file-Routen mit @docker-Routen konkurrieren lassen. In Traefik v3 gewinnt der File-Provider und hat z.B. Immich auf die falsche IP geroutet (Bad Gateway). Nach Löschung läuft Traefik ausschließlich auf Docker-Labels.
Regel: Neue Dienste ausschließlich via Docker Compose Labels konfigurieren. Keine neuen .yml-Dateien im dynamic/-Verzeichnis für Service-Routen anlegen.
Komodo — Ablösung von Portainer als Stack-Manager (2026-03-28)
Komodo ist nun der primäre GitOps-Stack-Manager:
- Komodo Core läuft als Docker-Stack (
ops/komodo/docker-compose.yml) - Komodo Periphery läuft auf dem Unraid-Host für direktes Server-Management
- Stacks werden via Gitea synchronisiert und über Komodo deployed
- Portainer CE ist abgeschaltet; Komodo ist der alleinige aktive Stack-Manager
Betriebsregel: Alle Stack-Änderungen laufen über Git; Komodo konsumiert nur den Stand aus Gitea.
Zugangsregel: Komodo bleibt bewusst bei nativer Authentifizierung ohne pauschal vorgeschaltete ForwardAuth-Middleware vor dem gesamten Router. Hintergrund sind die gemischten UI-, API-, Webhook- und Periphery-Endpunkte unter derselben Domain.
Komodo Self-Stack Drift-Recovery (2026-05-04)
- Befund:
komodo-coreundkomodo-peripheryliefen aus temporaeren/tmp/*repair.yml-Dateien, waehrendkomodo-mongoauf den fehlenden persistenten Pfad/mnt/user/services/stacks/komodo/compose.yamlverwies. - Recovery: Repair-YAMLs und Runtime-ENV wurden unter
/mnt/user/appdata/komodo/_drift_backup_2026-05-04/gesichert; eine zusaetzliche Recovery-ENV liegt unter/mnt/user/appdata/secrets/_komodo_stack_env_recovery_2026-05-04.envund ist als temporaeres Tier-1-Secret-Material zu behandeln. - Der persistente Self-Stack wurde unter
/mnt/user/services/stacks/komodo/compose.yamlausops/komodo/docker-compose.ymlwiederhergestellt. Die hostseitige.envbleibt ausserhalb von Git. - Reconcile-Regel: Bei Self-Stack-Drift keinen pauschalen
docker compose up -dausfuehren, wenn der Dry-runkomodo-mongorecreaten wuerde. Core und Periphery koennen gezielt mit--no-depsneu erstellt werden, Mongo bleibt dabei unangetastet. - Ergebnis: Alle drei Komodo-Container zeigen wieder auf
/mnt/user/services/stacks/komodo/compose.yaml; Mongo blieb waehrend der Rueckfuehrung healthy.
AdGuard Home — Ablösung von Pi-hole (2026-03-28)
binhex-official-pihole wurde entfernt und durch AdGuard Home + unbound ersetzt:
- AdGuard läuft als Git-Stack (
host-services/Adguard/docker-compose.yml) - Netzwerke:
dns_net(feste IP 172.23.0.3) +frontend_net - Port 53 (DNS) direkt gebunden — dokumentierte Ausnahme
- Admin-UI direkt gebunden via Host-Port 8082 auf Container-Port 80 — Traefik-Absicherung ausstehend (Block F)
unboundläuft weiterhin als Upstream-Resolver indns_net
diun — Entfernung (2026-03-28)
diun (Docker Image Update Notifier) wurde deinstalliert:
- Stack gelöscht
- Orphan-Netzwerk
diun_diun_defaultbereinigt - Repo-Eintrag
infra/diun/aus Git entfernt
Update-Monitoring kann über Komodo's eingebaute Update-Notifications abgedeckt werden.
ntfy — Push-Notifications (Git-Stack)
ntfy läuft als Git-Stack (apps/ntfy/docker-compose.yml):
ntfy.kaleschke.infovia TraefikNTFY_UPSTREAM_BASE_URL: https://ntfy.shfür mobile Push-NotificationsNTFY_BEHIND_PROXY: truekorrekt gesetzt
immich_default — internal: true gesetzt (2026-03-29)
immich_default wurde von external: true auf ein Compose-verwaltetes internes Netz umgestellt:
- Vorher:
external: true(manuell erstellt, falsche Labelscom.docker.compose.network=default) - Nachher: Compose-managed,
internal: true,driver: bridge, korrekte Labels - Durchgeführt via: manuelles
docker stopder Containers →docker network rm immich_default→ Komodo Redeploy - Ergebnis: alle Immich-Container (
immich_postgres,immich_redis,immich_machine_learning) sind jetzt vom Internet isoliert; nurimmich_serverhat zusätzlichfrontend_netfür Traefik
Secrets in Komodo Stacks
Host-Pfade in env_file (z.B. /mnt/...) sind in Git-Stacks nicht verfügbar. Standardlösung: Stack Environment Variables + ${VARIABLE_NAME} in der Compose.
Regel: Wenn _FILE nicht unterstützt wird → Stack Environment Variable. Kein Secret im Git.
Bewusste Ausnahme: paperless-ngx bleibt fuer PAPERLESS_DBPASS und PAPERLESS_REDIS vorerst bei Stack Environment Variables. Eine Umstellung auf _FILE ist fachlich denkbar, wird aber nicht gegen den aktuell stabilen Produktionsstand erzwungen.
Borg UI / BorgBase (2026-04-12)
borg-uiläuft als Admin-Dienst inops/borg-ui/docker-compose.yml- nur
frontend_net, weil Web-UI + externer SSH-Zugang zu BorgBase benötigt werden - keine direkten Host-Ports; Zugriff ausschließlich via Traefik + Middleware über
borg.kaleschke.info - breite Restore-/Backup-Mounts bewusst gesetzt; inklusive
/local/secretsfuer Disaster Recovery, separates Restore-Ziel unter/mnt/user/appdata/borg-ui/restore - kein separater Borg-CLI-Container nötig, da Borg UI die Borg-CLI bereits im Container mitbringt
| Container | _FILE Support |
|---|---|
| Vaultwarden | ✅ ja |
| PostgreSQL | ✅ ja |
| code-server | ✅ ja (PASSWORD_FILE) |
| Immich Postgres | ✅ ja (POSTGRES_PASSWORD_FILE) |
| Mealie | ✅ ja (POSTGRES_PASSWORD_FILE) |
| paperless-ngx | ❌ nein für DB-Pass → Stack ENV |
Reproduzierbare Deployments (2026-04-17)
Mutable Tags wie latest, stable, release oder reine Major-Tags wurden auf die aktuell laufenden Digests eingefroren. Das ist bewusst kein Upgrade-Mechanismus, sondern dient dazu, den heute funktionierenden Laufzeitstand exakt im Repo festzuhalten. Echte Versions-Upgrades bleiben ein eigener, geplanter Schritt.
Stateful Digest-Pinning (2026-05-05, ergaenzt 2026-05-16)
- Tier-1/stateful Basisdienste werden bevorzugt mit sprechendem Minor-/Patch-Tag plus Digest gepinnt, z. B.
postgres:17.9@sha256:...odermongo:7.0.32@sha256:.... - Redis-Caches sind seit dem Hardening-Sprint 2026-05-16 auf
redis:7.4-alpine@sha256:...vereinheitlicht. Updates erfolgen bewusst stackweise mit Smoke-Test. - Bereits versionierte Apps koennen optional spaeter ebenfalls Digests erhalten; dieser Schritt ist getrennt vom Datenhalter-Pinning.
Nextcloud und Stirling-PDF (2026-04-19)
nextcloudwird bewusst nicht als AIO-Stack gebaut, sondern als klassischer Docker-Microservice-Stack mit eigenem PostgreSQL und eigenem Redis. Das passt besser zum bestehenden GitOps-/Compose-Modell des Repos.nextcloudbleibt bei nativer App-Authentifizierung ohne zentrale ForwardAuth-Middleware vor dem Router, damit Browser-Login, Desktop-/Mobile-Clients sowie WebDAV/CardDAV sauber funktionieren.stirling-pdfwird als geschuetzter Tool-Stack hinterauthelia@file,secure-headers@filebetrieben; die interne Stirling-Login-Funktion bleibt deaktiviert, um Doppel-Login zu vermeiden.
BentoPDF und Monitoring-Zielstack (2026-04-30, aktualisiert 2026-05-17)
bentopdfersetzt repo-seitigstirling-pdfauf der bestehenden Domainpdf.kaleschke.info, bleibt aber bis zum bewussten Komodo-Deploy nur vorbereitet.- BentoPDF benoetigt fuer Office-Konvertierung die Cross-Origin-Isolation-Header
Cross-Origin-Opener-Policy: same-originundCross-Origin-Embedder-Policy: require-corp; diese werden per Traefik-Docker-Middleware gesetzt. monitoring/ist der zentrale Zielstack fuer Prometheus, Loki, Promtail, Grafana, node-exporter, cAdvisor und InfluxDB 3 Core.monitoring-grafanawird als geschuetztes Monitoring-UI untermonitoring.kaleschke.infobetrieben.monitoring-influxdb3-corebleibt ohne Traefik-/Public-Route; fuer interne Writer wie Home Assistant kann Port8181perINFLUXDB_BIND_IPauf eine LAN-Adresse gebunden werden.- Fuer dieses Port-Publishing nutzt
monitoring-influxdb3-corezusaetzlichmonitoring_influx_lan. Das ist keine Public-App-Freigabe und ersetzt nicht die Token-Authentifizierung. - InfluxDB 3 Core nutzt einen festen Versionstag statt
latest, weil der InfluxDB-latest-Tag versionsstrategisch im Umbruch ist. - Die alten Pfade
ops/grafana-influxdbundops/lokisind abgeloeste Altstaende und sollen nach erfolgreichem Monitoring-Deploy nicht parallel betrieben werden.
Monitoring-Logging-Baseline (2026-05-17)
monitoring-lokilaeuft intern aufmonitoring_net, ohne Traefik-Route und ohne Host-Port.monitoring-promtailsammelt Docker-Logs ueber/var/run/docker.sock:round/var/lib/docker/containers:round schreibt sie an Loki.monitoring-grafanabekommt provisionierte Datasources fuer Prometheus, Loki und InfluxDB 3 Core.- Loki-Logdaten sind Diagnosematerial mit begrenzter Retention, keine primaere Restore-Quelle.
Authelia ohne Redis-Session-Backend (2026-05-04)
- Authelia nutzt PostgreSQL fuer persistente Storage-Daten, aber bewusst kein Redis-Session-Backend.
- Das haelt den Tier-1-Auth-Pfad einfacher; nach einem Authelia-Restart muessen aktive Sessions neu aufgebaut werden.
infra/redisbleibt shared Cache fuer Dienste wie Paperless, ist aber keine Authelia-Abhaengigkeit.
ddns-updater — Netz-Ausnahme
Bleibt bewusst in frontend_net statt backend_net, weil backend_net internal: true ist und ddns-updater die Cloudflare-API erreichen muss.
mail-archiver — Hybrid-Dienst
Benötigt backend_net (PostgreSQL) + frontend_net (IMAP-Abruf von GMX/Gmail). Kein reiner Backend-Dienst. Die Web-UI ist via Traefik unter mail.kaleschke.info erreichbar und wird durch authelia@file,secure-headers@file plus App-eigene Auth geschuetzt.
Netzwerk-Standard für Apps mit Datenbanken
- App →
frontend_net+ internes Netzwerk - Datenbank → nur internes Netzwerk (
internal: true)
Beispiel (Mealie): mealie → frontend_net + mealie_internal, mealie-postgres → nur mealie_internal.
Schlussformel
Dieses Dokument ist keine lose Notiz, sondern das operative Masterdokument für die Docker- und Zugriffsarchitektur des Homelabs.
Zielbild in einem Satz:
frontend_net für Web-UIs und Dienste mit Internetbedarf, backend_net für interne Backends, app-interne Netze nur wenn technisch nötig, Tailscale für Remote-Admin-Zugriff, Traefik als einziger Web-Einstieg (Service-Routing via Docker-Labels, File-Provider nur für zentrale Dynamic-Config), Komodo als GitOps-Stack-Manager, AdGuard Home + Unbound für DNS, keine produktiven Container im Docker-Default-bridge.