# 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. --- ## 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. [Migrationsstrategie (Blöcke A–F)](#9-migrationsstrategie-blöcke-a-f) 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) --- ## 1. Systemüberblick | Eigenschaft | Wert | |---|---| | Host-OS | Unraid | | Hostname | Kallilabcore | | Reverse Proxy | Traefik v3 | | VPN / Remote-Zugang | Tailscale (`Tailscale-Docker`, host-Netz) | | DNS-Stack | Pi-hole (host) → Unbound (`dns_net`) | | Basis-Domain | `kaleschke.info` | | TLS | Let's Encrypt via Cloudflare DNS Challenge | | Certresolver | `le` | | Compose-Standard | Unraid Compose Manager | | Zusatz-Tool | Portainer als Verwaltungs-UI | | 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 final direkte Host-Ports außer `traefik` selbst. Begründete Ausnahmen: `gitea`-SSH, `Plex-Media-Server`, `binhex-official-pihole`, `Tailscale-Docker`. ### P2 — Das Setup bleibt bewusst einfach: `frontend_net` + `backend_net` + app-interne Netze Die Quellenlage für Homelabs mit Traefik spricht für ein simples 2-Netz-Modell: - `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_internal`, `immich_default`, `scanopy_scanopy`, `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 Portainer, Dozzle, filebrowser, scrutiny, UptimeKuma, dashdot, code-server, luckyBackup, Traefik-Dashboard, netdata, Glances und netalertx sind standardmäßig **Tailscale-only** oder hinter Traefik **mit zentraler Middleware** abgesichert. ### 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 in `_FILE`-Variablen. Ziel: kein sensibles Secret mehr sichtbar in `docker inspect`. ### 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 - `read_only: true` und Non-Root nur nach getesteter Image-Kompatibilität - Docker-Socket standardmäßig vorsichtig behandeln; **PortainerCE ist eine 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 für `unbound` | bleibt | | `mealie_internal` | bridge, `internal: true` | internes Netz nur für `mealie` + `mealie-postgres` | Ziel | | `immich_default` | Compose-intern | internes Immich-Netz | bleibt | | `scanopy_scanopy` | Compose-intern | internes Scanopy-Netz | bleibt | | `diun_default` | Compose-intern | Compose-Netz für diun | bleibt, zusätzlich Join zu `frontend_net` | | `host` | host | nur für echte Sonderfälle | begründet | ### 3.2 Finales Diagramm (vereinfacht) ```text Internet │ ▼ traefik (80/443) │ └── frontend_net ├── öffentliche Apps ├── Admin-UIs mit Middleware └── interne Web-UIs für Tailscale-only backend_net (internal: true) ├── postgresql17 ├── Redis ├── mail-archiver └── paperless / andere Backends App-interne Netze ├── mealie_internal ├── immich_default └── scanopy_scanopy Host-Sonderfälle ├── Tailscale-Docker ├── binhex-official-pihole ├── Plex-Media-Server ├── netdata ├── Glances └── netalertx ``` ### 3.3 Architekturentscheidung (final) **Wir bleiben final bei wenigen Netzen.** Das ist bewusst näher an aktuellen Homelab-Traefik-Setups als ein künstlich übersegmentiertes Docker-Netzmodell. Trennung erfolgt primär über: - Traefik - Auth-/Security-Middlewares - Tailscale - kein direktes Port-Publishing - app-interne Netze - Host-Sonderfälle nur mit Begründung --- ## 4. Zugangsmodell: Traefik vs. Tailscale ### 4.1 Öffentlich über Traefik Diese Dienste dürfen final über echte `*.kaleschke.info`-Domains erreichbar sein: - `homepage` - `vaultwarden` - `mealie` - `paperless-ngx` - `gotify` - `gitea` (Web) - `immich_server` - optional `mail-archiver` - optional `backrest` - optional `Stash` (nur wenn bewusst gewünscht) ### 4.2 Nicht öffentlich / nur Tailscale oder Traefik + Middleware Diese Dienste sind **keine Public Apps**: - `PortainerCE` - `Dozzle` - `UptimeKuma` - `dashdot` - `filebrowser` - `scrutiny` - `luckyBackup` - `code-server` - `scanopy-server` - `Traefik-Dashboard` - `netdata` - `Glances` - `netalertx` ### 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 zusätzlich durch Tailscale bzw. Auth begrenzt ist --- ## 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` 5. `no-new-privileges:true` ergänzen, wo praktikabel 6. `traefik.docker.network=frontend_net` immer explizit setzen 7. Admin-Dienste immer mit `dashboard-auth@file,secure-headers@file` 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 Manager / YAML 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 eine DB / Redis / interne Backends? - **Ja** → zusätzlich `backend_net` oder eigenes app-internes Netz - **Nein** → nur das funktional nötige Netz ### Schritt 3 — Ist es eine Datenbank oder ein Cache? - **Ja** → niemals `frontend_net`, nur `backend_net` oder internes Compose-Netz ### Schritt 4 — Ist es ein Admin-/Monitoring-Dienst? - **Ja** → wenn Web-UI vorhanden trotzdem `frontend_net`, aber nur mit: - Middleware - keiner direkten Portfreigabe - Tailscale-only-Charakter ### Schritt 5 — Braucht der Dienst Host-/Discovery-/L2-Sicht? - **Ja** → `host` nur mit dokumentierter Begründung - **Nein** → kein `host` ### Schritt 6 — Braucht die App ein eigenes internes App-Netz? - **Ja** → Compose-internes Netz mit `internal: true` - **Nein** → kein weiteres Netz anlegen ### Kurzregel - **UI** → `frontend_net` - **DB/Cache** → `backend_net` - **Spezialfall** → app-internes Netz - **Host-Zugriff** → nur dokumentierte Ausnahme --- ## 7. Container-Zielbild (vollständig) Legende Status: - `✅` = bereits weitgehend passend - `⏳` = noch zu migrieren / zu korrigieren ### 7.1 Infrastruktur / Core | Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte | |---|---|---|---|---|---| | `traefik` | ✅ | `frontend_net`, `backend_net` | öffentlich | zentraler Ingress, 80/443 direkt | Middleware-File-Provider sauber pflegen | | `homepage` | ✅ | `frontend_net` | Traefik | öffentliche Startseite | — | | `ddns-updater` | ⏳ | `backend_net` | intern | kein Grund für `frontend_net` | aus `frontend_net` raus | | `Tailscale-Docker` | ⏳ | `host` | VPN-Zugang | bleibt Host-Sonderfall | `restart` fixen; `TS_USERSPACE`/`privileged` später prüfen, nicht als Quick Win | | `binhex-official-pihole` | ⏳ | `host` | LAN DNS / intern | bleibt Host-Sonderfall | `restart` fixen | | `unbound` | ✅ | `dns_net` | intern | Resolver bleibt isoliert | — | | `backrest` | ⏳ | `frontend_net`, `backend_net` | Traefik oder intern | UI via Traefik, Repo intern | `traefik.docker.network` auf `frontend_net`; DNS-Hardcoding entfernen; Mounts straffen | | `diun` | ⏳ | `diun_default`, `frontend_net` | intern | braucht `frontend_net`, um `gotify` zu erreichen | Gotify-Endpoint per Container-Name | | `theme-park` | ⏳ | `frontend_net` oder rein intern | intern oder Traefik | nur veröffentlichen, wenn wirklich genutzt | Placeholder-Labels bereinigen | | `scanopy-daemon` | ⏳ | `host`, `scanopy_scanopy` falls nötig | intern | Host-naher Sonderfall | Privileged nur dokumentiert belassen oder später testen | ### 7.2 Sicherheit / Identity | Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte | |---|---|---|---|---|---| | `vaultwarden` | ✅ | `frontend_net` | Traefik | keine Host-Ports, kein `bridge`, Secret-Datei | `ADMIN_TOKEN`-Bug fixen; Port 4743 entfernen; Compose-Migration | ### 7.3 Datenbanken / Caches | Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte | |---|---|---|---|---|---| | `postgresql17` | ✅ | `backend_net` | intern | keine Host-Ports, kein `bridge` | Port 5432 entfernen; Secret-Datei; Compose-Migration | | `Redis` | ✅ | `backend_net` | intern | intern-only Cache | optional named volume statt anonym | | `mealie-postgres` | ✅ | `mealie_internal` | intern | nur intern, nie `frontend_net` | aus `frontend_net` raus; Secret-Datei | | `immich_postgres` | ⏳ | `immich_default` | intern | intern-only | Passwort rotieren; named volume prüfen | | `immich_redis` | ⏳ | `immich_default` | intern | intern-only | anonymes Volume perspektivisch bereinigen | | `scanopy-postgres` | ⏳ | `scanopy_scanopy` | intern | intern-only | Passwort rotieren (aktuell Wiederverwendung) | ### 7.4 Öffentliche Apps | Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte | |---|---|---|---|---|---| | `paperless-ngx` | ⏳ | `frontend_net`, `backend_net` | Traefik | vorbereitete Labels final aktivieren | `traefik.enable=true`; echte Domain; Port entfernen; Secret-Datei | | `Paperless-AI` | ⏳ | `frontend_net` | Traefik oder intern | Port nicht mehr direkt offen | echte Domain; Labels aktivieren | | `mealie` | ✅ | `frontend_net`, `mealie_internal` | Traefik | sauber getrennte App/DB-Struktur | Port entfernen; Secret-Datei | | `gotify` | ⏳ | `frontend_net` | Traefik oder intern | intern per Container-Name für `diun` erreichbar | Passwort rotieren; Port entfernen | | `gitea` | ⏳ | `frontend_net` | Traefik + SSH | Web via Traefik, SSH-Port bleibt | HTTP-Labels sauberziehen | | `immich_server` | ⏳ | `immich_default`, `frontend_net` | Traefik | internes Immich-Netz bleibt; Web via Traefik | Port 2283 entfernen; Secret-Datei; `frontend_net` ergänzen | | `immich_machine_learning` | ✅ | `immich_default` | intern | bleibt intern | — | | `Stash` | ⏳ | `frontend_net` | intern oder Traefik | aus `bridge` raus; nur veröffentlichen wenn bewusst gewünscht | Port entfernen; ggf. Traefik-Labels | ### 7.5 Admin / Operations | Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte | |---|---|---|---|---|---| | `code-server` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | nicht öffentlich offen | `PASSWORD` → `HASHED_PASSWORD`; Secret-Datei | | `PortainerCE` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | keine Host-Ports | echte Domain; Labels aktivieren; direkte Ports entfernen; **Docker-Socket nicht blind auf `:ro`** | | `Dozzle` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | keine Host-Ports | Labels aktivieren; direkte Ports entfernen | | `filebrowser` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | aus `bridge`; breite FS-Mounts prüfen | Port entfernen; Mounts einschränken | | `scanopy-server` | ⏳ | `scanopy_scanopy`, `frontend_net` | Traefik + Middleware / Tailscale-only | kein direkter Host-Port | `frontend_net` ergänzen; Port entfernen | | `luckyBackup` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | aus `bridge`; nur intern | Port entfernen; breite Mounts prüfen | ### 7.6 Monitoring / Status | Container | Status | Soll-Netz(e) | Finaler Zugang | Finaler Sollzustand | Offene Punkte | |---|---|---|---|---|---| | `UptimeKuma` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | keine direkten Ports | Labels sauberziehen; Port entfernen | | `dashdot` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | keine direkten Ports | Placeholder-Domain raus; Labels aktivieren | | `Glances` | ⏳ | `host` | Tailscale-only | Host-Metriken | optional später hinter Traefik, aber nicht nötig | | `netdata` | ⏳ | `host` | Tailscale-only | Host-Metriken | `restart` fixen; leere CLAIM-Vars aufräumen | | `scrutiny` | ⏳ | `frontend_net` | Traefik + Middleware / Tailscale-only | aus `bridge`; echtes Image beibehalten | Ports entfernen; später prüfen, ob `privileged` reduziert werden kann | | `netalertx` | ✅ | `host` | Tailscale-only | Host-/Netzsicht bleibt | optional später hinter Traefik, aber kein Muss | --- ## 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 für Admin-Dienste ```yaml - traefik.http.routers..middlewares=dashboard-auth@file,secure-headers@file ``` ### Regeln - `traefik.docker.network` immer explizit auf `frontend_net` - keine `yourdomain.tld`-Platzhalter - certresolver immer `le` - wenn Traefik aktiv ist, werden direkte Host-Ports entfernt - Admin-Dienste niemals ohne Middleware veröffentlichen --- ## 9. Migrationsstrategie (Blöcke A–F) **Letzte Aktualisierung:** 2026-03-25 ### Block A — Quick Wins (geringes Risiko, sofort) ```text [x] restart: unless-stopped für: - Tailscale-Docker - binhex-official-pihole - postgresql17 - vaultwarden - mail-archiver - scrutiny - netdata - Stash - Plex-Media-Server [x] vaultwarden ADMIN_TOKEN-Doppelpräfix korrigieren [x] backrest DNS-Hardcoding entfernen [x] diun ↔ gotify Erreichbarkeit prüfen / herstellen [x] leere Netzwerke prüfen und entfernen: br0, immich_net, kopia_default, netbox_default [x] ungenutzte anonyme Volumes prüfen ``` ### Block B — Kritische Kernmigrationen (höchste Priorität) ```text [x] vaultwarden - von bridge weg - Host-Port weg - Secret-Datei - Traefik sauber aktiv [x] postgresql17 - Port 5432 entfernen - nur backend_net - Secret-Datei - aus bridge raus [x] diun - Join zu frontend_net - gotify via Container-Name [x] mealie-postgres - aus frontend_net raus - mealie_internal ``` ### Block C — Frontend-Stack finalisieren ```text [ ] paperless-ngx - traefik.enable=true - paperless.kaleschke.info - Port entfernen [ ] Paperless-AI - traefik.enable=true - paperless-ai.kaleschke.info - Port entfernen [ ] PortainerCE - traefik.enable=true - portainer.kaleschke.info - Middleware - direkte Ports entfernen [ ] Dozzle - traefik.enable=true - dozzle.kaleschke.info - Middleware - direkte Ports entfernen [ ] dashdot - traefik.enable=true - dash.kaleschke.info - Middleware - direkte Ports entfernen [ ] theme-park - nur wenn wirklich benötigt veröffentlichen ``` ### Block D — Bridge-/Dockerman-Container in Compose ```text [ ] vaultwarden [ ] postgresql17 [ ] mail-archiver [ ] scrutiny [ ] filebrowser [ ] luckyBackup [ ] Stash [ ] Tailscale-Docker [ ] netdata [ ] Plex-Media-Server [ ] binhex-official-pihole ``` ### Block E — Secrets-Migration ```text [ ] vaultwarden → ADMIN_TOKEN_FILE [ ] postgresql17 → POSTGRES_PASSWORD_FILE [ ] mail-archiver → Authentication__Password_FILE [ ] mealie → POSTGRES_PASSWORD_FILE [ ] mealie-postgres → POSTGRES_PASSWORD_FILE [ ] gotify → Passwort rotieren + Secret-Datei [ ] diun → GOTIFY token als Datei [ ] paperless-ngx → PAPERLESS_DBPASS_FILE [ ] code-server → HASHED_PASSWORD / Secret [ ] immich_server → DB_PASSWORD rotieren + Datei [ ] immich_postgres → POSTGRES_PASSWORD_FILE [ ] scanopy-postgres → Passwort rotieren ``` ### Block F — Feinschliff / Hardening ```text [ ] backrest - traefik.docker.network → frontend_net - Mounts straffen [ ] Redis - optional named volume [ ] immich_redis - optional named volume [ ] netdata - leere CLAIM-Vars entfernen [ ] scrutiny - später prüfen, ob privileged reduziert werden kann [ ] Tailscale-Docker - später prüfen, ob TS_USERSPACE/privileged bereinigt werden kann [ ] Pi-hole - zuletzt konsolidieren, nicht als Erstprojekt ``` --- ## 10. Bekannte Ausnahmen und Begründungen | Container | Ausnahme | Begründung | |---|---|---| | `traefik` | Host-Ports 80/443 | zentraler Reverse Proxy | | `Tailscale-Docker` | `host`, aktuell `privileged`, `TS_USERSPACE=true` | bestehender VPN-Zugang; Umstellung nur kontrolliert | | `binhex-official-pihole` | `host` | DNS-/DHCP-naher Sonderfall | | `Plex-Media-Server` | `host` | Discovery / mDNS / Plex GDM | | `netdata` | `host` + zusätzliche Rechte | Host-Metriken | | `Glances` | `host` | Host-Metriken | | `netalertx` | `host` + Netzwerksicht | ARP / Netzwerkscan | | `scanopy-daemon` | `host`, aktuell privilegiert | hardware-/systemnaher Sonderfall | | `PortainerCE` | Docker-Socket nicht dogmatisch `:ro` | Management-UI; Schreiboperationen können nötig sein | --- ## 11. Projektorganisation und Arbeitsmodus ### 11.1 Unser Arbeitsprinzip Dieses Projekt wird **blockweise** umgesetzt, nicht wild containerweise. ### 11.2 Reihenfolge der Umsetzung 1. **Sprint 1:** Quick Wins + `vaultwarden` 2. **Sprint 2:** `postgresql17` + `diun/gotify` 3. **Sprint 3:** `mealie` / `mealie-postgres` + `mail-archiver` 4. **Sprint 4:** Frontend-Stack (`paperless`, `Portainer`, `Dozzle`, `dashdot`, etc.) 5. **Sprint 5:** Compose-Migration der Dockerman-Container 6. **Sprint 6:** Hardening / Secrets / Volumes / Sonderfälle ### 11.3 Regel für jede Änderung Jeder Sprint folgt demselben Schema: 1. Zielbild in diesem Dokument prüfen 2. nur den aktuellen Block anfassen 3. Compose-Datei ändern 4. deployen 5. testen 6. dokumentieren / abhaken 7. erst dann nächster Schritt ### 11.4 Source-of-Truth-Hierarchie 1. **Dieses Dokument** 2. Compose-Dateien 3. operative Checklisten / Excel 4. ad-hoc Notizen / Chat --- ## 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 --- ## ⚠️ Erweiterte Learnings (Portainer + GitOps) ### Secrets in Portainer Git-Stacks Bei Deployments über Portainer mit Git-Repositories gilt: * Host-Pfade in `env_file` (z. B. `/mnt/...`) sind **nicht verfügbar** * Portainer-Container hat keinen Zugriff auf diese Pfade #### Konsequenz * `env_file` ist für Secrets ungeeignet in diesem Setup #### Standardlösung * Verwendung von **Portainer Environment Variables** * Compose nutzt Variablen: * `POSTGRES_PASSWORD: ${VARIABLE_NAME}` 👉 Ergebnis: * keine Secrets im Git * funktionierender Git-Deployment-Flow --- ### Umgang mit `_FILE` Variablen Nicht alle Container unterstützen `_FILE`-basierte Secrets. #### Übersicht * Vaultwarden → unterstützt `_FILE` * PostgreSQL → unterstützt `_FILE` * Mealie → unterstützt `_FILE` **nicht** #### Regel * Wenn `_FILE` nicht unterstützt wird: → Nutzung von Environment Variables über Portainer --- ### Netzwerk-Standard für Apps mit Datenbanken #### Architektur-Regel * App → `frontend_net` + internes Netzwerk * Datenbank → nur internes Netzwerk (`internal: true`) #### Beispiel (Mealie) * `mealie` → `frontend_net` + `mealie_internal` * `mealie-postgres` → nur `mealie_internal` 👉 Vorteil: * Datenbank vollständig isoliert * keine externe Erreichbarkeit möglich --- ### Migrations-Standard für kritische Services Bei Änderungen an Datenbanken oder Core-Services: #### Vorgehen 1. Backup erstellen (`pg_dumpall`) 2. aktuellen Zustand sichern (`docker inspect`) 3. neue Compose in Git definieren 4. Container stoppen & entfernen 5. neuen Stack deployen 6. Funktion prüfen (Logs + abhängige Services) #### Grundsatz * Daten liegen im Volume → bleiben erhalten * Container sind austauschbar 👉 Ziel: * risikoarme Migration ohne Datenverlust ## Mail-Archiver Netzwerk-Design Der mail-archiver Service benötigt Zugriff auf zwei unterschiedliche Netzwerkbereiche: ### backend_net - Verbindung zur PostgreSQL-Datenbank (postgresql17) - rein interne Kommunikation ### frontend_net - erforderlich für externe Verbindungen: - IMAP (z. B. GMX, Gmail) - DNS-Auflösung - Internetzugriff allgemein ### Begründung Ein ausschließlich internes Netzwerk (backend_net) ist für mail-archiver nicht ausreichend, da der Service aktiv E-Mails von externen Mailservern abruft. Durch die zusätzliche Anbindung an frontend_net wird: - externer Mail-Zugriff ermöglicht - gleichzeitig bleibt die Datenbank isoliert im backend_net ### Fazit mail-archiver ist kein reiner Backend-Service, sondern ein hybrider Dienst: → benötigt sowohl interne als auch externe Netzwerkzugriffe ## 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 alle Web-UIs, `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, keine produktiven `bridge`-Container mehr.