*Stand: November 2026

Komodo ist eine Weboberfläche für Docker. Du legst darin Stacks an, bearbeitest Compose-Dateien und Konfigurationswerte im Browser, liest Protokolle mit und siehst, welcher Container wie viel Speicher und Prozessorzeit belegt. Komodo ersetzt Docker nicht, es steuert es – auf einem Server oder auf mehreren aus derselben Oberfläche.

In dieser Reihe ist Komodo ab jetzt der Weg, auf dem jede weitere Anwendung auf den VPS kommt. Der Artikel baut auf Docker mit den beiden Netzen aus Artikel 03 und auf Tailscale aus Artikel 05 auf: Komodo ist ausschließlich über das VPN erreichbar – kein offener Port, keine Domain, kein Anmeldeformular im Internet.

Neu in der Reihe? Hier geht's los
Hardware & Setup dieser Serie

Am Ende hast du

  • Komodo Core + Periphery installiert (mit Postgres + FerretDB)
  • Web-Oberfläche erreichbar unter http://vps:9120 – nur über Tailscale
  • Admin-Account angelegt, Registrierung wieder geschlossen
  • Core und Periphery verbunden – über automatisch ausgetauschte Schlüssel, ohne manuell verwaltete Secrets
  • Die Variablen DOCKER_ROOT und DATA_ROOT angelegt
  • Einen Test-Stack über die Komodo-UI ausgerollt und wieder entfernt
  • Komodos tägliche Sicherung der eigenen Datenbank in einem Verzeichnis, das mitgesichert wird
  • Verstanden, warum genau dieser eine Stack von Hand entsteht und alle folgenden nicht

Voraussetzungen

  • Artikel 02–05 abgeschlossen
  • Tailscale läuft auf Server und lokalem Rechner, ssh vps geht über das VPN
  • docker compose funktioniert als Benutzer martin ohne sudo
  • homelab_net und homelab_intern existieren (aus Artikel 03)
  • Die Tailscale-Adresse deines Servers, notiert in Artikel 05 – wir holen sie gleich noch einmal

Getestet mit: Debian 13 · Docker Engine 29.9.3 · Komodo 2.3.4 · FerretDB

Zuletzt durchgespielt: November 2026

1. Was Komodo dir gibt

Im Einzelnen:

  • Alle Container auf einen Blick mit CPU-, RAM- und Status-Anzeige
  • Logs in Echtzeit im Browser, ohne docker logs -f im Terminal
  • Compose-Dateien direkt in der UI editieren, mit Syntax-Highlighting
  • Stacks ausrollen, neu starten, stoppen per Mausklick
  • Update-Erkennung für Container-Images
  • Mehrere Server verwalten aus einem Dashboard (über Periphery-Agents auf jedem Host)
  • Meldungen bei Problemen oder Updates – als Push-Nachricht aufs Handy

Core und Periphery

Komodo besteht aus zwei Bausteinen:

Komponente Wofür?
Komodo Core Die Web-UI, die du im Browser aufrufst. Speichert Stack-Definitionen, Logins, History.
Komodo Periphery Ein Agent, der auf jedem verwalteten Server läuft und dort tatsächlich die docker-Befehle ausführt.

Auf einem einzelnen Server laufen beide auf demselben Gerät, getrennt nur durch das interne Docker-Netz. Kommt später ein zweiter Server dazu, installierst du dort nur Periphery – Core bleibt einmal zentral.

Im fertigen Stack laufen am Ende vier Container: Komodo Core, Komodo Periphery, Postgres (mit DocumentDB-Extension) und FerretDB als MongoDB-Adapter dazwischen.

Authentifizierung zwischen Core und Periphery

Core und Periphery authentifizieren sich über automatisch erzeugte Schlüsselpaare (Ed25519). Du musst kein Geheimnis selbst generieren und in Config-Dateien synchron halten:

  1. Beim ersten Start erzeugen Core und Periphery jeweils ihr eigenes Schlüsselpaar in einem geteilten Docker-Volume.
  2. In der .env weisen wir beide an, den Public Key des jeweils anderen direkt aus diesem Volume zu lesen.
  3. Ab da läuft die gegenseitige Authentifizierung über die ausgetauschten Public Keys – ohne manuellen Eingriff.

Für einen zweiten Server gibt es zusätzlich einen Onboarding-Key, mit dem sich dessen Periphery beim bestehenden Core anmeldet. Für einen einzelnen Server brauchst du ihn nicht.

⚠️ Was du Komodo damit gibst

Periphery bekommt Zugriff auf den Docker-Steuerkanal des Servers (/var/run/docker.sock). Ein Container mit diesem Zugriff kann faktisch alles auf dem Host tun – Container starten, Verzeichnisse einbinden, Rechte ausweiten. Das ist bei jeder Docker-Verwaltungsoberfläche so, egal welche.

Genau deshalb steht Komodo hinter dem VPN und nicht hinter einem Anmeldeformular im Internet. Halt dich an diese Regel, auch wenn dir später eine bequemere Variante begegnet.

