How to Auto-Update Docker Containers with Watchtower (and When Not To)

Watchtower: auto-update your containers — Sunday 4 am, with a message about what changed.

Unattended-upgrades keeps the operating system patched (tutorial 36), but nothing updates your Docker containers unless you run docker compose pull. Watchtower is a container that checks the others for new images on a schedule, pulls them, and restarts each one with exactly the settings it had. Set it to run at 4 am on Sundays, tell it to leave the fragile apps alone, and have it message you about what it did.

Quick reference

TaskWhat
Folder~/docker/watchtower/compose.yaml
ScheduleWATCHTOWER_SCHEDULE in cron format (six fields, with seconds)
Exclude a containerlabel com.centurylinklabs.watchtower.enable=false
Notify only, don't updateWATCHTOWER_MONITOR_ONLY=true
Clean old imagesWATCHTOWER_CLEANUP=true
Run once nowdocker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once

1. The compose file

mkdir -p ~/docker/watchtower && cd ~/docker/watchtower
nano compose.yaml

services:
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
environment:
TZ: Europe/London
WATCHTOWER_SCHEDULE: "0 0 4 * * 0"
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_INCLUDE_STOPPED: "false"
WATCHTOWER_NOTIFICATION_URL: "telegram://BOT_TOKEN@telegram?chats=CHAT_ID"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped

docker compose up -d

2. Exclude what shouldn't auto-update

Some apps need you to read release notes before updating — databases, Immich, Nextcloud, Home Assistant. Add a label to those services in their compose files:

labels:
- com.centurylinklabs.watchtower.enable=false

and docker compose up -d there. Watchtower skips them and tells you an update exists instead.

Prefer the other way round? Set WATCHTOWER_LABEL_ENABLE=true and only containers labelled enable=true are touched.

3. Or notify only

If automatic restarts make you nervous, add:

WATCHTOWER_MONITOR_ONLY: "true"

Watchtower then just messages you "new image for jellyfin" and you update by hand. Many people run it this way.

4. Pinned versions still work

A container on nextcloud:30 only gets 30.x updates — Watchtower pulls whatever tag the container was started with. Pin major versions for things with migration steps and leave latest for the simple ones.

What Watchtower can't do

It doesn't rebuild images you built yourself, and it doesn't read compose.yaml changes — it recreates the container as it was. If you change the compose file, run docker compose up -d yourself.

Troubleshooting

Nothing ever updates. Check the schedule has six fields and the time zone is set. docker logs watchtower shows "Scheduling first run".

An app broke after an update. Roll back by pinning the previous tag in its compose file (image: app:1.2.3) and up -d. Then add the exclude label.

Notifications don't arrive. Test the URL with docker run --rm containrrr/watchtower --notification-url "..." --run-once.

Watchtower updated itself and vanished. Normal — it restarts. If it doesn't, docker compose up -d in its folder.

Wrapping up

One container, a Sunday-morning schedule, cleanup on, a Telegram message with the results. Label the fragile apps so they wait for you. Between this and unattended-upgrades, the server keeps itself current and you keep the decisions that matter.

Call us