Watchtower vs. Diun — Docker Container Updates auf Debian 13 automatisieren

Docker-Container-Updates richtig automatisieren: Watchtower für Auto-Updates oder Diun für Benachrichtigungen. Vergleich, Setup und Strategie für sicheres Patch-Management.

Docker-Container-Updates richtig automatisieren: Watchtower für Auto-Updates oder Diun für Benachrichtigungen. Vergleich, Setup und Strategie für sicheres Patch-Management.

💡 Hinweis: Dieses Tutorial setzt voraus, dass du Docker auf Debian 13 installiert hast und mehrere Container betreibst. Ein Discord- oder Telegram-Webhook wird empfohlen — Setup zeigen wir.

Einleitung — Warum automatisierte Container-Updates?

Wer Self-Hosting betreibt, kennt das Problem: Pro Container ein Repository, pro Update ein docker compose pull. Bei zwanzig Containern wird das schnell zur Pflicht-Übung — oder wird vergessen, was schlimmer ist. Veraltete Container sind ein Top-Sicherheitsrisiko: Ein ungepatcher Vaultwarden, eine alte Nextcloud-Version mit bekannten CVEs, ein veraltetes Authentik mit Auth-Bypass — alles realistische Szenarien.

Es gibt zwei sinnvolle Ansätze, um das in den Griff zu kriegen:

  • Watchtower — Updates automatisch installieren, ohne dass ihr eingreift
  • Diun — Benachrichtigung bei verfügbaren Updates, manuelles Update bleibt euer Job

Beide haben ihre Daseinsberechtigung. Wir zeigen beide Setups und am Ende, wie ihr sie sinnvoll kombiniert.

Watchtower vs. Diun — Direktvergleich

FeatureWatchtowerDiun
Auto-UpdateJaNein
BenachrichtigungJaJa (Hauptzweck)
Pre-Update-BackupManuell konfigurierbarNicht relevant
Selektives UpdatePer LabelPer Label
Image-Registry-SupportDocker Hub, GHCR, etc.Docker Hub, GHCR, etc.
KonfigurationCompose + Env VarsYAML-Konfigfile
RollbackNein (Tag-Pinning manuell)n.v.
Beste Wahl fürHomelab ohne Downtime-RisikoProduktion mit Audit-Pflicht

⚠️ Wichtig: Auto-Update klingt verlockend, ist aber für kritische Production-Setups riskant. Eine breaking Change in einem Major-Update kann eure Cloud, Authentication oder Datenbank zerlegen. Für Vaultwarden, Authentik und Nextcloud empfehlen wir Diun-Notifications + manuelles Update statt Watchtower-Auto-Update.


Variante A: Watchtower (Auto-Update)

Watchtower überwacht laufende Container, vergleicht ihre Image-Hashes mit den Registry-Versionen und führt bei Updates automatisch docker pull + recreate aus.

Schritt 1: Watchtower mit Discord-Notifications

sudo mkdir -p /opt/watchtower
sudo nano /opt/watchtower/docker-compose.yml

Inhalt:

services:
  watchtower:
    image: containrrr/watchtower:latest
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /etc/localtime:/etc/localtime:ro
    environment:
      # Nur Container mit dem Label "com.centurylinklabs.watchtower.enable=true" updaten
      WATCHTOWER_LABEL_ENABLE: "true"

      # Updates jeden Tag um 4:00 Uhr (Cron-Format mit Sekunden)
      WATCHTOWER_SCHEDULE: "0 0 4 * * *"

      # Alte Images aufräumen
      WATCHTOWER_CLEANUP: "true"

      # Rolling Updates statt alle gleichzeitig
      WATCHTOWER_ROLLING_RESTART: "true"

      # Discord-Notifications
      WATCHTOWER_NOTIFICATIONS: shoutrrr
      WATCHTOWER_NOTIFICATION_URL: "discord://EUER_DISCORD_WEBHOOK_TOKEN@EURE_CHANNEL_ID"
      WATCHTOWER_NOTIFICATIONS_LEVEL: info

      # Format der Nachrichten
      WATCHTOWER_NOTIFICATION_TEMPLATE: |
        {{- if .Report -}}
        {{- with .Report -}}
        {{ len .Updated }}/{{ len .Scanned }} updated.
        {{- range .Updated }}
        - {{ .Name }} ({{ .ImageName }}): {{ .CurrentImageID.ShortID }} → {{ .LatestImageID.ShortID }}
        {{- end }}
        {{- end }}
        {{- end }}