2. Zugriff: ausschließlich über Tailscale

Komodo darf alle Container auf deinem Server starten, stoppen, löschen. Das bedeutet: kein öffentliches Login-Formular, kein offener Port im Internet, keine Domain. Die Oberfläche ist nur über das Tailscale-VPN erreichbar – genau dafür haben wir es im letzten Artikel eingerichtet.

Wir binden Komodos Port 9120 deshalb gezielt an die Tailscale-Adresse deines Servers. Docker veröffentlicht den Port dann nur auf diesem Interface, nicht auf 0.0.0.0. Damit umgehen wir auch das aus Artikel 03, Abschnitt 7 bekannte Problem, dass Docker veröffentlichte Ports an UFW vorbei in die Firewall einträgt: Wenn der Port erst gar nicht auf der öffentlichen IP gebunden wird, kommt da auch nichts an.

Tailscale-Adresse ermitteln:

tailscale ip -4

Check

Ausgabe: Eine Adresse aus dem Bereich 100.x.x.x – dieselbe, die du in Artikel 05 notiert hast. Du trägst sie gleich zweimal in die .env-Datei ein.

3. Stack-Verzeichnis anlegen

Ab dem nächsten Artikel legt Komodo die Verzeichnisse seiner Stacks selbst an. Für Komodo selbst geht das nicht – es kann sich nicht selbst ausrollen. Dieser eine Stack entsteht deshalb von Hand, im Muster aus Artikel 03:

mkdir -p /srv/docker/stacks/komodo
cd /srv/docker/stacks/komodo

Die Daten-Verzeichnisse für Postgres und FerretDB legt Docker beim ersten Start selbst als benannte Volumes an.

4. Secrets generieren

Komodo nutzt Schlüsselpaare für die Core-Periphery-Authentifizierung (siehe Abschnitt 1) – das spart einige Geheimnisse, die du sonst selbst pflegen müsstest. Was bleibt, sind drei Werte:

echo "DB Passwort:      $(openssl rand -hex 24)"
echo "JWT Secret:       $(openssl rand -hex 32)"
echo "Webhook Secret:   $(openssl rand -hex 24)"

Das Ergebnis sind drei Zeichenketten. Kopiere sie in deinen Passwort-Manager. Du brauchst sie gleich in der .env-Datei und noch einmal, falls du den Stack neu aufsetzt.

Warum hexadezimal?

openssl rand -hex erzeugt nur Ziffern und die Buchstaben a bis f. Damit kann keiner der Werte etwas kaputtmachen: Das Datenbank-Passwort landet in einer Verbindungsadresse der Form mongodb://user:PASSWORT@host, in der +, / und = eine eigene Bedeutung haben, und ab Artikel 07 stehen Geheimnisse in Konfigurationswerten, in denen $ eine eigene Bedeutung hat. Ein Zeichensatz für alle Werte erspart dir die Frage, welcher wo hingehört.

⚠️ Niemals Sample-Werte aus Tutorials oder dieser Anleitung übernehmen

Jeder Generator-Aufruf erzeugt frische Zufallswerte. Wenn du Secrets aus Beispielen oder einer öffentlichen Doku übernimmst, sind sie aus Sicherheits­sicht wertlos – sie sind ja öffentlich. Generiere immer eigene.

5. .env-Datei erstellen

Komodo nutzt eine .env-Datei zur Konfiguration. Lege sie an:

nano /srv/docker/stacks/komodo/.env

Inhalt (Platzhalter <...> durch deine echten Werte ersetzen – inklusive der eben generierten Secrets und deiner Tailscale-Adresse):

####################################
# 🦎 KOMODO - KONFIGURATION        #
####################################

# Image-Version
COMPOSE_KOMODO_IMAGE_TAG=2

# Wo Komodo später erreichbar ist (für Webhook-URLs, Anzeige)
KOMODO_HOST=http://<TAILSCALE-IP>:9120
KOMODO_TITLE=Komodo

# Port-Bindung: Komodo nur über Tailscale erreichbar
TAILSCALE_IP=<TAILSCALE-IP>

# Postgres / FerretDB Zugangsdaten
KOMODO_DATABASE_USERNAME=komodo
KOMODO_DATABASE_PASSWORD=<DB-PASSWORT-AUS-OPENSSL-HEX>

# Krypto-Secrets
KOMODO_JWT_SECRET=<JWT-SECRET-AUS-OPENSSL>
KOMODO_WEBHOOK_SECRET=<WEBHOOK-SECRET-AUS-OPENSSL>

# Auth-Verhalten
KOMODO_LOCAL_AUTH=true
KOMODO_DISABLE_USER_REGISTRATION=false
KOMODO_DISABLE_NON_ADMIN_CREATE=false
KOMODO_TRANSPARENT_MODE=false
KOMODO_JWT_TTL="1-day"

