Files
homelab-infra/HOMELAB_ARCHITECTURE_MASTER_V2.md
T

26 KiB
Raw Blame History

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-03-26 | Aktueller Sprint: 4 (Frontend-Stack) — Sprints 13 abgeschlossen


Inhaltsverzeichnis

  1. Systemüberblick
  2. Architektur-Prinzipien
  3. Finales Netzwerk-Zielbild
  4. Zugangsmodell: Traefik vs. Tailscale
  5. Globale Sicherheitsregeln
  6. Einordnungsschema für neue Container
  7. Container-Zielbild (vollständig)
  8. Traefik-Label-Standard
  9. Migrationsstrategie (Blöcke AF)
  10. Bekannte Ausnahmen und Begründungen
  11. Projektorganisation und Arbeitsmodus
  12. Nutzung mit KI / Kontext-Regel
  13. Betriebserfahrungen und Entscheidungs-Log

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 Portainer Stacks (Web-Editor oder Git)
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 finale direkte Host-Ports außer traefik selbst.
Begründete Ausnahmen: gitea-SSH (Port 222), 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_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

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 als Portainer Environment Variables mit ${VARIABLE} in der Compose.
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_mealie_internal bridge, internal: true internes Netz nur für mealie + mealie-postgres umgesetzt
immich_default Compose-intern internes Immich-Netz internal: true noch setzen
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, gotify)
         ├── Admin-UIs mit Middleware (portainer, dozzle, uptime-kuma, dashdot, filebrowser, scrutiny, code-server)
         └── Hybrid-Dienste mit Internetbedarf (mail-archiver, ddns-updater)

backend_net (internal: true)
   ├── postgresql17
   ├── Redis
   ├── mail-archiver
   └── paperless-ngx

App-interne Netze
   ├── mealie_mealie_internal (internal: true) ✅
   └── immich_default (internal: true ausstehend) ⏳

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
  • mail-archiver
  • backrest

4.2 Nicht öffentlich / nur Tailscale oder Traefik + Middleware

Diese Dienste sind keine Public Apps:

  • PortainerCE
  • Dozzle
  • UptimeKuma
  • dashdot
  • filebrowser
  • scrutiny
  • luckyBackup
  • code-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 oder Portainer Environment Variables mit ${VAR}
  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?

  • Jafrontend_net
  • Nein → weiter zu Schritt 2

Schritt 2 — Braucht der Dienst externe Internetverbindungen?

  • Jafrontend_net (auch ohne Web-UI — z.B. ddns-updater, mail-archiver)
  • 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
    • keiner direkten Portfreigabe
    • Tailscale-only-Charakter

Schritt 6 — Braucht der Dienst Host-/Discovery-/L2-Sicht?

  • Jahost nur mit dokumentierter Begründung
  • Nein → kein host

Schritt 7 — Braucht die App ein eigenes internes App-Netz?

  • Ja → Compose-internes Netz mit internal: true
  • Nein → kein weiteres Netz anlegen

Kurzregel

  • UIfrontend_net
  • Externer Internetzugriff nötigfrontend_net (auch ohne UI)
  • DB/Cachebackend_net
  • Spezialfall → app-internes Netz
  • Host-Zugriff → nur dokumentierte Ausnahme

7. Container-Zielbild (vollständig)

Legende Status:

  • = umgesetzt
  • = 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 frontend_net intern bleibt in frontend_net — braucht Internetzugang für Cloudflare DNS Dokumentierte Ausnahme, kein backend_net wegen internal: true
Tailscale-Docker host VPN-Zugang Host-Sonderfall, restart: unless-stopped gesetzt TS_USERSPACE/privileged später prüfen
binhex-official-pihole host LAN DNS / intern Host-Sonderfall, restart: unless-stopped gesetzt
unbound dns_net intern Resolver bleibt isoliert
backrest frontend_net, backend_net Traefik traefik.docker.network=frontend_net korrigiert Breite Mounts straffen (Block F)
diun frontend_net intern in frontend_net, gotify via Container-Name erreichbar

7.2 Sicherheit / Identity

