Keep Self-Hosted Docker Containers Patched Automatically with Watchtower
Keep Self-Hosted Docker Containers Patched Automatically with Watchtower
Docker does not update your running containers on its own. When a new image is pushed to a registry, every container you started from the old build keeps running that old build until you do something about it. docker pull fetches the new layer, but the live container never changes. Patch, rebuild, or repackage upstream, and your self-hosted stack stays stuck on whatever version was live when you first started it.
In a homelab with twenty containers, "manual" means a weekly checklist of docker pull and docker compose up -d per app. Watchtower exists to remove that chore.
What Watchtower actually does
Watchtower is a small container that watches the other containers on a host. On a schedule it polls each image's registry, compares the digest to what's running, and when a new build exists it:
- Pulls the new image.
- Gracefully stops the running container.
- Restarts it with the same options it was launched with (ports, volumes, environment, restart policy).
The one thing every setup needs is access to the Docker daemon socket, mounted in with --volume /var/run/docker.sock:/var/run/docker.sock. That mount is how Watchtower talks to the Docker API. Without it, nothing works.
Run it with docker run
docker run --detach \
--name watchtower \
--restart unless-stopped \
--volume /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--schedule "0 0 4 * * *"
The schedule flag takes a 6-field cron expression. "0 0 4 * * *" runs the check daily at 4:00 AM - off-peak for most home networks. Skip --schedule and Watchtower defaults to a 24-hour poll interval; the two settings are mutually exclusive.
Run it under Docker Compose
As a Compose service it fits neatly into an existing stack:
services:
watchtower:
image: containrrr/watchtower
container_name: watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
TZ: Asia/Hong_Kong
command: --schedule "0 0 4 * * *" --cleanup
Bring it up with docker compose up -d and it stays a background daemon. Two flags worth knowing: --cleanup deletes superseded images after an update to reclaim disk, and --label-enable switches to an opt-in model so only containers tagged com.centurylinklabs.watchtower.enable=true get touched - the safer default when you do not want your database auto-restarted without warning.
The caveats
Watchtower is not a silver bullet, and the project is explicit about it:
- Homelab and dev only. The official stance is to use it in homelabs, media centers, and local dev environments, and not in a commercial or production environment. Auto-restarting containers in front of real users, with no staged rollout or rollback, is a risk you should not take. Kubernetes-style orchestration is the production answer, not an auto-updater.
- It does not update the Docker engine. Watchtower manages containers and images. The Docker daemon itself still needs its own upgrade path (unattended-upgrades on a Debian host, for example).
- Keep backups before you automate. An automatic restart can pull a broken build at 4 AM while you sleep. Watchtower gracefully restarts containers, but "gracefully" does not mean "safely" if the new upstream image is bad. A rolling backup of your volumes (or at least your databases) is the minimum insurance before you point any auto-updater at persistent data.
Start in monitor-only or label-enable mode, watch the logs for a week, then decide which containers you trust to update themselves. That is how you keep a self-hosted stack patched without losing the sleep that your servers need to stay up.