Schritt 2: Discord-Webhook konfigurieren

Das Format der WATCHTOWER_NOTIFICATION_URL ist:

discord://TOKEN@CHANNEL_ID

Den Wert bekommt ihr aus der Discord-Webhook-URL:

https://discord.com/api/webhooks/CHANNEL_ID/TOKEN

Für Telegram:

telegram://BOT_TOKEN@telegram?chats=CHAT_ID

Für E-Mail:

smtp://user:password@smtp.example.com:587/?fromAddress=from@example.com&toAddresses=to@example.com

Eine vollständige Liste der unterstützten Notification-Provider findet ihr im Shoutrrr-Projekt.

Schritt 3: Container, die geupdatet werden sollen, markieren

Nur Container mit dem Label com.centurylinklabs.watchtower.enable=true werden geupdatet. Beispiel:

services:
  whoami:
    image: traefik/whoami
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

Schritt 4: Watchtower starten

cd /opt/watchtower
sudo docker compose up -d
sudo docker logs -f watchtower

Bei Watchtower 1.x.x und Scheduling first run: ... läuft alles.

Geschafft! Watchtower überwacht eure Container und updatet sie nachts automatisch. Discord bekommt nach jedem Lauf einen Status-Report.

Sofortiges Update auslösen — manuell

sudo docker exec watchtower /watchtower --run-once --label-enable

Variante B: Diun (Notification only)

Diun macht kein automatisches Update — es schickt nur eine Benachrichtigung, wenn ein Container-Image eine neuere Version hat. Ihr entscheidet, wann ihr updatet.

Schritt 1: Verzeichnisstruktur

sudo mkdir -p /opt/diun/data
sudo nano /opt/diun/diun.yml

Schritt 2: Diun-Konfiguration

db:
  path: /data/diun.db

watch:
  workers: 10
  schedule: "0 */6 * * *"   # alle 6 Stunden prüfen
  jitter: 30s
  firstCheckNotif: <strong>false</strong>

providers:
  docker:
    watchByDefault: <strong>false</strong>   # nur Container mit Label "diun.enable=true"
    watchStopped: <strong>false</strong>

notif:
  discord:
    webhookURL: "https://discord.com/api/webhooks/CHANNEL_ID/TOKEN"
    mentions:
      - "@everyone"
    renderFields: <strong>true</strong>
    timeout: 10s

Schritt 3: docker-compose.yml

sudo nano /opt/diun/docker-compose.yml

Inhalt:

services:
  diun:
    image: ghcr.io/crazy-max/diun:latest
    container_name: diun
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/data
      - ./diun.yml:/diun.yml:ro
    environment:
      TZ: "Europe/Berlin"
      LOG_LEVEL: info
    command: serve --config /diun.yml

Schritt 4: Container, die überwacht werden sollen, markieren

services:
  vaultwarden:
    image: vaultwarden/server:latest
    labels:
      - "diun.enable=true"

Schritt 5: Diun starten

cd /opt/diun
sudo docker compose up -d
sudo docker logs -f diun

Beim ersten Lauf indiziert Diun alle markierten Container. Sobald ein Update verfügbar ist, kommt eine Discord-Nachricht.

💡 Tipp: Wenn ihr Diun das erste Mal startet und nicht für jeden bestehenden Container eine Nachricht wollt, lasst firstCheckNotif: false aktiv. Dann bekommt ihr nur Notifications für echte zukünftige Updates.


Variante C: Die Kombination — empfohlene Strategie

Die meisten Self-Hoster brauchen einen Mittelweg:

  • Unkritische Container (Tools, Test-Setups, Development) → Watchtower-Auto-Update
  • Kritische Container (Datenbanken, Authentication, Cloud) → Diun-Notification + manuelles Update

So baut ihr beides parallel:

In den Labels jedes Containers entscheidet ihr, welcher Mechanismus greift:

services:
  # Auto-Update via Watchtower
  whoami:
    image: traefik/whoami
    labels:
      - "com.centurylinklabs.watchtower.enable=true"

  # Notification-only via Diun
  authentik-server:
    image: ghcr.io/goauthentik/server:2025.10
    labels:
      - "diun.enable=true"
      # Kein Watchtower-Label — Watchtower lässt diesen Container in Ruhe

Beide Tools laufen parallel, jedes prüft nur seine eigenen markierten Container.

💡 Empfehlung: Aus Erfahrung — pinnt kritische Container immer auf eine konkrete Major.Minor-Version (z.B. authentik:2025.10 statt authentik:latest). Damit greift Auto-Update nur für Patch-Releases, nicht für Major-Updates mit potenziellen Breaking Changes.