Container Status Soll-Netz(e) Finaler Zugang Finaler Sollzustand Offene Punkte
vaultwarden frontend_net Traefik kein Host-Port, Secret-Datei (ADMIN_TOKEN_FILE)

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 statt anonym
mealie-postgres mealie_mealie_internal intern isoliert, nie frontend_net
immich_postgres immich_default intern intern-only immich_defaultinternal: true ausstehend
immich_redis immich_default intern intern-only anonymes Volume → named volume

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
Paperless-AI frontend_net Traefik aktiv
mealie frontend_net, mealie_mealie_internal Traefik sauber getrennte App/DB-Struktur
gotify frontend_net Traefik aktiv via gotify.kaleschke.info, kein Host-Port
gitea frontend_net Traefik + SSH Web via Traefik, SSH-Port 222 bleibt
immich_server immich_default, frontend_net Traefik aktiv via immich.kaleschke.info immich_defaultinternal: true ausstehend
immich_machine_learning immich_default intern bleibt intern

7.5 Admin / Operations

Container Status Soll-Netz(e) Finaler Zugang Finaler Sollzustand Offene Punkte
code-server frontend_net Traefik + Middleware PASSWORD_FILE aktiv
PortainerCE frontend_net Traefik + Middleware keine Host-Ports
Dozzle frontend_net Traefik + Middleware keine Host-Ports
filebrowser frontend_net Traefik + Middleware aktiv via files.kaleschke.info Breite Mounts einschränken (Block F)
luckyBackup frontend_net Traefik + Middleware noch in bridge aus bridge; Port entfernen
mail-archiver frontend_net, backend_net Traefik aktiv via mail.kaleschke.info, kein Host-Port

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, kein Host-Port
dashdot frontend_net Traefik + Middleware aktiv, kein Host-Port
Glances host Tailscale-only Host-Metriken
netdata host Tailscale-only Host-Metriken leere CLAIM-Vars entfernen
scrutiny frontend_net Traefik + Middleware aktiv via scrutiny.kaleschke.info, Git-Stack privileged später prüfen ob reduzierbar
netalertx host Tailscale-only Host-/Netzsicht

7.7 Entfernte Container

Container Entfernt am Begründung
scanopy-server 2026-03-26 nicht aktiv genutzt, durch paperless-ngx ersetzt
scanopy-postgres 2026-03-26 zusammen mit scanopy entfernt
scanopy-daemon 2026-03-26 zusammen mit scanopy entfernt

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 für Admin-Dienste

  - traefik.http.routers.<name>.middlewares=dashboard-auth@file,secure-headers@file

Regeln

  • traefik.docker.network immer explizit auf frontend_net — nie auf backend_net oder anderen Netzen!
  • keine yourdomain.tld-Platzhalter
  • certresolver immer le
  • tls=true immer explizit setzen — ohne diese Zeile kein TLS
  • wenn Traefik aktiv ist, werden direkte Host-Ports entfernt
  • Admin-Dienste niemals ohne Middleware veröffentlichen

9. Migrationsstrategie (Blöcke AF)

Letzte Aktualisierung: 2026-03-26

Block A — Quick Wins ABGESCHLOSSEN

[x] restart: unless-stopped für alle Container gesetzt
[x] vaultwarden ADMIN_TOKEN-Doppelpräfix korrigiert
[x] backrest DNS-Hardcoding entfernt
[x] diun ↔ gotify Erreichbarkeit hergestellt
[x] leere Netzwerke entfernt: br0, immich_net, kopia_default, netbox_default, diun_default
[x] anonyme/verwaiste Volumes bereinigt (9 anonyme + immich_model-cache alt)
[x] scanopy komplett entfernt (3 Container + 2 Volumes + Netz)

Block B — Kritische Kernmigrationen ABGESCHLOSSEN

[x] vaultwarden
    - aus bridge, in frontend_net
    - Host-Port entfernt
    - ADMIN_TOKEN_FILE aktiv
    - Traefik aktiv

[x] postgresql17
    - Port 5432 entfernt
    - nur backend_net
    - POSTGRES_PASSWORD_FILE aktiv

