IAnswerable

Auto-Update Containers with Watchtower

30 Sep 2026

Watchtower watches your running containers and pulls new images the moment they’re pushed. No cron job, no manual docker pull && docker up -d. It also means a bad upstream release lands on your server at 3am with nobody watching.

What it actually does

Watchtower polls the registry for each container’s image tag on an interval. If the digest changed, it pulls the new image, stops the old container, and starts a new one with the same config. That’s it — no build step, no test run, no approval gate.

docker run -d \
  --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower --interval 3600

That one line auto-updates every container on the host, every hour, forever.

The 3am failure mode

You’re running postgres:16 with no digest pin. Upstream ships 16.4 with a changed default for max_connections, or a security patch that breaks an extension you depend on. Watchtower pulls it, restarts the container, and your app starts throwing connection errors while you’re asleep.

The failure isn’t Watchtower’s fault — it’s doing exactly what you told it to. The mistake is auto-updating anything that holds state or matters at 2am.

Scope it with labels, not a blanket interval

Don’t run the bare command above. Opt containers in explicitly:

docker run -d \
  --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower --interval 3600 --label-enable

Then tag only the containers you actually want auto-updated:

services:
  nginx-proxy:
    image: nginx:1.27
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
  postgres:
    image: postgres:16
    # no label — Watchtower ignores this one

Stateless, easily-restarted services (reverse proxies, static site containers, a status page) are good candidates. Databases, queues, and anything with migrations are not.

Pin tags, don’t float on latest

image: myapp:latest means Watchtower updates on any push, including ones you didn’t mean to ship broadly. Use a specific minor version (myapp:1.4) so a 1.4.x patch release is the only thing that moves under you, and bump major/minor versions yourself, deliberately.

Get notified before you get paged

Watchtower can post to Slack, Discord, or a generic webhook on every update:

docker run -d \
  --name watchtower \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e WATCHTOWER_NOTIFICATIONS=slack \
  -e WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL=https://hooks.slack.com/services/XXX \
  containrrr/watchtower --interval 3600 --label-enable

Now an update at 3am shows up in Slack instead of only in docker logs watchtower, and you can correlate “site’s down” with “oh, it updated an hour ago” in seconds instead of guessing.

What breaks and how to see it

Symptom Likely cause Fix
Container restarts, app 500s New image changed a default (env var, config format) Pin the tag, read the changelog before bumping
Container won’t start after update Image removed a feature you relied on docker logs <container>, roll back tag manually
Data loss / corruption on restart Auto-updated a stateful service mid-write Never label stateful containers for auto-update

If a container gets stuck in a bad state, Watchtower doesn’t roll back for you — it only rolls forward. Keep the previous image tag noted somewhere (a comment in your compose file is enough) so docker run myapp:1.3 is a thirty-second fix, not an archaeology project.

Use Watchtower for the boring, stateless stuff. Update everything else on your own schedule, when you’re awake to watch it.