# Monitoring-Intervalle
KOMODO_MONITORING_INTERVAL="15-sec"
KOMODO_RESOURCE_POLL_INTERVAL="5-min"

# Anmeldung über fremde Dienste aus
KOMODO_OIDC_ENABLED=false
KOMODO_GITHUB_OAUTH_ENABLED=false
KOMODO_GOOGLE_OAUTH_ENABLED=false

# Lokalen Server automatisch beim ersten Start anlegen
KOMODO_FIRST_SERVER_NAME=vps

# Schlüsseltausch: Core und Periphery lesen sich gegenseitig
# automatisch aus dem geteilten keys-Volume
KOMODO_PERIPHERY_PUBLIC_KEY=file:/config/keys/periphery.pub

# Periphery
PERIPHERY_CORE_ADDRESS=ws://core:9120
PERIPHERY_CONNECT_AS=${KOMODO_FIRST_SERVER_NAME}
PERIPHERY_CORE_PUBLIC_KEYS=file:/config/keys/core.pub
PERIPHERY_ROOT_DIRECTORY=/srv/docker/stacks/komodo/periphery
PERIPHERY_STACK_DIR=/srv/docker/stacks

# Zeitzone
TZ=Europe/Berlin

Speichern mit Strg + X, Y, Enter.

Check

grep -n "<" /srv/docker/stacks/komodo/.env

Ausgabe: keine. Kommt eine Zeile zurück, ist dort ein Platzhalter stehen geblieben – spitze Klammern gibt es in keinem der echten Werte. Diese Prüfung ist nicht Formsache: Bei KOMODO_DATABASE_PASSWORD fällt ein Platzhalter sofort auf, weil der Stack nicht startet. Bei KOMODO_HOST startet er, und die Zeile fällt erst später auf.

Zu drei Zeilen kurz die Begründung:

KOMODO_DISABLE_USER_REGISTRATION=false erlaubt gleich das Anlegen des Admin-Accounts. Sobald das erledigt ist, drehen wir den Wert um – damit niemand sonst einen Account anlegen kann.

PERIPHERY_STACK_DIR=/srv/docker/stacks legt fest, dass alle künftigen Stacks unter /srv/docker/stacks/<n>/ landen – im Muster aus Artikel 03. Ohne diese Zeile legt Komodo sie in einem eigenen Verzeichnis irgendwo im System ab.

PERIPHERY_ROOT_DIRECTORY ist das Arbeitsverzeichnis von Periphery. Es liegt im Komodo-Ordner, damit alles, was zu Komodo gehört, an einer Stelle unter /srv/docker/stacks steht.

Wie die Authentifizierung zwischen Core und Periphery funktioniert: Beide Container teilen sich ein gemeinsames Docker-Volume namens keys. Beim ersten Start erzeugt Core dort sein Schlüsselpaar (core.key + core.pub), Periphery seins (periphery.key + periphery.pub). Die beiden Public-Key-Pfade stehen oben in der .env. Damit weiß Core, welchem Periphery er vertrauen darf, und umgekehrt. Der KOMODO_FIRST_SERVER_NAME legt beim ersten Start automatisch einen Server-Eintrag in der UI an, und Periphery verbindet sich über PERIPHERY_CONNECT_AS genau mit diesem.

Zugriffsrechte einschränken (die Datei enthält jetzt Klartext-Passwörter):

chmod 600 /srv/docker/stacks/komodo/.env

Bei den Stacks ab Artikel 07 entfällt dieser Schritt – dort schreibt Komodo die .env selbst.

6. compose.yaml erstellen

nano /srv/docker/stacks/komodo/compose.yaml

Inhalt:

name: komodo

services:
  postgres:
    image: ghcr.io/ferretdb/postgres-documentdb
    container_name: komodo-postgres
    restart: unless-stopped
    labels:
      komodo.skip: ""
    environment:
      POSTGRES_USER: ${KOMODO_DATABASE_USERNAME}
      POSTGRES_PASSWORD: ${KOMODO_DATABASE_PASSWORD}
      POSTGRES_DB: postgres
    volumes:
      - postgres-data:/var/lib/postgresql/data
    networks:
      - komodo_internal

  ferretdb:
    image: ghcr.io/ferretdb/ferretdb
    container_name: komodo-ferretdb
    restart: unless-stopped
    labels:
      komodo.skip: ""
    environment:
      FERRETDB_POSTGRESQL_URL: postgres://${KOMODO_DATABASE_USERNAME}:${KOMODO_DATABASE_PASSWORD}@postgres:5432/postgres
    depends_on:
      - postgres
    volumes:
      - ferretdb-state:/state
    networks:
      - komodo_internal

  core:
    image: ghcr.io/moghtech/komodo-core:${COMPOSE_KOMODO_IMAGE_TAG}
    container_name: komodo-core
    init: true
    restart: unless-stopped
    labels:
      komodo.skip: ""
    env_file: .env
    environment:
      KOMODO_DATABASE_ADDRESS: ferretdb:27017
    ports:
      - "${TAILSCALE_IP}:9120:9120"
    volumes:
      - keys:/config/keys
      - /srv/docker/stacks/komodo/backups:/backups
    depends_on:
      - ferretdb
    networks:
      - komodo_internal
      - homelab_net

  periphery:
    image: ghcr.io/moghtech/komodo-periphery:${COMPOSE_KOMODO_IMAGE_TAG}
    container_name: komodo-periphery
    init: true
    restart: unless-stopped
    labels:
      komodo.skip: ""
    env_file: .env
    volumes:
      - keys:/config/keys
      - /var/run/docker.sock:/var/run/docker.sock
      - /proc:/proc
      - /srv/docker/stacks:/srv/docker/stacks
    depends_on:
      - core
    networks:
      - komodo_internal