[x] diun
    - frontend_net beigetreten
    - gotify via Container-Name (http://gotify:80) erreichbar
    - Token via Portainer ENV

[x] mealie-postgres
    - aus frontend_net raus
    - nur mealie_mealie_internal

Block C — Frontend-Stack finalisieren

[x] gotify
    - traefik.enable=true
    - gotify.kaleschke.info
    - Port entfernt

[x] paperless-ngx
    - traefik.enable=true
    - paperless.kaleschke.info
    - Port entfernt
    - tls=true ergänzt

[x] Paperless-AI
    - traefik.enable=true
    - aktiv

[x] PortainerCE
    - traefik.enable=true
    - Middleware aktiv
    - direkte Ports entfernt

[x] Dozzle
    - traefik.enable=true
    - Middleware aktiv
    - direkte Ports entfernt

[x] dashdot
    - traefik.enable=true
    - Middleware aktiv
    - direkte Ports entfernt

[x] UptimeKuma
    - traefik.enable=true
    - uptime.kaleschke.info
    - Port entfernt
    - Middleware aktiv

[x] filebrowser
    - aus bridge → frontend_net
    - traefik.enable=true
    - files.kaleschke.info
    - Port entfernt
    - Middleware aktiv

[x] scrutiny
    - aus bridge → frontend_net
    - traefik.enable=true
    - scrutiny.kaleschke.info
    - Ports entfernt
    - Middleware aktiv
    - als Git-Stack migriert

[x] gitea
    - traefik.enable=true
    - git.kaleschke.info
    - SSH-Port 222 bleibt (Ausnahme dokumentiert)

[x] backrest
    - traefik.docker.network=frontend_net korrigiert (war backend_net — Routing-Bug)

[ ] luckyBackup
    - aus bridge → frontend_net
    - traefik.enable=true
    - Middleware
    - Port entfernen

[ ] theme-park
    - nur wenn wirklich benötigt veröffentlichen
    - direkte Ports 80/443 entfernen

Block D — Bridge-/Dockerman-Container in Compose

[x] vaultwarden ✅
[x] postgresql17 ✅
[x] mail-archiver ✅
[x] scrutiny ✅ (Git-Stack)
[x] filebrowser ✅
[ ] luckyBackup
[ ] Stash
[ ] Tailscale-Docker
[ ] netdata
[ ] Plex-Media-Server
[ ] binhex-official-pihole

Block E — Secrets-Migration

[x] vaultwarden       → ADMIN_TOKEN_FILE ✅
[x] postgresql17      → POSTGRES_PASSWORD_FILE ✅
[x] mail-archiver     → Portainer ENV (${MAILARCHIVER_AUTH_PASSWORD}) ✅
[x] mealie            → Portainer ENV (kein _FILE-Support) ✅
[x] mealie-postgres   → Portainer ENV (kein _FILE-Support) ✅
[x] gotify            → GOTIFY_DEFAULTUSER_PASS_FILE ✅
[x] diun              → GOTIFY_TOKEN via Portainer ENV ✅
[x] paperless-ngx     → Portainer ENV (${PAPERLESS_DBPASS}) ✅
[x] code-server       → PASSWORD_FILE ✅
[x] immich_server     → Portainer ENV (${IMMICH_DB_PASSWORD}) ✅
[x] immich_postgres   → POSTGRES_PASSWORD_FILE ✅
[ ] immich_redis      → anonymes Volume → named volume
[ ] luckyBackup       → Secrets prüfen

Block F — Feinschliff / Hardening

[ ] immich_default
    - internal: true setzen (kurzer Downtime nötig)

[ ] immich_redis
    - anonymes Volume → named volume in Compose

[ ] immich_server
    - anonymes Volume prüfen und benennen

[ ] backrest
    - /mnt/user doppelt gemountet (einmal ro, einmal rw)
    - rw-Mount auf konkrete Pfade einschränken

[ ] filebrowser
    - /mnt/user:/srv ist sehr breit
    - auf /mnt/user/documents:/srv einschränken wenn möglich

[ ] 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 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
scrutiny privileged: true SMART-Datenzugriff auf Laufwerke
PortainerCE Docker-Socket nicht dogmatisch :ro Management-UI; Schreiboperationen können nötig sein
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 Internetzugang für Cloudflare-API; backend_net ist internal: true
mail-archiver frontend_net + backend_net braucht Internetzugang für IMAP-Abruf (GMX, Gmail) und DB-Zugang

11. Projektorganisation und Arbeitsmodus

11.1 Unser Arbeitsprinzip

Dieses Projekt wird blockweise umgesetzt, nicht wild containerweise.

11.2 Reihenfolge der Umsetzung

Sprint Inhalt Status
Sprint 1 Quick Wins + vaultwarden Abgeschlossen
Sprint 2 postgresql17 + diun/gotify Abgeschlossen
Sprint 3 mealie / mealie-postgres + mail-archiver Abgeschlossen
Sprint 4 Frontend-Stack (paperless, Portainer, Dozzle, dashdot, scrutiny, filebrowser, gitea, UptimeKuma) 🔄 In Bearbeitung
Sprint 5 Compose-Migration der Dockerman-Container (luckyBackup, Stash, Tailscale, netdata, Plex, Pi-hole) Offen
Sprint 6 Hardening / Secrets / Volumes / Sonderfälle (immich_default, Volumes, Mounts) Offen

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
  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

13. Betriebserfahrungen und Entscheidungs-Log

Secrets in Portainer Stacks

Bei Deployments über Portainer gilt:

  • Host-Pfade in env_file (z.B. /mnt/...) sind nicht verfügbar — Portainer-Container hat keinen Zugriff
  • env_file ist für Secrets ungeeignet in diesem Setup

Standardlösung: Portainer Environment Variables + ${VARIABLE_NAME} in der Compose

POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

→ kein Secret im Git, funktionierender Deployment-Flow


Umgang mit _FILE Variablen

Nicht alle Container unterstützen _FILE-basierte Secrets:

Container _FILE Support
Vaultwarden ja
PostgreSQL ja
Gotify ja (GOTIFY_DEFAULTUSER_PASS_FILE)
code-server ja (PASSWORD_FILE)
Mealie nein → Portainer ENV
diun nein für Token → Portainer ENV
paperless-ngx nein für DB-Pass → Portainer ENV

Regel: Wenn _FILE nicht unterstützt wird → Portainer Environment Variable


diun — Korrekte Konfiguration (v4.x)

Wichtige Learnings aus der Migration:

  • DIUN_NOTIFY_GOTIFY=true existiert nicht — diese Variable gibt es in v4 nicht, führt zu field not found Fehler
  • DIUN_NOTIF_GOTIFY_TOKEN_FILE wird nicht unterstützt — Token muss direkt gesetzt werden
  • Gotify ist automatisch aktiv wenn DIUN_NOTIF_GOTIFY_ENDPOINT und DIUN_NOTIF_GOTIFY_TOKEN gesetzt sind
  • DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=true nötig damit alle Container überwacht werden (sonst nur Container mit diun.enable=true Label)

Korrekte Minimal-Konfiguration:

environment:
  - DIUN_PROVIDERS_DOCKER=true
  - DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=true
  - DIUN_NOTIF_GOTIFY_ENDPOINT=http://gotify:80
  - DIUN_NOTIF_GOTIFY_TOKEN=${GOTIFY_TOKEN}   # via Portainer ENV

ddns-updater — Netz-Ausnahme

ddns-updater hat keine Web-UI, würde laut Schema in backend_net gehören — bleibt aber bewusst in frontend_net.

Begründung: backend_net ist internal: true → kein Internetzugang. ddns-updater muss die Cloudflare-API erreichen. frontend_net ist hier die einzig funktionierende Option.

→ Dokumentierte Ausnahme in Kapitel 10.


Netzwerk-Standard für Apps mit Datenbanken

  • App → frontend_net + internes Netzwerk
  • Datenbank → nur internes Netzwerk (internal: true)

Beispiel (Mealie):

  • mealiefrontend_net + mealie_mealie_internal
  • mealie-postgres → nur mealie_mealie_internal

→ Datenbank vollständig isoliert, keine externe Erreichbarkeit möglich


Migrations-Standard für kritische Services

Bei Änderungen an Datenbanken oder Core-Services:

  1. Backup erstellen (pg_dumpall)
  2. aktuellen Zustand sichern (docker inspect)
  3. neue Compose in Git/Portainer definieren
  4. Container stoppen & entfernen
  5. neuen Stack deployen
  6. Funktion prüfen (Logs + abhängige Services)

→ Daten liegen im Volume und bleiben erhalten — Container sind austauschbar


mail-archiver — Hybrid-Dienst

mail-archiver benötigt beide Netze:

  • backend_net → Verbindung zu postgresql17
  • frontend_net → IMAP-Abruf von externen Mailservern (GMX, Gmail) + DNS-Auflösung

→ Kein reiner Backend-Dienst, sondern Hybrid mit externem Internetzugriff


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 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, keine produktiven bridge-Container mehr.