Self-Host Watchtower: Automatic Docker Container Updates on Autopilot

Self-Host Watchtower: Automatic Docker Container Updates on Autopilot

Stop manually checking for Docker updates. Set up Watchtower to auto-update your containers, with sane exclusions so only safe services update unattended.

đź’ˇ Disclosure: This article contains affiliate links. If you make a purchase through these links, we may earn a small commission at no extra cost to you. This helps support the site and keeps the content free.

I used to be religious about manual updates. Every Sunday morning, coffee in hand, I’d SSH into my server and run a dozen docker compose pull && docker compose up -d commands like some kind of sysadmin church ritual.

Then I missed a critical security patch on my reverse proxy. Someone found it before I did. That was the day I stopped pretending I’d keep up with updates manually.

Watchtower Is Not Renovate (And That’s Fine)

If you’ve read the Renovate guide on this site, you know the argument against automatic updates: they can break things. I agree. For critical services like Vaultwarden or your auth portal, manual review makes sense.

But here’s the thing — Renovate and Watchtower solve different problems. Renovate gives you pull requests to review. Watchtower just updates stuff. One is cautious, the other is lazy. I use both. Renovate for the apps I care about most, Watchtower for everything else.

For my media stack (Jellyfin, Sonarr, Radarr), transmission, monitoring tools, and utilities — I genuinely don’t care if they update to a broken version. In the worst case, I roll back. And honestly? In two years, that’s happened exactly once.

Deploying Watchtower

The setup is laughably simple. Create a docker-compose.yml:

services:
  watchtower:
    image: containrrr/watchtower
    container_name: watchtower
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - TZ=Etc/UTC
      - WATCHTOWER_CLEANUP=true
      - WATCHTOWER_SCHEDULE=0 0 3 * * *
      - WATCHTOWER_INCLUDE_RESTARTING=true

That WATCHTOWER_SCHEDULE is a cron expression — 0 0 3 * * * means “run every night at 3 AM.” Adjust it to whenever your server is least busy.

WATCHTOWER_CLEANUP=true removes old images after updating, so your disk doesn’t fill up with stale layers.

Spin it up:

docker compose up -d

Check it’s running:

docker logs watchtower

You should see it checking for new images immediately. Then it’ll go quiet until the scheduled time.

Excluding Containers You Care About

This is the trick that makes Watchtower actually useful instead of terrifying. Add a label to any container you don’t want auto-updated:

services:
  vaultwarden:
    image: vaultwarden/server:latest
    labels:
      - "com.containrrr.watchtower.enable=false"

Now Vaultwarden stays on whatever version you manually approve, while everything else updates on autopilot.

I exclude my authentication services, databases, and anything that handles money or credentials. Everything else gets the automatic treatment.

One-Time Updates (The Manual Middle Ground)

Don’t want fully automatic updates but still hate SSHing to run commands? Use Watchtower in one-shot mode:

docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower \
  --run-once \
  --cleanup

This updates everything right now, then exits. Perfect for those times when you remember “oh right, I should update stuff” but don’t want to type five separate docker compose commands.

I have this aliased in my .bashrc:

alias update-all='docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once --cleanup'

Notifications When Things Update

Watchtower can ping you when it does its thing. Here’s my config with Gotify (covered in another article on this site):

services:
  watchtower:
    image: containrrr/watchtower
    environment:
      - WATCHTOWER_NOTIFICATIONS=gotify
      - WATCHTOWER_NOTIFICATION_GOTIFY_URL=https://gotify.yourdomain.com
      - WATCHTOWER_NOTIFICATION_GOTIFY_TOKEN=your_token_here

Now every time Watchtower updates a container, you get a push notification. You’ll know exactly what changed and when. If something breaks, you know where to look.

Shoutout to Shoutrrr, which Watchtower uses under the hood. It supports Slack, Discord, Telegram, email, and basically everything else.

My Actual Setup After Two Years

Two years in, here’s what I actually run:

  • Scheduled at 4 AM daily — Updates most containers automatically
  • Excluded: Vaultwarden, Authentik, Traefik, databases
  • Notifications: Gotify with title “Watchtower Update” so I can filter
  • Manual check: I run update-all before any intentional downtime

Has it ever caused real problems? Once. Jellyfin pushed a bad build that broke hardware transcoding. I noticed the next morning because Plex (yes, I run both) still worked. Rolled Jellyfin back with docker compose pull [previous-tag] and moved on. The total damage was about ten minutes of my spouse saying “the movie app isn’t working.”

Worth it for the hundreds of updates I didn’t have to think about.

When Not to Use Watchtower

Be honest with yourself. If you’re running something that handles authentication, financial data, or personal documents — don’t let Watchtower touch it. Put that exclusion label on and sleep better.

And no, Watchtower is not a substitute for a proper backup strategy. If an update nukes your database schema, auto-updating to the latest image won’t help. Make sure you have backups before you automate anything.

But for the rest of your stack? Let it fly. Your Sunday mornings will thank you.

🚀NordVPN

Secure your server with a reliable VPN before exposing Watchtower-updated services to the internet.

Get NordVPN →

Affiliate link — we may earn a commission at no extra cost to you.

Stay in the loop 📬

Get self-hosting tutorials, tool reviews, and infrastructure tips delivered to your inbox. No spam, unsubscribe anytime.

Join 0 self-hosters. Free forever.