volumes:
  postgres-data:
  ferretdb-state:
  keys:

networks:
  komodo_internal:
    name: komodo_internal
  homelab_net:
    external: true

Speichern und schließen.

Was passiert hier?

Block Erklärung
name: komodo Expliziter Projektname (wie in Artikel 03 etabliert).
komodo.skip: "" Markiert alle Container, damit Komodo seinen eigenen Stack nicht stoppt oder neu ausrollt.
init: true Sorgt für sauberes Aufräumen beendeter Prozesse im Container.
postgres mit DocumentDB-Image Postgres + DocumentDB-Extension, Basis für FerretDB.
keys-Volume Speichert die automatisch erzeugten Schlüsselpaare von Core und Periphery. Es muss erhalten bleiben, sonst müssen sich beide bei jedem Neustart neu bekannt machen.
core mit ports: "${TAILSCALE_IP}:9120:9120" Port 9120 wird ausschließlich auf das Tailscale-Interface gebunden. Über die öffentliche IP des VPS ist nichts erreichbar.
core mit /backups Hierhin schreibt Komodo jede Nacht eine Sicherung seiner eigenen Datenbank. Ohne diese Zeile landen die Abzüge nur im Container und sind beim nächsten Update weg. Das Verzeichnis legt Docker beim ersten Start an.
core an beiden Netzen An komodo_internal für den Datenbankzugriff, an homelab_net für den Weg nach draußen.
periphery ohne ports: Periphery ist nur intern erreichbar – Core spricht es über den Container-Namen an.
/var/run/docker.sock Der Steuerkanal zu Docker. Ohne ihn kann Periphery nichts ausführen.
/proc Damit Periphery Prozessorlast und Speicher des Servers auslesen kann.
/srv/docker/stacks:/srv/docker/stacks Innen unter demselben Pfad wie außen. Diese Gleichheit ist wichtig: Periphery gibt Pfade an Docker weiter, und Docker liest sie als Pfade des Hosts. Über diesen einen Eintrag erreicht Periphery beides – die Verzeichnisse der Stacks und sein eigenes Arbeitsverzeichnis.
komodo_internal mit name: Ohne die Zeile hängt Compose den Projektnamen davor.

Eine bewusste Abweichung von Artikel 03: Das interne Netz bekommt hier kein internal: true. Komodo sieht regelmäßig nach, ob es neue Versionen der verwendeten Images gibt, und verschickt später Meldungen – beides braucht einen Weg nach draußen. Bei den Anwendungen der App-Artikel ist das anders: Dort wird die Datenbank abgeriegelt.

7. Stack starten

cd /srv/docker/stacks/komodo
docker compose up -d

Beim ersten Start richtet sich Postgres ein (das kann eine Minute dauern), FerretDB verbindet sich, Core kommt hoch und legt sein Schlüsselpaar an, Periphery ebenso.

Check

docker compose ps

Ausgabe: Vier Container, alle Up:

NAME               STATUS                   PORTS
komodo-core        Up 30 seconds            100.x.x.x:9120->9120/tcp
komodo-ferretdb    Up 35 seconds
komodo-periphery   Up 30 seconds
komodo-postgres    Up 1 minute

Achte auf die Portspalte bei komodo-core: Dort muss deine Tailscale-Adresse stehen, nicht 0.0.0.0.

Dass sich die beiden Teile gefunden haben, steht im Protokoll:

docker compose logs periphery | grep -i "logged in"

Ausgabe: Eine Zeile in der Art Logged in to Komodo Core core:9120 websocket as Server vps.

Eine Meldung im Protokoll, die harmlos ist: Failed to connect to websocket … Connection refused direkt beim Start. Periphery ist schneller oben als Core, versucht es alle paar Sekunden erneut, und die Erfolgsmeldung steht kurz darauf darunter.

Ein Verzeichnis periphery unter /srv/docker/stacks/komodo/ suchst du an dieser Stelle vergeblich. Periphery legt es erst an, wenn es gebraucht wird.

Wenn etwas nicht startet, zeigen die Protokolle warum:

docker compose logs postgres
docker compose logs ferretdb
docker compose logs core
docker compose logs periphery

