# 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-04-17 | **Aktueller Schwerpunkt:** GitOps / Doku-Synchronisierung / Reproduzierbare Deployments --- ## Inhaltsverzeichnis 1. [Systemüberblick](#1-systemüberblick) 2. [Architektur-Prinzipien](#2-architektur-prinzipien) 3. [Finales Netzwerk-Zielbild](#3-finales-netzwerk-zielbild) 4. [Zugangsmodell: Traefik vs. Tailscale](#4-zugangsmodell-traefik-vs-tailscale) 5. [Globale Sicherheitsregeln](#5-globale-sicherheitsregeln) 6. [Einordnungsschema für neue Container](#6-einordnungsschema-für-neue-container) 7. [Container-Zielbild (vollständig)](#7-container-zielbild-vollständig) 8. [Traefik-Label-Standard](#8-traefik-label-standard) 9. [Historische Migration (abgeschlossen)](#9-historische-migration-abgeschlossen) 10. [Bekannte Ausnahmen und Begründungen](#10-bekannte-ausnahmen-und-begründungen) 11. [Projektorganisation und Arbeitsmodus](#11-projektorganisation-und-arbeitsmodus) 12. [Nutzung mit KI / Kontext-Regel](#12-nutzung-mit-ki--kontext-regel) 13. [Betriebserfahrungen und Entscheidungs-Log](#13-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 + 3000/Admin), `Tailscale`, `Plex-Media-Server`. ### P2 — Das Setup bleibt bewusst einfach: `frontend_net` + `backend_net` + app-interne Netze - `frontend_net` = Proxy-/Web-Netz - `backend_net` = intern für DB/Cache/App-Kommunikation - zusätzliche Netze nur app-intern, wenn technisch nötig (`mealie_mealie_internal`, `immich_default`, `dns_net`) Es gibt **keine künstlichen globalen Zusatznetze** wie `admin_net`, `monitoring_net` oder `media_net`. ### 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, backrest 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änzen - `privileged: true` nur 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_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 | | `host` | host | nur für echte Sonderfälle | begründet | ### 3.2 Finales Diagramm (vereinfacht) ```text 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, backrest, borg-ui, glances, speedtest, stirling-pdf) ├── 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_mealie_internal (internal: true) ✅ ├── immich_default (internal: true) ✅ └── nextcloud_internal (internal: true) ✅ 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.info - `mealie` — mealie.kaleschke.info - `paperless-ngx` — paperless.kaleschke.info - `ntfy` — ntfy.kaleschke.info - `gitea` (Web) — git.kaleschke.info - `immich_server` — immich.kaleschke.info - `mail-archiver` — mail.kaleschke.info - `nextcloud` — 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 + Middleware - `backrest` — Traefik + Middleware - `borg-ui` — borg.kaleschke.info (Middleware) - `homepage` — home.kaleschke.info (Middleware) - `paperless-gpt` — paperless-gpt.kaleschke.info (Middleware) - `glances` — glances.kaleschke.info (Middleware) - `speedtest-tracker` — speedtest.kaleschke.info (Middleware) - `stirling-pdf` — pdf.kaleschke.info (Middleware) - `Traefik-Dashboard` - `AdGuard Home` — Port 3000 direkt (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 1. Keine produktiven Dienste im Docker-Default-`bridge` 2. Keine direkten Host-Ports für Web-UIs außer dokumentierte Ausnahmen 3. `restart: unless-stopped` als Standard 4. Secrets als Datei / `_FILE` oder Komodo Stack Environment Variables mit `${VAR}` 5. `no-new-privileges:true` ergänzen, wo praktikabel 6. `traefik.docker.network=frontend_net` immer explizit setzen 7. Admin- und interne Web-Dienste standardmaessig mit zentraler Middleware absichern (`authelia@file,secure-headers@file` oder dokumentierte Ausnahme) 8. Placeholder-Domains (`yourdomain.tld`) sind verboten 9. `privileged: true` nur mit Begründung 10. Volume-Mounts so klein und so read-only wie möglich 11. Neue Dienste nur via Compose / Git-Stack 12. Ä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_net` oder eigenes app-internes Netz - **Nein** → nur das funktional nötige Netz ### Schritt 4 — Ist es eine Datenbank oder ein Cache? - **Ja** → niemals `frontend_net`, nur `backend_net` oder 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** → `host` nur 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 3000 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/`) | `TS_USERSPACE`/`privileged` später prüfen | | `backrest` | ✅ | `frontend_net`, `backend_net` | Traefik + Middleware | produktiver Backup-Admin-Dienst | breite Mounts bewusst dokumentieren | | `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 + Redis Shared | — | ### 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_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 Öffentliche 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 | aktiv via `mail.kaleschke.info`; IMAP-Abruf + DB-Zugang | — | | `mealie` | ✅ | `frontend_net`, `mealie_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` | Mounts einschränken (Block F) | | `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` | — | | `stirling-pdf` | ✅ | `frontend_net` | Traefik + Middleware | PDF-Tooling via `pdf.kaleschke.info`; lokale Stirling-Auth deaktiviert zugunsten zentraler Auth | — | ### 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` | — | ### 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 backrest | | `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: ```yaml labels: - traefik.enable=true - traefik.docker.network=frontend_net - traefik.http.routers..rule=Host(`.kaleschke.info`) - traefik.http.routers..entrypoints=websecure - traefik.http.routers..tls=true - traefik.http.routers..tls.certresolver=le - traefik.http.services..loadbalancer.server.port= ``` ### Zusatz fuer Admin-Dienste (Standard) ```yaml - traefik.http.routers..middlewares=authelia@file,secure-headers@file ``` ### Regeln - `traefik.docker.network` immer explizit auf `frontend_net` - keine `yourdomain.tld`-Platzhalter - certresolver immer `le` - `tls=true` immer 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 wie `Komodo` bleiben 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` | VPN-Zugang; Umstellung nur kontrolliert möglich | | `AdGuard Home` | Port 53 (TCP/UDP) direkt + Port 3000 Admin | 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 | --- ## 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 1. Zielbild prüfen 2. lokal synchronisieren 3. gezielt ändern 4. Commit + Push 5. Komodo-Webhook und Ergebnis prüfen 6. Dokumentation nachziehen ### 11.3 Regel für jede Änderung 1. Zielbild in diesem Dokument prüfen 2. nur den betroffenen Bereich anfassen 3. Änderung lokal vorbereiten 4. nach Gitea pushen 5. automatische Reaktion von Komodo beachten 6. testen 7. dokumentieren ### 11.4 Source-of-Truth-Hierarchie 1. **Gitea Online (`origin/master`)** 2. lokaler Clone / GitHub Desktop 3. Compose-Dateien im Git-Repo 4. Komodo als Deploy-Consumer 5. 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 origin` und danach `Pull origin` erfolgen. ## 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. ### 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 - Port 3000 (Admin-UI) direkt gebunden — Traefik-Absicherung ausstehend (Block F) - `unbound` läuft weiterhin als Upstream-Resolver in `dns_net` ### diun — Entfernung (2026-03-28) `diun` (Docker Image Update Notifier) wurde deinstalliert: - Stack gelöscht - Orphan-Netzwerk `diun_diun_default` bereinigt - 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.info` via Traefik - `NTFY_UPSTREAM_BASE_URL: https://ntfy.sh` für mobile Push-Notifications - `NTFY_BEHIND_PROXY: true` korrekt 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 Labels `com.docker.compose.network=default`) - **Nachher:** Compose-managed, `internal: true`, `driver: bridge`, korrekte Labels - Durchgeführt via: manuelles `docker stop` der Containers → `docker network rm immich_default` → Komodo Redeploy - Ergebnis: alle Immich-Container (`immich_postgres`, `immich_redis`, `immich_machine_learning`) sind jetzt vom Internet isoliert; nur `immich_server` hat zusätzlich `frontend_net` fü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-ui` läuft als Admin-Dienst in `ops/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/secrets` fuer 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. ### Nextcloud und Stirling-PDF (2026-04-19) - `nextcloud` wird 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. - `nextcloud` bleibt bei nativer App-Authentifizierung ohne zentrale ForwardAuth-Middleware vor dem Router, damit Browser-Login, Desktop-/Mobile-Clients sowie WebDAV/CardDAV sauber funktionieren. - `stirling-pdf` wird als geschuetzter Tool-Stack hinter `authelia@file,secure-headers@file` betrieben; die interne Stirling-Login-Funktion bleibt deaktiviert, um Doppel-Login zu vermeiden. ### 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. Aktuell via Traefik unter `mail.kaleschke.info` geroutet. ### Netzwerk-Standard für Apps mit Datenbanken - App → `frontend_net` + internes Netzwerk - Datenbank → nur internes Netzwerk (`internal: true`) Beispiel (Mealie): `mealie` → `frontend_net` + `mealie_mealie_internal`, `mealie-postgres` → nur `mealie_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 `bridge`-Container mehr.