Watchtower was doing what I needed on my Synology NAS: checking selected Docker containers for updates and reporting the results through Telegram. But after setting up What’s Up Docker (WUD), I decided to move the update workflow to a dashboard that could monitor the whole Docker estate while automatically updating only the services I approved.
This guide documents the actual migration on my DS224+ (Seido), using Portainer, four opted-in containers, a 02:00 maintenance schedule and concise Telegram notifications. It also explains an easily missed detail: an automatic WUD trigger can run as soon as an update is detected, not necessarily at your preferred maintenance time.
Why replace Watchtower with WUD?
I wanted one place to see available updates across containers, including applications I wouldn’t allow to update themselves. WUD separates its three jobs into watchers (discovery), registries (checking published images) and triggers (acting on updates). The web dashboard made the difference for me.
There is an important safety distinction: monitoring an image is not the same as automatically replacing a running container. For example, my custom Node.js services and WordPress MariaDB database should be assessed before major runtime or database upgrades.
Install WUD as a Portainer stack
This is an example of the final stack structure. The admin password and Telegram bot token are supplied as Portainer stack environment variables, not embedded in the YAML. Replace the Telegram chat variable with your own. Docker-socket access gives WUD substantial control over the host, so keep the dashboard authenticated and limited to trusted users.
services:
wud:
image: getwud/wud:latest
container_name: wud
restart: unless-stopped
ports:
- "3030:3000"
environment:
TZ: Europe/London
WUD_AUTH_ADMIN_USER: admin
WUD_AUTH_ADMIN_PASSWORD: ${WUD_ADMIN_PASSWORD}
WUD_WATCHER_LOCAL_CRON: "0 2 * * *"
WUD_WATCHER_LOCAL_JITTER: "0"
WUD_WATCHER_LOCAL_WATCHEVENTS: "false"
WUD_WATCHER_LOCAL_WATCHATSTART: "false"
WUD_TRIGGER_DOCKER_AUTOUPDATE_AUTO: "true"
WUD_TRIGGER_DOCKER_AUTOUPDATE_INCLUDEBYDEFAULT: "false"
WUD_TRIGGER_DOCKER_AUTOUPDATE_PRUNE: "false"
WUD_TRIGGER_DOCKER_AUTOUPDATE_SELFUPDATE: "false"
WUD_TRIGGER_TELEGRAM_NOTIFY_BOTTOKEN: ${TELEGRAM_BOT_TOKEN}
WUD_TRIGGER_TELEGRAM_NOTIFY_CHATID: ${TELEGRAM_CHAT_ID}
WUD_TRIGGER_TELEGRAM_NOTIFY_AUTO: "true"
WUD_TRIGGER_TELEGRAM_NOTIFY_EVENTS: "success,failure"
WUD_TRIGGER_TELEGRAM_NOTIFY_INCLUDEBYDEFAULT: "true"
WUD_TRIGGER_TELEGRAM_NOTIFY_SUCCESSTITLE: "🐳 SEIDO DOCKER UPDATE"
WUD_TRIGGER_TELEGRAM_NOTIFY_SUCCESSBODY: "✅ $${container.name} updated successfully"
WUD_TRIGGER_TELEGRAM_NOTIFY_FAILURETITLE: "🐳 SEIDO DOCKER UPDATE"
WUD_TRIGGER_TELEGRAM_NOTIFY_FAILUREBODY: "❌ $${container.name} update failed"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- wud-data:/store
volumes:
wud-data:
In Portainer, define WUD_ADMIN_PASSWORD, TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID as stack environment variables. The double dollar signs in the notification body ($${container.name}) are intentional: Compose must pass WUD’s template variable through, not interpolate it itself.
Opt in only trusted containers
With INCLUDEBYDEFAULT=false, WUD monitors all discovered containers but will not automatically update one merely because a new image is available. Add this label to an individual service’s Compose definition:
labels:
- "wud.trigger.docker.autoupdate.enabled=true"
I applied this to Homepage, Home Assistant (container installation), Cloudflared and Plex. I did not apply it to MariaDB, WordPress or the custom Node.js admin tools until I’d assessed their upgrade paths. Later I opted MariaDB in only after pinning it to an LTS release and establishing backups.
After redeploying an opted-in service, verify the label on the Synology shell:
docker inspect homepage --format '{{index .Config.Labels "wud.trigger.docker.autoupdate.enabled"}}'
The expected result is true. Note that WUD’s Docker trigger recreates containers directly; keep all configuration, bind mounts, named volumes and labels accurately recorded in Portainer stacks. A Docker-managed anonymous volume deserves particular care: before updating Plex, I discovered its /config was a generated Docker volume and explicitly retained that existing volume in the Compose file.
Why did Plex update before 02:00?
This was our first useful lesson. After I opted Plex in, WUD detected its available new image digest and updated the container during the evening. The 02:00 cron expression controlled a scheduled watcher check, but it did not inherently prohibit event- or startup-driven scans.
To avoid unintended daytime restarts, I disabled the watcher’s startup and Docker-event scans using WUD_WATCHER_LOCAL_WATCHATSTART=false and WUD_WATCHER_LOCAL_WATCHEVENTS=false. The cron job remains 0 2 * * *. This controls automatic discovery timing; a user can still initiate manual updates from the dashboard. Verify your installed WUD version’s handling of these settings, and remember that a scan-to-update workflow isn’t a transactional maintenance window or a guarantee against manually initiated changes.
Short Telegram messages instead of image hashes
The first successful Plex test produced full SHA256 digests. Technically accurate, but far more information than I wanted on my phone. WUD’s success and failure title/body templates let us reduce the result to a useful couple of lines:
🐳 SEIDO DOCKER UPDATE
✅ plex updated successfully
The failure message follows the same pattern with a cross and the container name. We tested Telegram using WUD’s trigger test, then confirmed the real Plex update also sent a message. An update that produces no change shouldn’t result in a nightly Telegram spam report when subscriptions are restricted to success,failure.
Verify the setup
docker logs --tail 60 wud
docker ps --filter name=plex
docker inspect plex --format '{{range .Mounts}}{{println .Name " -> " .Destination}}{{end}}'
Look for the watcher registering the 02:00 cron schedule, the Docker and Telegram triggers registering, and no configuration errors. After an actual update, confirm the service starts and its persistent data is still available. With Plex, I checked that all media libraries remained intact.
What I would do differently
Define persistent volumes explicitly from day one, back up stateful services before handing them to an updater, treat recommendations to jump Node.js or database major versions as planned projects, and test each notification path with a real container update. WUD is a strong monitoring and automation tool, but selective automation is what makes it suitable for a mixed homelab.
For the earlier setup, see my original Watchtower on Synology guide. The official WUD trigger documentation explains the opt-in labels and notification events, while the Docker trigger documentation covers automatic and manual update modes.