Häufigste Ursache: ein Tippfehler in der .env-Datei oder ein Platzhalter, der stehen geblieben ist.

Wenn komodo-core in einer Restart-Schleife hängt (Restarting in docker compose ps) und das Log password must be URL encoded zeigt: Dein DB-Passwort enthält Sonderzeichen. Du hast es vermutlich mit -base64 statt -hex erzeugt. Lösung: ein neues Passwort mit openssl rand -hex 24 erzeugen, in der .env eintragen – und weil Postgres das alte Passwort bereits im Volume gespeichert hat, das Volume neu aufsetzen:

docker compose down -v
docker compose up -d

Das ist verlustfrei, solange Komodo noch nie vollständig lief – es sind ja noch keine Daten drin. Achtung: down -v löscht alle Volumes des Stacks, auch das keys-Volume. Das ist hier in Ordnung, weil Komodo die Schlüssel beim nächsten Start neu erzeugt. Bei einem laufenden Komodo wäre derselbe Befehl ein Datenverlust.

8. Erstaufruf der Web-UI

Im Browser, auf einem Gerät, das im Tailscale-Netz angemeldet ist:

http://vps:9120

Der Name kommt aus MagicDNS, eingerichtet in Artikel 05.

Hinweis zur Browser-Warnung „Nicht sicher": Du sprichst Komodo über http:// an, nicht über https:// – deshalb meldet dein Browser eine fehlende Zertifikatsabsicherung. Das ist hier kein Problem: Die Verbindung läuft durch den Tailscale-Tunnel und ist dort verschlüsselt. Caddy und HTTPS brauchen wir ab dem nächsten Artikel nur für Dienste, die übers offene Internet erreichbar sein sollen.

Falls die Seite nicht lädt, prüfe in dieser Reihenfolge:

  1. Bist du im Tailscale-Netz aktiv? tailscale status auf dem lokalen Rechner sollte den Server zeigen.
  2. docker compose ps auf dem Server – läuft komodo-core?
  3. Stimmt die Tailscale-Adresse in der .env? tailscale ip -4 auf dem Server gibt die korrekte Adresse aus.

Admin-Account anlegen

Beim ersten Aufruf erscheint ein Formular, das gleichzeitig Anmeldung und Registrierung ist – ein getrennter Registrieren-Knopf fehlt:

  1. Benutzernamen eintragen (z. B. martin)
  2. Passwort vergeben (mindestens 12 Zeichen, am besten aus deinem Passwort-Manager)
  3. Auf Sign Up klicken

Der erste Account bekommt automatisch alle Rechte. Du bist danach angemeldet.

Wenn nach dem Sign-Up nur „Komodo Log in" ohne Felder erscheint: Die UI hält Dateien hartnäckig im Zwischenspeicher. Strg + Shift + R lädt die Seite vollständig neu und löst das fast immer. Sonst hilft ein privates Browserfenster.

Registrierung schließen

Sofort danach, damit niemand sonst einen Account anlegen kann:

nano /srv/docker/stacks/komodo/.env

Diese Zeile ändern:

KOMODO_DISABLE_USER_REGISTRATION=true

Speichern, dann:

cd /srv/docker/stacks/komodo
docker compose up -d

Docker erneuert nur die Container, die es betrifft. Postgres und FerretDB laufen unverändert weiter.

Check

Im privaten Browserfenster Komodo aufrufen: Jetzt erscheint nur noch die Anmeldung, kein Sign-Up mehr.

9. Server in der UI prüfen

Du musst nichts verbinden – das ist beim ersten Start bereits passiert. Core und Periphery haben ihre Schlüssel ausgetauscht, und KOMODO_FIRST_SERVER_NAME=vps hat den Eintrag für den Server angelegt.

Im Menü auf Servers. Rechts öffnet sich die Übersicht, und darin steht eine Zeile für vps mit der Komodo-Version.

Check

Die Zeile ist grün. Damit steht die Verbindung zwischen Core und Periphery.

Ein Klick auf den Server führt zu seiner Konfiguration; die Live-Werte – Prozessorlast, Speicher, Plattenbelegung – liegen dort im Reiter Stats. Brauchen musst du beides jetzt nicht, aber du weißt, wo es steht.

Den Namen lässt du so. Core ordnet die Anmeldung des Agenten über den Namen zu: Der Eintrag in der Oberfläche muss Zeichen für Zeichen so heißen wie PERIPHERY_CONNECT_AS in der .env. Benennst du ihn später hier um, musst du die Zeile mitziehen – sonst meldet sich Periphery an, Core findet keinen passenden Eintrag, und der Server steht auf „is not connected".

10. Zwei Variablen anlegen

Bevor der erste App-Stack entsteht, legst du zwei Werte an, die Komodo später in jede Compose-Datei einsetzt. Das ist der Grund, warum die App-Artikel dieser Reihe eine Compose-Datei zeigen, die auf dem VPS und auf einer NAS gleichermaßen funktioniert: Die Pfade stehen nicht in der Datei, sondern hier.

  1. Unten links auf Settings, dann auf den Reiter Variables
  2. + New Variable, zweimal:
