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
| Typ | Wofür | Beispiele |
|---|---|---|
| Stack (UI Defined) | Compose-Stacks mit Named Volumes / absoluten Pfaden | immich, paperless, gitea, monitoring |
| Stack (Files on Host) | Compose mit relativen Pfaden / build: / .env – läuft in-place aus dem Original-Ordner | Trading-Stacks, npm, plausible, authentik |
| Deployment | Einzelcontainer (docker run-Äquivalent) | prometheus, jellyfin, ntfy, ns/bind |
| Build | Image aus Git bauen → Gitea-Registry → deployen (ersetzt Drone für den Container) | tally, inventar |
| Repo | Git-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
:latestfür stateful Stacks. Ein unkontrollierter paperless-Sprung 3.0.0 → 3.0.1 hat die DB-Migrations-Historie zerlegt (Issue #13241) – Fix nur per manuellemINSERTindjango_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.envdaneben nutzt – sonst zeigen die Pfade in Komodos leeres Stack-Verzeichnis → Datenverlust. Voraussetzung: die Periphery muss die Ordner sehen (Mimir-Periphery mountet dafür/volume1/dockerbreit). - Ordner-
.envlädt automatisch, solange Komodosenvironment-Feld leer bleibt. Sobald man es füllt, übergibt Komodo--env-fileund überstimmt die Ordner-.env. project_namemuss zum laufenden Compose-Projekt passen (docker compose ls), sonst legt Komodo neue leere Volumes an statt zu adoptieren.- Komodo sucht per Default
compose.yaml→file_pathsauf den echten Dateinamen setzen. - Cutover bei Einzelcontainern: alten Container erst
stop+rm(Ports/Namen freigeben), dann das Deployment hoch. Bei anonymen Volumes keinrm -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 aufbridgegesetzt (stattproxy), 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:2222für den SSH-Tarpit) funktionieren dabei unabhängig vom Netz — die brauchen kein Host-Network. - NPM nie neu starten, solange
docker exec <npm> nginx -tnicht 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-serverundimmich-machine-learningimmer 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 ChangeundSchedule Runraus — sonst Dauerfeuer bei jedem Redeploy/Auto-Update. Nur echtes Betriebs-Zeug (Stack State Change, Failed-*, Unreachable, CPU/Disk/Mem).
- Alerter-Typ-Whitelist gefiltert: Update-Typen,
- Versions-Updates der Gruppe-A-Apps: WUD als Deployment pro Host (lokaler Socket), Trigger
WUD_TRIGGER_NTFY_*→ dasselbe ntfy.WUD_WATCHER_LOCAL_WATCHBYDEFAULT=false+ Labelwud.watch=truenur 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.atomprüft und bei neuer Version an ntfy pusht.
- WUD-UI (Hetzner) hinter Authentik Forward Auth. Komodos
poll_for_updatesbleibt aus (WUD macht das).
Betriebs-Lehren NPM ↔ Komodo
- NPM-proxied Container müssen ins
proxy-Netz. Aufbridge→ nginx kann den Upstream nicht auflösen → nächster Reload kippt die ganze NPM-Config. Betraf tarpit + stirling-pdf nach der Migration (Deployments waren aufbridgestattproxy). - NPM nie neu starten, solange
docker exec <npm> nginx -tnicht 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.