Komodo ist der zentrale Container-Manager für beide Hosts. Löste im Juli 2026 Portainer (Server auf Hetzner + Edge Agent auf Mimir) und Watchtower ab.

Topologie

                 Hetzner-VPS (Schaugarten)              Mimir / DS220+ (Gewaechshaus)
   ┌───────────────────────────────────────┐        ┌──────────────────────────────┐
   │  Komodo Core  +  FerretDB / Postgres   │        │                              │
   │  (Web-UI, DB, orchestriert alles)      │◄───────┤  Komodo Periphery (OUTBOUND) │
   │            ▲                           │  wss   │  dialt raus zur Core          │
   │            │ ws://core:9120 (intern)   │        │  – kein offener Port, kein VPN│
   │  Komodo Periphery (lokal)              │        └──────────────────────────────┘
   └───────────────────────────────────────┘
  • Core läuft auf dem Hetzner-VPS – Web-UI + Datenbank (FerretDB auf Postgres, kein MongoDB wegen SSPL-Lizenz). Erreichbar hinter NPM (TLS).
  • Periphery = der Agent pro Host. Auf Hetzner lokal (verbindet intern zu Core), auf Mimir im Outbound-Mode: die NAS dialt raus zur Core – exakt wie früher der Portainer Edge Agent, nur ohne offenen Port und ohne Polling-Overhead.

Ressourcentypen

TypWofürBeispiele
Stack (UI Defined)Compose-Stacks mit Named Volumes / absoluten Pfadenimmich, paperless, gitea, monitoring
Stack (Files on Host)Compose mit relativen Pfaden / build: / .env – läuft in-place aus dem Original-OrdnerTrading-Stacks, npm, plausible, authentik
DeploymentEinzelcontainer (docker run-Äquivalent)prometheus, jellyfin, ntfy, ns/bind
BuildImage aus Git bauen → Gitea-Registry → deployen (ersetzt Drone für den Container)tally, inventar
RepoGit-Repo klonen + on_pull-Befehl auf dem Server ausführen (ersetzt Drone für Static-Sites, ohne Image)digitalgarden (Quartz-Build → NPM-Webroot)

Bewusst NICHT von Komodo verwaltet

Der „Bootstrap-Layer” – Komponenten, deren Job es ist, Komodo selbst zu betreiben oder zu exponieren:

  • Die Periphery-Agenten selbst (Henne-Ei: ein Agent, der sich über sich selbst neu deployt, sägt am eigenen Ast).
  • NPM auf Hetzner – frontet die Core-UI. Wird per CLI (/opt/npm) gepflegt, nicht über Komodo (sonst sperrt ein Fehl-Deploy dich aus deinem eigenen Werkzeug aus). NPM auf Mimir ist unkritisch (frontet Core nicht) → dort adoptiert.
  • drone-runner (auf beiden Hosts) – Teil der Drone-CI-Infra.

