Deploying Diun and Watchtower: The Decisions That Determine Whether It Actually Works
Starting point
The decision to use Diun alongside Watchtower has already been made: Diun handles notification, Watchtower handles execution, and the combination restores a human checkpoint to a change surface that running :latest tags makes otherwise invisible. What that setup actually looks like, and whether it holds under real operating conditions, depends entirely on a set of decisions that most guides skip past on the way to the Compose file.
The operating context here is a homelab running 10 to 25 Docker containers on Compose, no Kubernetes, one operator. The decisions below are worked through from that position, with honest notes on where the answers change for a team environment or a deployment with stricter operational requirements.
Which containers get auto-update, and which wait for you
This is the decision that defines what the whole setup is for. Watchtower can automatically pull and restart containers when a new image ships, or it can sit in monitor-only mode and wait for an explicit trigger. The choice is not binary across your entire fleet; it's a per-container categorisation that you encode in Docker labels. Getting this wrong in either direction produces the same outcome you were trying to avoid: either something breaks without warning, or nothing ever updates.
The categorisation question is: which containers can absorb an unreviewed restart, and which ones can't? Stateless media tools, dashboard utilities, and containers with no persistent state and no external dependencies are candidates for auto-update. If the image ships a breaking change and the container fails to start, the cost is a few minutes of troubleshooting. That's acceptable. The containers that belong in the manual-review tier are the ones where that failure has more consequence: anything with a database behind it, anything that handles authentication or credentials, anything with external service dependencies that might version-lock, anything you rely on heavily enough that a 2am restart would actually matter to you.
In a homelab, this categorisation is personal and informal. You know which containers you care about. The enforcement mechanism is a single Watchtower label on each container. In a team environment, the same categorisation becomes a documented policy, because the person who built the stack may not be the person on call when Watchtower restarts something at an inconvenient time. The label is still just a label, but what sits behind it should be a decision someone made deliberately and wrote down, not a default that nobody questioned.
Where I landed: media and monitoring containers on auto-update with a maintenance schedule (more on that below). Everything else in the notification-only tier, which means Diun alerts and Watchtower doesn't touch it until I pull manually.
How Watchtower should operate: automatic, scheduled, or on demand
Even for containers you've decided to auto-update, there are three distinct operating modes for Watchtower and they're not equivalent. Fully automatic means Watchtower polls on its own schedule and updates whenever it detects a new image. Scheduled means you constrain when restarts can happen, which is what a maintenance window looks like in this context. On-demand means Watchtower runs as a one-shot job when you choose to trigger it, rather than as a persistent daemon.
The fully automatic mode is the one that gets people burned. It's convenient until a restart happens mid-day on a container you're actively using, or until an upstream image ships a bad release and Watchtower applies it before you've had a chance to check the changelog. The schedule option addresses the timing problem without changing the automation level. Restricting Watchtower's active window to off-hours (using the WATCHTOWER_SCHEDULE cron expression) means restarts happen when you're not in the middle of something, and a failed update waits until morning rather than interrupting your evening.
The on-demand mode is underused and often the right choice for the manual-review tier. Rather than running Watchtower as a service at all, you run it as a one-shot container when you've made the decision to update a specific container. This keeps the automation surface minimal: Diun tells you something changed, you review the changelog, and you run Watchtower's one-shot job against the container you've decided to update. It adds one step but removes the possibility of an unintended update entirely.
In a homelab: scheduled auto-update for the low-risk tier, one-shot on-demand for everything else. In a team environment: I'd move the scheduled auto-update down to dev environments only, and require the explicit one-shot trigger for anything closer to production. Watchtower's restart behavior doesn't respect health checks well enough to trust it with services that carry real uptime expectations.
Where the notification actually lands
Diun firing an alert is only valuable if the alert reaches somewhere you actually look and prompts you to act. This sounds obvious until you set up a Slack notification that lands in a high-volume channel and check it three days later, by which time either you've already updated manually or the notification has scrolled off your attention entirely.
The notification channel decision is partly about tooling and mostly about your real attention patterns. Gotify works well for homelabs that are already using it for other alerting: it's self-hosted, supports persistent notifications that don't disappear, and has a mobile app. Telegram is persistent by default and reaches wherever your phone is. Email works if you actually process your email and treat it as an action queue rather than an inbox you batch-process weekly. Webhook outputs work if you're piping alerts into a workflow (an n8n flow that formats the notification and routes it, for example).
The failure mode to avoid is distributing the notification too broadly. If six people in a team all receive the same Diun alert, nobody feels personally responsible for acting on it. In a solo homelab, this isn't a problem. On a team, the notification needs to route to whoever owns the update decision for that container. Diun's label filtering means you can scope which images generate which notifications, which makes targeted routing possible once the ownership model is defined.
In a homelab: Gotify to mobile is the configuration I'd recommend if you already have Gotify running. If you don't, Telegram is the lower-overhead path. The goal is a persistent notification that doesn't disappear when you close the app.
Docker socket access: full mount or socket proxy
Both Diun and Watchtower need access to the Docker daemon to do their work. The standard configuration mounts the Docker socket directly: /var/run/docker.sock:/var/run/docker.sock. This works immediately and requires no additional setup. It also gives both containers root-equivalent access to the host, because anything that can control the Docker daemon can start privileged containers, mount host filesystems, and escalate beyond the container boundary.
The socket proxy option, most commonly Tecnativa's docker-socket-proxy, exposes only specific Docker API endpoints rather than the full socket. Diun needs read access to container information and image data. Watchtower needs the ability to pull images and restart containers. Neither needs the endpoints that enable the most damaging operations. Restricting to the minimum required is a standard defense-in-depth principle. The cost is one additional container in your stack, some environment variable configuration, and the occasional debugging session when an endpoint you didn't think you needed turns out to be required.
The honest homelab answer is that most people use the full socket mount and accept the risk, because the socket proxy requires knowing it exists and caring enough to implement it before something goes wrong. In an environment that isn't internet-exposed and where the containers running are all from sources you trust, this is a defensible position. The socket proxy becomes important when any of those conditions aren't true: if the host is accessible from external networks, if you're running third-party images you haven't fully audited, or if other containers on the same host run code you didn't write and haven't reviewed.
In a team environment or any deployment with external exposure, the full socket mount is not a policy you want to defend. Minimum viable mitigation is the socket proxy. More complete mitigation is a container runtime with proper RBAC, which is the territory where this tooling approach starts to hit its ceiling and a real orchestrator becomes the right answer.
Monitoring scope: everything or selective
Diun defaults to watching all running containers, which is the right starting point and the wrong long-term configuration for any fleet of meaningful size. Some upstream images release frequently, multiple times a week for active projects. If you're monitoring everything and several images release on overlapping schedules, you get alert volume that trains you to ignore the notifications, which defeats the purpose of the entire setup.
The selective scope approach uses Diun's label configuration to opt containers in explicitly: diun.enable=true on the containers you want monitored, and a Diun configuration that only watches labeled containers. The tradeoff is that new containers are off by default, which means you have to remember to label them at deploy time. The more common failure is forgetting to add the label and wondering later why you never heard about a container that had been running a stale image for months.
Starting broad and narrowing down is a reasonable path: run Diun watching everything for a few weeks to understand your actual update cadence across the fleet, then prune to the containers where the notification adds genuine value. Containers that update every few days from an upstream you trust implicitly are better candidates for auto-update without individual review notifications. Containers that update rarely but carry high stakes when they do update are exactly what the notification layer is for.
In a team context, the scope decision becomes a policy question again: which images are in scope for update monitoring is something that should be defined, not left to individual contributors to add labels or not as they see fit.
What to carry into your own setup
The decisions above are not independent. The scope decision shapes the alert volume, which determines whether the notification channel you chose can absorb it. The auto-update tier you defined determines whether Watchtower's schedule matters or whether you're running it on-demand. The socket access decision scales with how much you trust the containers sharing that socket.
Before deploying: know which containers are in the manual-review tier before you turn Watchtower loose. Label them first. The notification layer works if and only if there's a real decision process sitting behind it. If the notification arrives and your response is to run the update immediately without checking the changelog, you've automated the surveillance and kept the blind execution, which is the failure mode you started with. The value is in the pause between the alert and the action. Design for that pause to actually happen.