Name Wert
DOCKER_ROOT /srv/docker/stacks
DATA_ROOT /srv/data

Die Option Secret bleibt bei beiden aus – es sind Pfade, keine Geheimnisse.

DATA_ROOT ist der Ort für Nutzdaten, die nicht zur Container-Ebene gehören: Dokumente, Bilder, Musik. Falls das Verzeichnis noch nicht existiert:

sudo mkdir -p /srv/data
sudo chown -R $(id -un):$(id -gn) /srv/data

So werden die Werte später benutzt. In jedem App-Stack stehen im Abschnitt Environment zwei Zeilen:

DOCKER_ROOT=[[DOCKER_ROOT]]
DATA_ROOT=[[DATA_ROOT]]

Die doppelten eckigen Klammern sind Komodos Schreibweise: Beim Ausrollen ersetzt Komodo sie durch die Werte von oben und schreibt das Ergebnis in die .env neben der Compose-Datei. Die Compose-Datei selbst nutzt danach die gewohnte Docker-Schreibweise:

    volumes:
      - ${DOCKER_ROOT}/beispiel/config:/config
      - ${DATA_ROOT}/dokumente:/data

Warum dieser Umweg? Weil dadurch kein einziger App-Artikel mehr einen Pfad nennen muss. Ziehst du später um, änderst du die Variable an dieser einen Stelle statt in zwanzig Stacks. Und dieselbe Compose-Datei läuft unverändert auf einem Gerät mit ganz anderer Verzeichnisstruktur.

11. Workflow ab jetzt: Stacks über die UI

Ab diesem Punkt installierst du neue Docker-Stacks nicht mehr per SSH und docker compose up -d. Du legst sie über die Komodo-UI an, pflegst die compose.yaml direkt im Browser-Editor und rollst sie per Mausklick aus.

Die eine Ausnahme ist der Komodo-Stack selbst, weil Komodo sich nicht selbst ausrollen kann. Wenn du Komodos Konfiguration änderst oder Komodo aktualisierst, machst du das per SSH. Dafür ist das komodo.skip-Label gesetzt – Komodo lässt seinen eigenen Stack in Ruhe. Wie das Update läuft, steht in Abschnitt 13.

12. Test-Deployment: whoami über die Komodo-UI

Bevor im nächsten Artikel mit Caddy der erste echte Stack entsteht, einmal trocken durchspielen: ein winziger Test-Stack, der nichts weiter tut, als seinen eigenen Namen zu melden.

In der UI:

  1. Links auf Stacks → oben rechts + New Stack
  2. Name: test-whoami
  3. Server: vps
  4. Stack Type: UI Defined
  5. Im Bereich Compose File folgendes einfügen:
name: test-whoami

services:
whoami:
image: traefik/whoami
container_name: test-whoami
restart: unless-stopped
networks:
- homelab_intern

networks:
homelab_intern:
external: true
  1. Save – damit ist die Stack-Definition gespeichert, gestartet ist noch nichts
  2. Deploy, dann im Bestätigungsdialog Confirm

Komodo schreibt die compose.yaml auf den Server, Periphery startet den Container, und in der Übersicht erscheint test-whoami als laufend. Die Logs des Containers sind einen Klick entfernt.

Check

ls -ld /srv/docker/stacks/test-whoami
ls /srv/docker/stacks/test-whoami

Ausgabe: Ein Verzeichnis mit der compose.yaml darin. Das zeigt, dass PERIPHERY_STACK_DIR sitzt – deine Stacks landen unter /srv/docker/stacks/, nicht irgendwo im System.

Aufräumen – in zwei Schritten, und der zweite geht nur über die Übersicht:

  1. In der Ansicht des Stacks auf Destroy – stoppt und entfernt den Container
  2. Links auf Stacks zurück in die Übersicht. Dort den Stack test-whoami auswählen und auf Execute, dann Delete – das entfernt die Definition aus Komodo

Den zweiten Schritt suchst du in der Ansicht des Stacks vergeblich: Gelöscht wird eine Definition nur über die Auswahl in der Übersicht.

Das Verzeichnis auf dem Server bleibt dabei liegen. Komodo räumt es nicht mit weg – bei einer echten Anwendung stünden dort deine Daten. Beim Test-Stack ist nichts drin, also weg damit:

sudo rm -rf /srv/docker/stacks/test-whoami

Merk dir das für später. Eine gelöschte Anwendung hinterlässt ihr Verzeichnis. Wer über Monate ausprobiert und wieder verwirft, sammelt Ordner an, die zu nichts mehr gehören – und sichert sie beim Backup mit.

Du hast den kompletten Ablauf damit einmal gesehen: anlegen, ausrollen, kontrollieren, entfernen. Genau so entsteht ab dem nächsten Artikel jeder neue Stack.