Lessons Learned (teuer bezahlt)

  • Nie :latest für stateful Stacks. Ein unkontrollierter paperless-Sprung 3.0.0 → 3.0.1 hat die DB-Migrations-Historie zerlegt (Issue #13241) – Fix nur per manuellem INSERT in django_migrations. Seither alle Image-Tags gepinnt, Watchtower abgeschaltet. Updates laufen kontrolliert über Komodo.
  • Files on Host statt UI Defined, sobald ein Compose relative Pfade (./data), build: . oder eine .env daneben nutzt – sonst zeigen die Pfade in Komodos leeres Stack-Verzeichnis → Datenverlust. Voraussetzung: die Periphery muss die Ordner sehen (Mimir-Periphery mountet dafür /volume1/docker breit).
  • Ordner-.env lädt automatisch, solange Komodos environment-Feld leer bleibt. Sobald man es füllt, übergibt Komodo --env-file und überstimmt die Ordner-.env.
  • project_name muss zum laufenden Compose-Projekt passen (docker compose ls), sonst legt Komodo neue leere Volumes an statt zu adoptieren.
  • Komodo sucht per Default compose.yamlfile_paths auf den echten Dateinamen setzen.
  • Cutover bei Einzelcontainern: alten Container erst stop+rm (Ports/Namen freigeben), dann das Deployment hoch. Bei anonymen Volumes kein rm -v (löscht die Daten).
  • DSM Container Manager auf Mimir ist deprecated – zeigt migrierte Projekte noch an, aber Wahrheit ist ab jetzt Komodo. Dort keine „Aktion” mehr auslösen.
  • Container, die NPM per Namen proxied, müssen ins proxy-Netz. Wird ein Deployment versehentlich auf bridge gesetzt (statt proxy), kann nginx den Upstream nicht auflösen → der nächste nginx-Reload/-Restart lässt die gesamte NPM-Config fallen (alle Hosts tot). Port-Mappings (z.B. 22:2222 für den SSH-Tarpit) funktionieren dabei unabhängig vom Netz — die brauchen kein Host-Network.
  • NPM nie neu starten, solange docker exec <npm> nginx -t nicht sauber ist. Der letzte gute Zustand läuft nur bis zum Restart; scheitert der Config-Test, kommt danach nichts mehr hoch. Notfall-Fix ohne UI: docker network connect proxy <container> + nginx -s reload.

Update-Strategie

Kein „alles pinnen” (Meldungs-Flut) und kein „alles auto-updaten” (paperless-3.0.1-Risiko), sondern zwei Gruppen:

Gruppe A — pinnen + beobachten (die 5 migrations-schweren DB-Apps): paperless, immich, gitea, authentik, plausible.

  • App-Image exakt gepinnt, DB/Infra-Images auf Major-Pin (postgres:17, redis:8-alpine → sichere Patches, kein Major-Sprung).
  • Komodo Auto-Update aus. Neue Releases meldet WUD (bzw. RSS für authentik) → bewusst updaten, mit Blick in die Release-Notes.
  • immich-Sonderfall: immich-server und immich-machine-learning immer auf dieselbe Version pinnen (driften sonst auseinander).

Gruppe B — Auto-Update (zustandslose/unkritische Drittanbieter): adguard, audiobookshelf, grafana, grimmory, jellyfin, prometheus, homepage, ntfy, pairdrop, privateBin, stirling-pdf, monitoring.

  • Rollender Tag + Auto Update an. Die „Global Auto Update”-Procedure redeployt nachts (03:00) still.

Bewusst manuell (weder Gruppe A noch B): npm (Proxy-Ausfall-Risiko), ns/bind (DNS-Ausfall + :latest-Config-Falle), homeassistant (Migrationen). Eigene Apps (tally, inventar, dyndns, Trading-Agents) laufen über Komodo Build/Repo — Update = git push.

Benachrichtigungen (ntfy, Topic komodo)

  • Betriebs-Alerts (Stack unhealthy, Build/Deploy/Procedure failed, Server unreachable): Komodos nativer ntfy-Alerter. Auth per Basic-Auth in der URL: https://komodo:<pw>@ntfy.host/komodo (Token-Weg hat einen Bug #576).
    • Alerter-Typ-Whitelist gefiltert: Update-Typen, Container State Change und Schedule Run raus — sonst Dauerfeuer bei jedem Redeploy/Auto-Update. Nur echtes Betriebs-Zeug (Stack State Change, Failed-*, Unreachable, CPU/Disk/Mem).
  • Versions-Updates der Gruppe-A-Apps: WUD als Deployment pro Host (lokaler Socket), Trigger WUD_TRIGGER_NTFY_* → dasselbe ntfy.
    • WUD_WATCHER_LOCAL_WATCHBYDEFAULT=false + Label wud.watch=true nur an die 4 semver-Apps (paperless, immich, gitea, plausible). WUD_WATCHER_LOCAL_CRON=0 6 * * * (täglich, sonst ghcr-429).
    • authentik-Ausnahme: CalVer (2025.12.3) → WUD scheitert („No tags found”). Läuft stattdessen als Komodo Repo + geschedulte Procedure (07:00), die den GitHub-releases.atom prüft und bei neuer Version an ntfy pusht.
  • WUD-UI (Hetzner) hinter Authentik Forward Auth. Komodos poll_for_updates bleibt aus (WUD macht das).

Betriebs-Lehren NPM ↔ Komodo

  • NPM-proxied Container müssen ins proxy-Netz. Auf bridge → nginx kann den Upstream nicht auflösen → nächster Reload kippt die ganze NPM-Config. Betraf tarpit + stirling-pdf nach der Migration (Deployments waren auf bridge statt proxy).
  • NPM nie neu starten, solange docker exec <npm> nginx -t nicht sauber ist — der letzte gute Zustand läuft nur bis zum Restart. Notfall ohne UI: docker network connect proxy <container> + nginx -s reload.
  • Forward-Auth-Host im NPM-Snippet muss auf den aktuellen Container-Namen zeigen (authentik-server-1:9000) — bei Adoption ändern sich Container-Namen.
  • NPM-Forward-Port ≠ App-Port kostet 502 (plausible lauscht auf 8080, nicht 8000).

Migration

Vollständig durchgezogen Juli 2026: erst Mimir, dann Hetzner. Portainer auf beiden Hosts abgeschaltet, portainer_data-Volume als Fallback noch kurz aufgehoben. Anschließend die eigenen Drone-Pipelines auf Komodo (Builds/Repos) migriert — Drone-Infra bleibt für künftige/fremde Repos.