If you're running more than a couple of self-hosted apps in LXC containers on Proxmox VE, you already know the routine. SSH into the container, cd into the compose folder, run docker compose pull, then docker compose up -d, and repeat for every other container on your node. It's not hard, but it's tedious, and it's exactly the kind of chore that gets skipped for months until you notice a container is three major versions behind and the upgrade path is a mess.

Watchtower fixes that by doing the boring part for you. It watches your running Docker containers, checks whether a newer image is available, and swaps the container over automatically — same volumes, same environment variables, same network settings, just running the new image. You set it up once and mostly forget about it.

This guide covers installing Watchtower inside a Docker-enabled LXC container on Proxmox VE 9.2 (Debian 13.5 Trixie, LXC 7.0), configuring it safely so it doesn't update things you don't want touched, and wiring up notifications so you actually know what it changed.

What You'll Learn

By the end of this guide you'll have Watchtower running inside an LXC container, checking for updates on a schedule you control, sending you a notification whenever it updates something, and leaving specific containers alone when you tell it to. You'll also know how to check what it did after the fact, and how to undo an update if a new image breaks something.

What Is Watchtower?

Watchtower is a small, open-source program that runs as its own Docker container. Once it's running, it periodically compares the image tag your containers are using against what's currently available in the registry — Docker Hub, GitHub Container Registry, or a private one. If there's a newer image with the same tag (for example, a fresh build of linuxserver/jellyfin:latest), Watchtower pulls it, stops the old container, and starts a new one in its place using the same configuration.

It doesn't touch anything outside of Docker. It has no idea Proxmox exists, doesn't manage LXC containers or VMs, and won't update Proxmox VE itself. All it does is watch and update Docker containers, which is exactly why it pairs so well with a Proxmox homelab full of single-purpose LXC containers each running one app via Docker.

Why Would You Use It?

Most of the self-hosted apps people run on Proxmox — things like Immich, Paperless-ngx, Uptime Kuma, or Vaultwarden — ship frequent updates. Some of those updates are security fixes. Waiting weeks or months to apply them is how a homelab quietly turns into a liability.

Manually updating a handful of containers is manageable. Once you're past ten or fifteen, across multiple LXC containers, it stops being manageable and starts being the thing you avoid doing. Watchtower removes the decision entirely: it checks, it updates, it tells you when it did.

It's not the right tool for everything, though. If you're running something where an unexpected version bump could break a working setup — a database with a picky migration process, or a reverse proxy config that's tightly coupled to a specific version — you probably want manual control there. Watchtower supports excluding specific containers, which is what makes it safe to run broadly instead of all-or-nothing.

Prerequisites

Before you start, you'll need:

  • A Proxmox VE 9.2 host with an unprivileged LXC container already created (Debian 13 or Ubuntu 24.04 both work well)
  • Docker installed and working inside that container, with at least one container already running via docker run or Docker Compose
  • Root or sudo access inside the LXC container
  • An outbound internet connection from the container, since Watchtower needs to reach Docker Hub or whatever registry your images come from

If Docker isn't running inside your LXC container yet, get that working first. It needs nesting=1 and keyctl=1 set as container features in the container's options (Resources → Options, or pct set <vmid> -features nesting=1,keyctl=1 from the host shell), otherwise the Docker daemon will fail to start with cgroup or overlay filesystem errors. That's a separate setup step and worth getting right before layering Watchtower on top.

Step-by-Step Tutorial

Step 1: Confirm Docker Is Working

SSH into your LXC container and run:

docker ps

You should see your existing containers listed. If you get a permission error or "Cannot connect to the Docker daemon," fix that before continuing — Watchtower needs a working Docker socket to do anything.

Step 2: Run Watchtower as a Container

The simplest way to run Watchtower is a single docker run command:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower

That mounts the Docker socket into the Watchtower container so it can see and manage the other containers on the same host, and sets it to restart automatically if the LXC container reboots. With no other options, Watchtower checks every container once every 24 hours by default.

Step 3: Set a Check Interval

A daily check is fine for most people, but if you want updates to land sooner — or you're testing your setup and don't want to wait a full day — add the WATCHTOWER_POLL_INTERVAL variable, in seconds:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -e WATCHTOWER_POLL_INTERVAL=21600 \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower

That checks every 6 hours. I wouldn't go much tighter than an hour on a home connection — there's no real benefit, and it's just extra registry API calls that can get you rate-limited on Docker Hub if you're running a lot of containers.

Step 4: Clean Up Old Images

By default, Watchtower leaves the old image sitting on disk after it updates a container. Over months that adds up to several gigabytes of dangling images nobody's using. Add WATCHTOWER_CLEANUP=true to remove the old image automatically once the new container is confirmed running:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -e WATCHTOWER_POLL_INTERVAL=21600 \
  -e WATCHTOWER_CLEANUP=true \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower

Step 5: Exclude Containers You Don't Want Touched

This is the step people skip and later regret. Not every container should update itself blindly — a database, for instance, might need a manual migration step between major versions. Watchtower respects a label on individual containers instead of making you list exceptions in the Watchtower config itself:

docker run -d \
  --name postgres \
  --label com.centurylinklabs.watchtower.enable=false \
  postgres:16

Then tell Watchtower to only touch labeled containers by adding WATCHTOWER_LABEL_ENABLE=true to its own run command. With that flag set, Watchtower ignores every container by default and only updates the ones explicitly labeled com.centurylinklabs.watchtower.enable=true. That's the safer approach if you have a mix of things you do and don't want auto-updated — it's opt-in rather than opt-out, so a new container you spin up later doesn't get auto-updated by accident.

Step 6: Add Notifications