13. Komodo im Alltag

Der Installationsteil ist durch. Ein paar Dinge lohnt sich zu kennen, bevor du sie das erste Mal brauchst.

Stack-Typen: drei Wege zum Compose-File

Komodo bietet drei Wege an, eine compose.yaml zu pflegen. Für diese Reihe gilt durchgängig der erste:

UI Defined – du tippst compose.yaml und Konfigurationswerte direkt im Komodo-Editor. Komodo schreibt die Dateien beim Ausrollen auf den Server (unter /srv/docker/stacks/<n>/). Kein SSH zum Editieren, alles an einer Stelle. Nachteil: keine echte Versionierung – Komodo hat eine begrenzte Änderungshistorie, aber keinen vollwertigen Vergleich.

Files on Host – Komodo liest eine compose.yaml, die schon auf dem Server liegt. Praktisch, wenn du einen bestehenden Stack übernehmen willst.

Git Repo – Komodo holt die compose.yaml aus einem Git-Repository. Damit bekommst du Versionierung und Rücksprünge auf ältere Stände. Das ist die Ausbaustufe für später und braucht ein paar Anpassungen an unserem Aufbau.

Compose File und Environment: zwei Bereiche pro Stack

In der Konfiguration eines Stacks liegen zwei Eingabebereiche untereinander. Oben Compose File, darunter Environment – und was du in Environment schreibst, legt Komodo beim Ausrollen als .env neben der Compose-Datei ab. Daher der Name.

Passwörter, Adressen und Versionsnummern stehen deshalb in Environment, in der Compose-Datei nur Verweise darauf. Das ist dasselbe Muster wie in Artikel 03 – nur dass du beide Dateien jetzt im Browser bearbeitest. In dieser Reihe heißt der Inhalt von Environment im Fließtext „die Konfigurationswerte".

