What Watchtower Does and Why You Want It
If you run Docker containers on an Ubuntu server, you already know the routine: an image maintainer ships a security fix, and your container keeps running the old image until you notice, pull the new one, and recreate the container by hand. On a server with ten containers, that routine eats an evening. Watchtower automates it.
Watchtower is a small container that watches your other containers, checks whether a newer version of their image exists in the registry, and — when one does — pulls it, stops the old container, and starts a new one with the exact same options. Your data volumes, port mappings, environment variables, and restart policies all carry over. By the end of this guide, Watchtower will be updating your stack on a schedule you control, and you will know how to verify it and rein it in.
Prerequisites
- An Ubuntu 22.04 or 24.04 server with sudo access.
- Docker Engine installed and running (check with
docker --version). - At least one running container to update — Watchtower is pointless on an empty host.
- A container registry you can reach (Docker Hub by default, or a private registry).
Step 1: Confirm Docker Is Running
Before anything else, confirm Docker is healthy and list your containers:
sudo systemctl status docker --no-pager
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
The first command confirms the Docker daemon is active. The second lists every running container with its image and status, so you know exactly what Watchtower will be managing.
Step 2: Start Watchtower
Watchtower itself is just a container. Start it with a single command:
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower
The -v /var/run/docker.sock:/var/run/docker.sock mount is the key: it gives Watchtower access to the Docker daemon so it can inspect and recreate containers. --restart unless-stopped makes sure Watchtower survives a server reboot. The image nickfedor/watchtower is the currently maintained fork of the original containrrr/watchtower project.
By default, Watchtower checks for updates every 24 hours. If you want it to run on your schedule instead, pass a cron expression:
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower \
--schedule "0 0 4 * * *"
The schedule 0 0 4 * * * is a six-field cron expression (seconds, minutes, hours, day, month, weekday) that runs the check every day at 04:00. Running updates at night means a brief container restart happens when traffic is lowest.
Step 3: Clean Up Old Images Automatically
Every update leaves the old image behind, and over weeks those stale images eat disk space. Add the --cleanup flag so Watchtower removes the image it just replaced:
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower \
--schedule "0 0 4 * * *" \
--cleanup
If Watchtower is already running, stop and remove it first, then rerun the command with the new flags — Watchtower's own settings live in its run command, not in a config file:
docker stop watchtower && docker rm watchtower
For Docker Compose users, the equivalent service block is:
watchtower:
image: nickfedor/watchtower
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command: --schedule "0 0 4 * * *" --cleanup
Step 4: Control Which Containers Get Updated
Updating everything blindly is risky — a major-version jump in your database could break your app. Watchtower gives you two safe patterns.
Option A: Opt-in with labels
Start Watchtower with --label-enable, and it will only touch containers carrying the label com.centurylinklabs.watchtower.enable=true:
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower \
--label-enable --cleanup
Then label the containers you want updated, for example in Compose:
nginx:
image: nginx:latest
labels:
- "com.centurylinklabs.watchtower.enable=true"
For a container started with docker run, add --label com.centurylinklabs.watchtower.enable=true to its run command.
Option B: Monitor-only mode
If you want visibility without automatic restarts, run Watchtower in monitor-only mode. It logs available updates but changes nothing:
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower \
--monitor-only
This is the safest first step on a production server: run monitor-only for a week, read the logs, and only then switch to automatic updates for the containers that behaved well.
Step 5: Get Notified About Updates
Watchtower can email you a summary after each run. Pass the notification settings as environment variables:
docker run -d \
--name watchtower \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_NOTIFICATIONS=email \
-e WATCHTOWER_NOTIFICATION_EMAIL_FROM=watchtower@yourdomain.com \
-e WATCHTOWER_NOTIFICATION_EMAIL_TO=you@yourdomain.com \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.yourdomain.com \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587 \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=watchtower@yourdomain.com \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD='your-smtp-password' \
nickfedor/watchtower \
--cleanup
Replace the SMTP values with your own mail provider's settings. Slack, Telegram, and other notification targets are also supported through the same WATCHTOWER_NOTIFICATIONS variable.
Verify It Worked
Watchtower logs every check it makes. Follow the log after starting it:
docker logs -f watchtower
You should see lines like Watchtower started and a session entry for each container it checked. To force an immediate check instead of waiting for the schedule, run Watchtower once:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
nickfedor/watchtower \
--run-once
Then confirm your containers are still running with their new images:
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
docker images --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedSince}}"
If a container restarted with a newer image tag or a fresh creation time, the update worked.
Common Issues and Fixes
Watchtower updates nothing, logs say "no new image found"
This usually means the container uses a pinned tag that never changes, like nginx:1.27.0, or a locally built image with no registry copy. Watchtower can only update images that exist in a registry. Switch to a floating tag such as nginx:latest or nginx:stable for containers you want auto-updated.
Private registry images fail with authentication errors
Watchtower reads the Docker config on the host. Log in to the registry on the host first so credentials exist:
docker login registry.example.com
Then restart Watchtower so it picks up the credentials from ~/.docker/config.json.
A container loses its custom options after an update
Watchtower recreates containers from the options recorded by the Docker daemon, so options set at creation time are preserved. If something is missing, it usually means the container was modified after creation with docker update or a manual network change — recreate the container once with the full intended options and Watchtower will preserve them from then on.
Watchtower itself never updates
By default, Watchtower does not update itself. Add the --label-enable pattern and label the Watchtower container, or enable self-update explicitly with the WATCHTOWER_SELF_UPDATE environment variable set to true and restart it.
Disk fills up despite updates working
You forgot --cleanup. Old images accumulate on every update. Add the flag, restart Watchtower, and prune the backlog once manually:
docker image prune -a -f
Be careful: that command removes all images not attached to a running container, so only run it when you are sure nothing important is stopped.
Conclusion
Watchtower turns container updates from a weekly chore into a background task: one small container, a schedule that fits your traffic, cleanup enabled, and labels or monitor-only mode keeping the risky services under your control. Start with monitor-only on production, graduate to labelled auto-updates, and let the logs tell you what changed.
Need help setting up Docker, Watchtower, or a full self-hosted stack on your server? XpertBees configures and maintains production Docker environments — reach out and we will get your infrastructure updating itself safely.



