Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Docker 01.06.2026 · 10 min Lesezeit

WUD statt Watchtower: Docker-Container automatisch aktualisieren

Watchtower ist eingestellt. Diese Anleitung richtet WUD (What's Up Docker) 9.4.1 per Docker Compose ein: Opt-in per Label, automatische Updates für freigegebene Stacks, Benachrichtigungen, Schutz für Datenbanken und Umstieg von Watchtower.

Geprüft am 14.10.2026 · für WUD 9.4.1

Mit KI erstellt – redaktionelle Prüfung ausstehend

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Hero-Grafik mit der Überschrift Docker-Container automatisch aktualisieren, WUD statt Watchtower, mit Container-Dashboard und Update-Pfeilen

Watchtower war jahrelang die bequemste Lösung, um Docker-Container automatisch zu aktualisieren. Das Projekt containrrr/watchtower ist inzwischen eingestellt: Das GitHub-Repository ist archiviert, das letzte Release 1.7.1 stammt von 2023. Als Ersatz beschreibt diese Anleitung WUD (What's Up Docker). WUD erkennt neue Image-Versionen, zeigt sie in einer Weboberfläche an, benachrichtigt Sie und aktualisiert auf Wunsch genau die Container, die Sie freigeben. Wer noch Watchtower betreibt, findet in Schritt 1 und Schritt 7 den Umstieg.

Voraussetzungen

  • Linux-Server oder Mini-PC mit Docker Engine und Compose-Plugin, x86_64 oder ARM64 (das Image gibt es für beide Architekturen)
  • Ressourcen: WUD selbst belegte im Test rund 85 MB RAM; 1 CPU-Kern und 512 MB freier RAM reichen neben Ihren Diensten, das Image braucht rund 560 MB Platz
  • Root- oder sudo-Zugriff, denn WUD braucht den Docker-Socket /var/run/docker.sock
  • Ihre Stacks liegen in einem gemeinsamen Ordner, in dieser Anleitung /opt/stacks/NAME/compose.yaml
  • Für Benachrichtigungen ein ntfy-Server oder ein anderer Kanal (Telegram, E-Mail, Gotify)
EckdatenWert
Imagegetwud/wud:9.4.1 (alternativ ghcr.io/getwud/wud:9.4.1)
Port3000 (Weboberfläche und API)
Volumes/var/run/docker.sock, ./store:/store, /opt/stacks:/opt/stacks
Wichtige VariablenWUD_AUTH_ADMIN_USER, WUD_AUTH_ADMIN_PASSWORD, WUD_WATCHER_LOCAL_*, WUD_TRIGGER_*

Schritt 1: Watchtower entfernen

Laufen Watchtower und WUD gleichzeitig, greifen zwei Werkzeuge auf dieselben Container zu. Entfernen Sie Watchtower deshalb zuerst. Lag Watchtower in einem eigenen Compose-Projekt, beenden Sie es dort:

cd /opt/watchtower
docker compose down
# oder bei einem per docker run gestarteten Container:
docker rm -f watchtower
docker image rm containrrr/watchtower:latest

Es gibt einen zweiten Grund, nicht zu warten: Im Test auf Docker Engine 29.8 startete containrrr/watchtower:latest (Version 1.7.1) gar nicht mehr. Das Log meldete client version 1.25 is too old. Minimum supported API version is 1.40, danach brach der Prozess mit einem Panic ab. Auf aktuellen Docker-Versionen aktualisiert Watchtower also nichts mehr, auch wenn der Container in alten Compose-Dateien noch steht.

Verifizieren: docker ps -a --filter name=watchtower gibt keine Zeile mehr aus.

Schritt 2: Projektordner und compose.yaml anlegen

Legen Sie einen Ordner für WUD an und darin eine Datei .env mit dem Administratorpasswort. Ein Doppelpunkt im Passwort ist laut Dokumentation nicht erlaubt.

sudo mkdir -p /opt/wud && cd /opt/wud
echo "WUD_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d ':/+=')" | sudo tee .env
sudo chmod 600 .env

Die compose.yaml:

services:
  wud:
    image: getwud/wud:9.4.1
    container_name: wud
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./store:/store
      - /opt/stacks:/opt/stacks
    environment:
      - TZ=Europe/Berlin
      - WUD_AUTH_ADMIN_USER=admin
      - WUD_AUTH_ADMIN_PASSWORD=${WUD_ADMIN_PASSWORD}
      # Opt-in: nur Container mit wud.watch=true
      - WUD_WATCHER_LOCAL_WATCHBYDEFAULT=false
      - WUD_WATCHER_LOCAL_CRON=0 4 * * *
      # Automatische Updates für Compose-Stacks, nur nach Freigabe
      - WUD_TRIGGER_DOCKERCOMPOSE_STACKS_INCLUDEBYDEFAULT=false
      - WUD_TRIGGER_DOCKERCOMPOSE_STACKS_BACKUP=true
      - WUD_TRIGGER_DOCKERCOMPOSE_STACKS_PRUNE=true
      # Benachrichtigung für alle überwachten Container
      - WUD_TRIGGER_NTFY_INFO_URL=https://ntfy.example.de
      - WUD_TRIGGER_NTFY_INFO_TOPIC=docker-updates
    labels:
      - wud.watch=true
      - wud.trigger.exclude=dockercompose.stacks

Die wichtigsten Punkte: Ohne WUD_WATCHER_LOCAL_WATCHBYDEFAULT=false überwacht WUD wie früher Watchtower jeden Container. Der Cron-Ausdruck legt die tägliche Prüfung auf 4 Uhr. Der Ordner /opt/stacks wird unter demselben Pfad eingebunden, denn der Compose-Trigger liest den Pfad der compose.yaml aus den Labels, die Docker Compose an jeden Container hängt. WUD überwacht sich selbst, aktualisiert sich aber nicht selbst; das erledigen Sie bewusst per Hand.

Verifizieren: docker compose config --quiet gibt nichts aus, die Datei ist also gültig, und cat .env zeigt ein Passwort ohne Doppelpunkt.

Schritt 3: WUD starten und anmelden

docker compose up -d
docker compose logs wud | grep -E "starting|watched|listening"

Im Test meldete das Log WUD is starting (version = 9.4.1), Server listening on port 3000 und nach dem ersten Lauf Cron finished (3 containers watched, 0 errors, 2 available updates). Beim ersten Start prüft WUD sofort, danach nach Zeitplan. Das Passwort legt WUD gehasht in der SQLite-Datenbank unter ./store ab; dieser Ordner gehört ins Backup.

Öffnen Sie http://SERVER-IP:3000 und melden Sie sich als admin an. Die Startseite zeigt Container, Trigger, Watcher und Registries im Überblick.

Startseite der WUD-Weboberfläche mit vier Containern, drei Triggern, einem Watcher und dem Hinweis auf zwei verfügbare Updates
Die Startseite von WUD 9.4.1 nach dem ersten Lauf: zwei Updates gefunden, drei Trigger aktiv.

Ohne Anmeldung ist auch die API gesperrt. Das prüfen Sie direkt auf dem Server:

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/health
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3000/api/containers
curl -s -o /dev/null -w "%{http_code}\n" -u "admin:$(grep -oP '(?<==).*' .env)" http://localhost:3000/api/containers

Verifizieren: docker compose ps zeigt wud als healthy. Die drei curl-Aufrufe liefern im Test 200, 401 und 200; mit falschem Passwort ebenfalls 401. Stellen Sie Port 3000 nicht ungeschützt ins Internet, sondern nutzen Sie VPN oder einen Reverse Proxy mit HTTPS.

Schritt 4: Container per Label freigeben

WUD arbeitet mit zwei Bausteinen: Der Watcher findet neue Versionen, ein Trigger handelt (benachrichtigen oder aktualisieren). Welche Container überwacht werden und welche Trigger für sie gelten, steuern Sie per Label in der compose.yaml des jeweiligen Stacks. Ein Beispiel mit Webserver und Datenbank in /opt/stacks/app/compose.yaml:

services:
  web:
    image: nginx:1.27.0-alpine
    labels:
      - wud.watch=true
      - wud.tag.include=^1\.27\.\d+-alpine$$
      - wud.trigger.include=dockercompose.stacks
  db:
    image: postgres:16.4-alpine
    labels:
      - wud.watch=true
      - wud.tag.include=^16\.\d+-alpine$$

wud.tag.include ist ein regulärer Ausdruck für die erlaubten Tags. So bleibt nginx bei 1.27.x und PostgreSQL in Major-Version 16. Das doppelte $$ ist Pflicht, sonst hält Docker Compose das Dollarzeichen für eine Variable. Container ohne Label ignoriert WUD; im Test tauchte ein dritter Container ohne Label nicht in der Liste auf. Einen Ad-hoc-Lauf starten Sie in der Containerliste mit WATCH NOW.

Containerliste in WUD: einzeln und app-db-1 mit verfügbarer neuer Version, app-web-1 und wud als aktuell markiert
Containerliste: Für einzeln und app-db-1 liegen neuere Tags vor, Container ohne Label erscheinen nicht.

Verifizieren: Unter Containers stehen nur Ihre markierten Container. Im Test erkannte WUD für postgres:16.4-alpine das neuere 16.15-alpine und ordnete das Update als minor ein.

Schritt 5: Automatische Updates per Trigger

Der Trigger dockercompose.stacks aus Schritt 2 gilt wegen INCLUDEBYDEFAULT=false nur für Container mit wud.trigger.include=dockercompose.stacks. Findet WUD für einen solchen Container einen passenden Tag, zieht es das Image, ersetzt den Container und schreibt den neuen Tag in die compose.yaml. Mit BACKUP=true bleibt die alte Fassung als compose.yaml.back liegen, PRUNE=true löscht das alte Image.

Im Test lief genau das direkt nach dem Start: nginx:1.27.0-alpine wurde auf 1.27.5-alpine gehoben, nicht auf eine neuere 1.29, weil der Tag-Filter greift. Das Log zeigt die Kette Pull image nginx:1.27.5-alpine, recreated on new image with success und Image nginx:1.27.0-alpine removed with success.

Für Container, die per docker run gestartet wurden, gibt es den Docker-Trigger. Ergänzen Sie dafür in der WUD-compose.yaml:

      - WUD_TRIGGER_DOCKER_EINZELN_INCLUDEBYDEFAULT=false
      - WUD_TRIGGER_DOCKER_EINZELN_PRUNE=true

und starten Sie den Container mit --label wud.watch=true --label wud.trigger.include=docker.einzeln. Updates lassen sich auch von Hand anstoßen: In der Containerliste das Menü am Zeilenende öffnen, Update container wählen und mit UPDATE bestätigen.

Dialog Update container in WUD für den Container einzeln von v1.10.0 auf v1.12.0 über den Trigger docker einzeln
Manuelles Update in WUD: Container einzeln von v1.10.0 auf v1.12.0 über den Docker-Trigger.

Verifizieren: docker ps zeigt den Container mit dem neuen Tag, diff compose.yaml.back compose.yaml im Stack-Ordner zeigt nur die geänderte image-Zeile. Im Test lief der Container danach mit traefik/whoami:v1.12.0, die compose.yaml enthielt nginx:1.27.5-alpine.

Schritt 6: Benachrichtigungen und Datenbanken absichern

Der ntfy-Trigger ntfy.info hat kein INCLUDEBYDEFAULT=false und meldet deshalb die Funde aller überwachten Container, die kein wud.trigger.include tragen. Das Label wud.trigger.include wirkt laut Dokumentation als ausschließliche Liste: Der nginx-Container aus Schritt 4 bekommt damit nur den Compose-Trigger und keine ntfy-Meldung. Soll ntfy auch für automatisch aktualisierte Container melden, ersetzen Sie dort das Label durch wud.trigger.dockercompose.stacks.enabled=true; diese Einzelfreigabe lässt die übrigen Trigger unberührt. Im Test kam auf dem Topic die Nachricht Container app-db-1 running with tag 16.4-alpine can be updated to tag 16.15-alpine an. Wie Sie einen eigenen ntfy-Server aufsetzen, zeigt ntfy mit Docker installieren. Für Telegram heißen die Variablen WUD_TRIGGER_TELEGRAM_NAME_BOTTOKEN und WUD_TRIGGER_TELEGRAM_NAME_CHATID.

Datenbanken bekommen bewusst kein wud.trigger.include. Ein automatischer Sprung auf eine neue Major-Version von PostgreSQL oder MariaDB kann das Datenverzeichnis unbrauchbar machen. Sichern Sie vor jedem Datenbank-Update, siehe MySQL- und PostgreSQL-Backup automatisieren, und aktualisieren Sie per Hand mit docker compose pull db && docker compose up -d db.

Detailansicht des Datenbank-Containers app-db-1 in WUD, im Reiter Triggers ist nur der Benachrichtigungs-Trigger Ntfy Info zugeordnet
Der Datenbank-Container hat nur den Benachrichtigungs-Trigger, ein automatisches Update ist nicht zugeordnet.

Verifizieren: Ein Klick auf den Datenbank-Container und den Reiter Triggers zeigt nur Ntfy Info. Im Test blieb postgres:16.4-alpine unverändert, obwohl 16.15 bereitstand.

Schritt 7: Watchtower-Labels und Einstellungen umstellen

Watchtower arbeitete standardmäßig nach dem Prinzip „alles aktualisieren, Ausnahmen markieren“, WUD in dieser Anleitung umgekehrt. Übertragen Sie Ihre alten Einstellungen so:

WatchtowerWUD
com.centurylinklabs.watchtower.enable=truewud.watch=true plus wud.trigger.include=dockercompose.stacks
com.centurylinklabs.watchtower.enable=falsekein Label (mit WATCHBYDEFAULT=false)
nur melden (--monitor-only)wud.watch=true ohne Update-Trigger
WATCHTOWER_SCHEDULE, WATCHTOWER_POLL_INTERVALWUD_WATCHER_LOCAL_CRON
WATCHTOWER_CLEANUP=trueWUD_TRIGGER_..._PRUNE=true
WATCHTOWER_NOTIFICATION_URLeigener Trigger je Kanal (ntfy, Telegram, SMTP)

Alte com.centurylinklabs.watchtower.*-Labels stören WUD nicht; im Test trug der nginx-Container noch das alte Label und wurde nur nach den WUD-Labels behandelt. Entfernen Sie sie trotzdem beim nächsten Bearbeiten, damit die Dateien eindeutig bleiben. Nach jeder Label-Änderung den Stack mit docker compose up -d neu erstellen, sonst sieht WUD die alten Labels.

Verifizieren: grep -rl centurylinklabs /opt/stacks findet nach dem Aufräumen keine Datei mehr, und die WUD-Containerliste zeigt dieselben Container, die vorher Watchtower aktualisiert hat.

Troubleshooting

  • Compose-Trigger tut nichts, Log meldet Compose file /opt/stacks/... does not exist: Der Stack-Ordner ist nicht oder unter einem anderen Pfad in WUD eingebunden. Im Test provoziert: Ohne Mount blieb der Container auf dem alten Tag. Pfad im Container identisch zum Host einbinden.
  • Warnung unable to delete ... (must be forced) beim Prune: Ein anderer Container nutzt das alte Image noch. Das Update selbst war erfolgreich; das Image bleibt, bis es niemand mehr verwendet.
  • API liefert 401: Falscher Benutzer oder Passwort mit Doppelpunkt. Passwort in .env ändern, docker compose up -d; WUD übernimmt es beim Start (Ensuring administrator role and updating credentials).
  • WUD überwacht alle Container: WUD_WATCHER_LOCAL_WATCHBYDEFAULT=false fehlt.
  • Tag-Filter wirkt nicht: In der compose.yaml fehlt das doppelte $$ am Ende des Ausdrucks.
  • Neuer Container erscheint nicht: In der Containerliste WATCH NOW klicken oder bis zum nächsten Cron-Lauf warten.

Häufige Fragen

Kann ich Watchtower einfach weiterlaufen lassen?

Nein. Das Original bekommt keine Updates mehr und startete im Test auf Docker Engine 29 nicht, weil es eine zu alte Docker-API anspricht.

Aktualisiert WUD sich selbst?

Nur, wenn Sie WUD_TRIGGER_DOCKER_NAME_SELFUPDATE=true setzen. In dieser Anleitung ist WUD vom Update-Trigger ausgenommen; Sie aktualisieren mit docker compose pull && docker compose up -d im Ordner /opt/wud.

Beim Wechsel von WUD 9.3.0 auf 9.4.1 sichern Sie zuerst den Store-Ordner und die Compose-Datei. Ändern Sie anschließend den Image-Tag und führen Sie docker compose pull wud sowie docker compose up -d wud aus. Version 9.4.1 enthält unter anderem Korrekturen für Container-Neuerstellung mit Docker 29 und für parallele Updates desselben Compose-Projekts. Im Praxistest antwortete der Healthcheck nach dem Upgrade und nach einer Neuinstallation mit HTTP 200; die Container-API lieferte ohne Anmeldung HTTP 401 und mit dem Administratorkonto HTTP 200. Neue Registry-Webhooks müssen Sie für diesen Updateweg nicht aktivieren.

Braucht WUD eine Datenbank?

Nein. Benutzer, Sitzungen und Zustand liegen in ./store/wud.sqlite. Sichern Sie den Ordner zusammen mit der compose.yaml und der .env.

Was ist mit Containern auf :latest?

Ohne Versionsnummer kann WUD nur den Digest vergleichen (Label wud.watch.digest=true). Besser sind feste Tags wie 1.27.5-alpine, dann sehen Sie in Meldungen, was sich ändert.

Fazit

WUD ersetzt Watchtower und ist dabei vorsichtiger: Es überwacht nur freigegebene Container, aktualisiert nur dort, wo Sie einen Trigger zuordnen, und hält Tag-Sprünge per Regex im Rahmen. Im Test erkannte WUD 9.4.1 veraltete Tags zuverlässig, hob einen Compose-Stack samt compose.yaml an, aktualisierte einen Einzelcontainer per Klick und meldete die Datenbank nur. Der Preis dafür sind ein paar Labels pro Stack und der Mount des Stack-Ordners.

Weiterführende Anleitungen und Quellen