An update happening silently in the background isn't very useful if something breaks and you don't know why. Watchtower can send a message through several services; a webhook to something like ntfy or Gotify (both of which you can also self-host in an LXC container on the same Proxmox host) is the easiest to set up:

docker run -d \
  --name watchtower \
  --restart unless-stopped \
  -e WATCHTOWER_POLL_INTERVAL=21600 \
  -e WATCHTOWER_CLEANUP=true \
  -e WATCHTOWER_LABEL_ENABLE=true \
  -e WATCHTOWER_NOTIFICATIONS=shoutrrr \
  -e WATCHTOWER_NOTIFICATION_URL="ntfy://ntfy.example.com/watchtower" \
  -v /var/run/docker.sock:/var/run/docker.sock \
  containrrr/watchtower

Swap that URL for whatever service you already use. Once it's set, every update run generates a short report — which containers were checked, which were updated, and which failed — delivered straight to your phone or desktop.

Commands Explained

A quick reference for what each piece of the setup actually does:

Command / FlagWhat It Does
-v /var/run/docker.sock:/var/run/docker.sockGives Watchtower access to the Docker daemon so it can see, stop, and recreate other containers. This is the same socket the docker CLI itself uses.
--restart unless-stoppedKeeps Watchtower running across reboots of the LXC container, unless you manually stop it.
WATCHTOWER_POLL_INTERVALHow often, in seconds, Watchtower checks for new images.
WATCHTOWER_CLEANUPRemoves the old image after a successful update, keeping disk usage down.
WATCHTOWER_LABEL_ENABLESwitches Watchtower to opt-in mode: only containers labeled for it get updated.
docker logs watchtowerShows what Watchtower has checked and updated so far, useful for confirming it's actually running.

Common Errors

"Cannot connect to the Docker daemon at unix:///var/run/docker.sock" — this usually means the socket wasn't mounted correctly, or you're running the command from inside a shell that doesn't have Docker access. Double-check the -v flag matches exactly, including the path on both sides of the colon.

Watchtower restarts a container but it immediately exits — this is almost never Watchtower's fault. It means the new image genuinely has a startup problem, a changed config format, or an environment variable the new version now requires. Check docker logs <container-name> for the real error from the app itself.

429 Too Many Requests from Docker Hub — you're polling too often, or you're running Watchtower on more than a couple of hosts pointed at the same Docker Hub account without authentication. Docker Hub rate-limits anonymous pulls to 100 per 6 hours per IP. Either space out your poll interval or authenticate with docker login before starting Watchtower.

Troubleshooting

If you're not sure Watchtower is doing anything at all, start with its own logs:

docker logs -f watchtower

A healthy run looks like a list of container names it checked, followed by either "Found no available updates" or a line showing it stopped and recreated a specific container. If the log is empty or the container has exited, run docker ps -a to check its status — a crash loop there usually traces back to a typo in one of the environment variables.

If notifications aren't arriving but updates are happening (visible in the logs), test the notification URL on its own first. Most notification failures come down to a wrong token or a firewall blocking the LXC container from reaching your ntfy or Gotify instance, not Watchtower itself.

If a specific container keeps getting updated even though you labeled it to be skipped, check that WATCHTOWER_LABEL_ENABLE=true is actually set on the Watchtower container. Without that flag, labels are ignored entirely and every container is fair game.

Best Practices

Run Watchtower with WATCHTOWER_LABEL_ENABLE=true rather than letting it touch everything by default. It takes an extra minute per container to add the label, and it means a database or a finicky reverse proxy config never gets surprise-updated while you're asleep.

Set notifications up before you need them, not after something breaks and you're trying to figure out what changed. A one-line ntfy notification costs nothing and saves you the guessing game later.

Take a Proxmox snapshot of the LXC container (or back it up with vzdump) before you first flip Watchtower on for a container you actually care about. If an update does go sideways, rolling back the whole container to a snapshot is faster than trying to manually downgrade a Docker image by hand.

Don't run Watchtower on truly critical infrastructure without testing the update path somewhere else first. Pi-hole, Vaultwarden, or your reverse proxy are things you want to know behave well across an upgrade before you let them auto-update unattended.

Frequently Asked Questions

Does Watchtower work with Docker Compose containers?

Yes. Watchtower works at the container level, not the compose-file level, so it doesn't care whether a container was started with docker run or docker compose up. It updates the running container either way.

Will Watchtower update Proxmox VE itself?

No. Watchtower only manages Docker containers. Updating Proxmox VE is a separate process using apt update && apt dist-upgrade on the host, unrelated to anything Watchtower does.

Can I run Watchtower on the Proxmox host instead of inside an LXC container?

Technically yes if Docker is installed directly on the host, but that's not recommended. Running Docker on the Proxmox host itself competes with Proxmox's own management tools for resources and complicates backups. An LXC container keeps it isolated.

What happens if an update breaks a container?

Watchtower doesn't roll back automatically. You'd need to manually pull the previous image tag and recreate the container, or restore from a Proxmox snapshot or backup taken before the update.

Does Watchtower use a lot of resources?

No. It's idle almost all the time and only briefly active during a check cycle. 512 MB of RAM and a single vCPU for the whole LXC container is more than enough, even running a handful of other lightweight services alongside it.

Conclusion

Watchtower is one of those tools that feels almost too simple for what it does. Fifteen minutes of setup, and every Docker container on that LXC host stays current without you having to remember it's a chore. The label-based exclusion is what makes it safe to trust broadly instead of babysitting every update — you decide what's hands-off, and everything else just stays patched.

Pair it with a notification channel and a snapshot habit before you flip it on for anything important, and it'll quietly do one of the more tedious parts of running a homelab so you don't have to think about it.