Praktischer Nebeneffekt: Wenn du einen Stack kopierst („Copy Stack"), übernimmt Komodo die compose.yaml, aber nicht automatisch die Konfigurationswerte. So landen Secrets nicht ungewollt in mehreren Stacks.

Updates erkennen

Komodo prüft im Hintergrund regelmäßig, ob es für die Images in deinen Stacks eine neuere Version gibt – alle 5 Minuten, einstellbar über KOMODO_RESOURCE_POLL_INTERVAL. Findet es eine, erscheint in der Stack-Übersicht ein Hinweis.

Pro Stack gibt es dafür zwei Schalter:

  • Poll for Updates – Komodo sieht nach und meldet, du entscheidest, wann du ausrollst
  • Auto Update – Komodo zieht das neue Image und rollt den Stack selbst aus

Für jeden Stack dieser Reihe gilt: Poll for Updates an, Auto Update aus. Größere Versionssprünge können Datenbanken umbauen oder Konfigurationen ändern. Wenn das nachts von allein passiert und am Morgen läuft etwas nicht mehr, fehlt dir der Zusammenhang.

Beide Schalter stehen in derselben Konfiguration wie Compose File und Environment, und Save sichert alles zusammen.

Komodo selbst aktualisieren

Der Weg von oben gilt für alle Stacks außer einem. Komodos eigener trägt das komodo.skip-Label und bleibt von Poll for Updates ausgenommen – er wird per SSH aktualisiert, wie jede Änderung an diesem Stack:

cd /srv/docker/stacks/komodo
docker compose pull
docker compose up -d

pull holt die neuesten Abbilder zur Marke 2 aus der .env, up -d tauscht nur die Container, deren Abbild sich geändert hat. Die Volumes bleiben unberührt: Stack-Definitionen, Konten und Historie überleben das.

Check

docker compose ps
docker compose logs periphery | grep -i "logged in"

Ausgabe: Vier Container Up, und eine neue logged in-Zeile mit aktuellem Zeitstempel. Der zweite Befehl ist der wichtigere: Wird Core neu erstellt, muss Periphery ihn wiederfinden.

Die abgelösten Abbilder bleiben auf der Platte liegen. docker image prune -f entfernt die, die kein Container mehr nutzt.

Ein Sprung auf eine neue Hauptversion – von 2 auf 3 – folgt anderen Regeln. Zwischen 1.x und 2.x wechselten das Postgres-Abbild, die Authentifizierung und die Pflichtangaben in der .env. Dafür liest man zuerst die Release Notes des Projekts und sichert die Datenbank – wie, steht im nächsten Unterabschnitt. Innerhalb von 2 passiert das nicht.

Komodos eigene Sicherung

Komodo legt bei einer neuen Installation von selbst eine Prozedur namens Backup Core Database an. Sie läuft jede Nacht um 01:00 und schreibt einen Ordner mit Datum in das Verzeichnis, das du in Abschnitt 6 bei core als /backups eingehängt hast – darin je eine gepackte Datei für Stacks, Server, Variablen, Empfänger, Konten und den Rest von Komodos Konfiguration.

Zu finden ist sie links unter Procedures. Dort startest du sie auch von Hand, etwa vor einem Sprung auf eine neue Hauptversion.

Check – am Tag nach der Einrichtung:

ls /srv/docker/stacks/komodo/backups

Ausgabe: ein Ordner mit Datum und Uhrzeit im Namen.

Gesichert ist damit Komodos eigene Datenbank, nicht die Daten deiner Anwendungen – die liegen in deren Verzeichnissen. Weil das Sicherungsverzeichnis unter /srv/docker/stacks liegt, nimmt der Backup-Artikel in Phase 4 es ohne weiteren Handgriff mit nach draußen.

Meldungen

Unter Alerters in den Settings lässt sich einstellen, dass Komodo aktiv meldet: Container ausgefallen, Server nicht erreichbar, Speicher knapp, Update verfügbar.

Als Empfänger kommt keine Mailadresse in Frage. Komodo verschickt keine Mail – ein SMTP-Versand ist nicht vorgesehen, auch nicht über den Mail-Weiterleiter aus Artikel 08. Es meldet an Push- und Chatdienste: Slack, Discord, Pushover und ntfy sind eingebaut, alles andere braucht einen Zwischenbaustein.

Deshalb bleibt dieser Punkt vorerst offen. In Artikel 10 – 10. ntfy: Meldungen von VPS und NAS direkt aufs Handy – richtest du einen eigenen Meldedienst ein und trägst ihn hier als Empfänger nach. Für jetzt reicht zu wissen, wo die Einstellung sitzt.

Zwei-Faktor-Anmeldung

Komodo kann die Anmeldung mit einer Zwei-Faktor-Anmeldung (2FA) absichern, in zwei Varianten – über einen Passkey oder über eine Authenticator-App mit Zahlencode. Du findest beides oben rechts im Profil unter Account.

Der Passkey funktioniert hier nicht, und das liegt nicht an Komodo: Browser geben die dafür nötige Schnittstelle nur auf Seiten mit gültigem HTTPS frei. Komodo rufst du über http:// auf, also meldet die Oberfläche, es sei kein Anbieter verfügbar. Das ist erwartet.

Die Authenticator-App funktioniert, weil der Zahlencode auf dem Server geprüft wird. Nimm dieselbe App wie in Artikel 05.

Pflicht ist 2FA hier nicht – wer die Oberfläche erreichen will, muss ohnehin erst im Tailscale-Netz sein. Aber es kostet zwei Minuten.

Was Komodo nicht ist

Komodo verwaltet Container. Es ist kein Reverse Proxy, kein Backup-Werkzeug für deine Anwendungen und keine Benutzerverwaltung. Adressen und Zertifikate macht Caddy im nächsten Artikel, die vorgeschaltete Anmeldung Authelia in Artikel 09, Sicherungen kommen in Phase 4.

Wenn es nicht klappt

Was du siehst Ursache Weiter
komodo-core hängt auf Restarting, im Protokoll password must be URL encoded Datenbank-Passwort mit Sonderzeichen erzeugt → Abschnitt 7, Kasten
komodo-core steigt mit Exited (128) aus In der .env ist ein Platzhalter stehen geblieben, am 18.10.2026 bei KOMODO_HOST grep -n "<" → Abschnitt 5
Failed to connect to websocket … Connection refused direkt nach dem Start Harmlos – Periphery ist schneller oben als Core → Abschnitt 7
Die Seite unter http://vps:9120 lädt nicht Tailscale aus, Core gestoppt oder falsche Tailscale-Adresse in der .env → Abschnitt 8, drei Prüfungen
Nach Sign Up steht nur „Komodo Log in" ohne Felder Zwischenspeicher des Browsers Strg + Shift + R → Abschnitt 8
Der Server steht auf „is not connected" Name in der Oberfläche passt nicht zu PERIPHERY_CONNECT_AS → Abschnitt 9, Kasten
In einer .env steht [[DOCKER_ROOT]] wörtlich Variable fehlt oder ist vertippt – Komodo setzt unbekannte Namen nicht ein Schreibweise unter Settings → Variables prüfen → Abschnitt 10

Und jetzt?

Du verwaltest Docker ab hier im Browser, erreichbar nur über dein VPN. SSH brauchst du künftig fast nur noch für Änderungen an Komodo selbst, gelegentliche Fehlersuche und die Dateien, die außerhalb von Komodo gepflegt werden.

Eine davon kommt sofort. Noch ist keiner deiner Dienste öffentlich erreichbar, und Komodo bleibt das auch. Für die Anwendungen, die öffentlich sein sollen, richtest du im nächsten Artikel Caddy ein: den einen Eingang von außen, mit automatischem HTTPS. Dort lernst du auch VS Codium kennen, das sich über SSH mit dem Server verbindet – dann ist nano Vergangenheit.

👉 Nächster Artikel: 07. Caddy auf dem VPS: ein Eingang, HTTPS für jede Anwendung