Schritt 6: Pre-Update-Backups (für Watchtower)

Watchtower kann vor jedem Update ein Lifecycle-Hook ausführen — perfekt für ein Quick-Backup.

In den Labels eines Containers:

labels:
  - "com.centurylinklabs.watchtower.enable=true"
  - "com.centurylinklabs.watchtower.lifecycle.pre-update=/backup.sh"
  - "com.centurylinklabs.watchtower.lifecycle.post-update=/cleanup.sh"

Im Container muss /backup.sh ausführbar sein. Beispiel-Script:

#!/bin/bash
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
mysqldump --single-transaction nextcloud | gzip > /backups/pre-update-$TIMESTAMP.sql.gz

⚠️ Best Practice: Pre-Update-Hooks sind besonders bei Datenbanken Gold wert. Falls ein Update fehlschlägt, habt ihr immer einen frischen Snapshot, mit dem ihr in Sekunden zurückrollen könnt.


Schritt 7: Tag-Strategie verstehen

Die meisten Update-Probleme kommen aus falschen Tags:

TagVerhaltenEmpfehlung
:latestImmer neueste Version, auch Major-UpdatesNur für unkritische Container
:1Höchste Version 1.x.xMittel-Risiko
:1.2Höchste Version 1.2.xEmpfohlen für kritische Apps
:1.2.3Genau diese VersionMaximale Stabilität, manuelle Updates nötig

Beispiele:

# Riskant: Watchtower würde 2.x → 3.x mitnehmen
image: postgres:latest

# Sicher: Watchtower bleibt bei Postgres 16, holt aber Patches (16.1 → 16.2 → 16.3)
image: postgres:16

# Maximal sicher: Keine Updates ohne explizite Änderung
image: postgres:16.4-alpine

💡 Tipp: Für Datenbanken (PostgreSQL, MariaDB, MongoDB) immer auf Major.Minor pinnen. Ein automatischer Sprung von postgres:15 auf postgres:16 würde eure DB beim ersten Restart in einen inkompatiblen State bringen.


Zusammenfassung & Checkliste

SchrittStatus
Discord/Telegram-Webhook eingerichtet
Watchtower oder Diun installiert
Notification-Test erfolgreich
Container mit Labels markiert
Tags auf Major.Minor gepinnt (kritische Apps)
Pre-Update-Backup-Hook (optional)
Test-Update durchgeführt
Update-Strategie dokumentiert

Troubleshooting

Watchtower updatet nicht

  • Container hat das Label com.centurylinklabs.watchtower.enable=true?
  • Watchtower läuft mit WATCHTOWER_LABEL_ENABLE=true?
  • Schedule-Format korrekt? Watchtower nutzt 6-Felder-Cron (mit Sekunden!)
  • Logs prüfen: sudo docker logs watchtower

Diun sendet keine Notifications

  • webhookURL korrekt? Test: curl -X POST -H "Content-Type: application/json" -d '{"content":"test"}' EURE_WEBHOOK_URL
  • firstCheckNotif: false aktiv? Dann gibt es bei der ersten Run keine Nachricht
  • Nur ein Container markiert? Diun loggt das beim Start

Watchtower startet Container, aber App ist kaputt

  • Tag auf :latest und Major-Update kam?
  • Container braucht Migration-Step? Manche Apps (z.B. Nextcloud) brauchen occ upgrade nach Image-Update
  • Lösung: Auf Major.Minor pinnen oder zu Diun wechseln

„no space left on device“

  • Watchtower-WATCHTOWER_CLEANUP=true aktiv? Räumt alte Images auf
  • Manuell: sudo docker system prune -a (Vorsicht — auch ungenutzte Volumes weg, falls --volumes)

Image kann nicht gepullt werden — Authentication

Bei privaten Registries:

volumes:
  - /home/youruser/.docker/config.json:/config.json

Watchtower / Diun nutzen diese Credentials dann automatisch.


Nächste Schritte

  • Backup-Strategie mit restic — Pre-Update-Backups in S3
  • Renovate Bot — Image-Tags in Compose-Files automatisch aktualisieren (Pull-Request-basiert)
  • Komodo / Portainer — Container-Management mit Update-Approval-Workflow
  • Trivy / Grype Image-Scanning — CVEs in Images vor Deployment finden

Habt ihr Fragen oder Probleme? Schreibt es in die Kommentare — ich helfe gerne!

Kommentar hinterlassen