Excluding and Ignoring Containers
One of the most-used Watchtower Docker advanced features is selective container management. You have full control over which containers Watchtower monitors.
Exclude specific containers (default: update all)
# Add this label to any container you want Watchtower to SKIP
services:
postgres:
image: postgres:16
labels:
- "com.centurylinklabs.watchtower.enable=false" # Always ignored
nginx:
image: nginx:stable # Will be updated normally
# (no watchtower label = updated by default)
Opt-in mode (update ONLY labeled containers)
# Set this on Watchtower to require explicit opt-in
environment:
- WATCHTOWER_LABEL_ENABLE=true
# Then label only the containers you want updated:
services:
myapp:
image: myapp:latest
labels:
- "com.centurylinklabs.watchtower.enable=true" # Will be updated
postgres:
image: postgres:16
# No label = ignored when WATCHTOWER_LABEL_ENABLE=true
Monitor-only for specific containers
# Notify but never update this container
labels:
- "com.centurylinklabs.watchtower.monitor-only=true"
Custom update notification per container
# Send update notification to a different Slack channel for this container
labels:
- "com.centurylinklabs.watchtower.enable=true"
# Container-level notification overrides aren't natively supported yet
# Use WATCHTOWER_SCOPE for multi-instance routing instead
Private Registry Authentication
Watchtower Docker private registry support covers Docker Hub (authenticated), GitHub Container Registry (ghcr.io), AWS ECR, Google Container Registry (gcr.io), GitLab Registry, and any OCI-compliant registry.
Method 1: Mount Docker credentials (recommended)
# Step 1: Log in to each registry on the Docker host
docker login # Docker Hub
docker login ghcr.io -u USERNAME --password-stdin # GitHub
docker login registry.gitlab.com # GitLab
aws ecr get-login-password | docker login --username AWS \
--password-stdin 123456789.dkr.ecr.us-east-1.amazonaws.com
# Step 2: Mount the resulting config.json into Watchtower
volumes:
- /root/.docker/config.json:/config.json:ro # Contains all registry credentials
Method 2: Environment variables (simple, single registry)
environment:
- REPO_USER=myDockerHubUsername
- REPO_PASS=myDockerHubPasswordOrToken
# Per-registry format (double underscore separator):
- REPO_USER__ghcr.io=myGitHubUsername
- REPO_PASS__ghcr.io=ghp_myGitHubToken
AWS ECR (rotating credentials)
# ECR tokens expire every 12 hours. Use the credential helper:
# 1. Install amazon-ecr-credential-helper on the host
# 2. Add to ~/.docker/config.json:
{
"credHelpers": {
"123456789.dkr.ecr.us-east-1.amazonaws.com": "ecr-login"
}
}
# 3. Mount config.json + the helper binary into Watchtower
volumes:
- /root/.docker/config.json:/config.json:ro
- /usr/bin/docker-credential-ecr-login:/usr/bin/docker-credential-ecr-login
Watchtower on Multiple Docker Hosts
Watchtower connects to one Docker daemon per instance. For Watchtower multiple Docker hosts, run a separate Watchtower container per host:
# On host-1: standard Watchtower with local socket
docker run -d \
--name watchtower-host1 \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_SCOPE=host1 \
-e WATCHTOWER_NOTIFICATION_TITLE_TAG=host1 \
containrrr/watchtower
# On host-2: standard Watchtower with local socket
docker run -d \
--name watchtower-host2 \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_SCOPE=host2 \
-e WATCHTOWER_NOTIFICATION_TITLE_TAG=host2 \
containrrr/watchtower
For a centralized approach (one Watchtower instance managing remote hosts), use TCP Docker API access:
# On the remote host: expose Docker API (use TLS in production!)
# /etc/docker/daemon.json:
{"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]}
# Watchtower pointing to remote host
docker run -d \
--name watchtower-remote \
-e DOCKER_HOST=tcp://192.168.1.100:2375 \
containrrr/watchtower
DOCKER_TLS_VERIFY=1) or an SSH tunnel for remote Docker access.Docker Socket Proxy (Security Hardening)
Mounting the raw Docker socket into Watchtower gives it root-equivalent access to the host. The Watchtower Docker socket proxy pattern limits this exposure:
services:
# Tecnativa Docker Socket Proxy — limits what Watchtower can do
socket-proxy:
image: tecnativa/docker-socket-proxy
restart: unless-stopped
privileged: true
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CONTAINERS=1 # Allow reading container info
- IMAGES=1 # Allow reading/pulling images
- POST=1 # Allow POST requests (needed for updates)
- DELETE=0 # Disallow delete (cleanup still works via Watchtower's own logic)
networks:
- socket-proxy
watchtower:
image: containrrr/watchtower
restart: unless-stopped
environment:
- DOCKER_HOST=tcp://socket-proxy:2375 # Connect via proxy, not raw socket
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_SCHEDULE=0 0 4 * * *
networks:
- socket-proxy
# No socket volume mount needed — connects via TCP to proxy
networks:
socket-proxy:
driver: bridge
internal: true # Isolated from external networks
Rootless Docker Support
In rootless Docker mode, the socket path differs from the default. Configure Watchtower Docker rootless setup:
# Find your rootless socket path:
echo $DOCKER_HOST
# Typically: unix:///run/user/1000/docker.sock
# Watchtower with rootless Docker (environment variable, not volume mount):
docker run -d \
--name watchtower \
-e DOCKER_HOST=unix:///run/user/1000/docker.sock \
-v /run/user/1000/docker.sock:/var/run/docker.sock \
containrrr/watchtower
# In Docker Compose:
services:
watchtower:
image: containrrr/watchtower
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- /run/user/1000/docker.sock:/var/run/docker.sock
Zero-Downtime Update Strategies
Watchtower Docker zero downtime updates are achievable with a combination of rolling restarts and health-check-aware pre/post update hooks.
# Rolling restart: update one container at a time (prevents all replicas restarting simultaneously)
environment:
- WATCHTOWER_ROLLING_RESTART=true
# Per-container: pre/post update lifecycle hooks
labels:
# Run before Watchtower stops the container (drain traffic, save state)
- "com.centurylinklabs.watchtower.lifecycle.pre-update=/scripts/pre-update.sh"
# Run after container is updated and running (notify load balancer)
- "com.centurylinklabs.watchtower.lifecycle.post-update=/scripts/post-update.sh"
# Example pre-update script (inside the container)
#!/bin/sh
# Signal the application to stop accepting new requests
kill -SIGTERM 1
sleep 5 # Allow in-flight requests to complete
Multi-Instance Scoping
Run multiple Watchtower instances on the same Docker host, each managing a different set of containers:
services:
# Instance 1: manages "production" containers with longer interval
watchtower-prod:
image: containrrr/watchtower
environment:
- WATCHTOWER_SCOPE=production
- WATCHTOWER_SCHEDULE=0 0 2 * * 0 # Weekly, 2 AM Sunday
- WATCHTOWER_CLEANUP=true
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Instance 2: manages "dev" containers with frequent checks
watchtower-dev:
image: containrrr/watchtower
environment:
- WATCHTOWER_SCOPE=development
- WATCHTOWER_POLL_INTERVAL=3600 # Every hour
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Each container declares which scope manages it:
# labels:
# - "com.centurylinklabs.watchtower.scope=production"
# # OR
# - "com.centurylinklabs.watchtower.scope=development"
Frequently Asked Questions
Add the label com.centurylinklabs.watchtower.enable=false to the container. Watchtower will skip it during all future update checks. This works regardless of whether WATCHTOWER_LABEL_ENABLE is set — the disable label is always honored.
Each Watchtower instance connects to one Docker daemon. To monitor multiple hosts, run a Watchtower container on each host, or run separate Watchtower instances pointing to remote hosts via DOCKER_HOST=tcp://host:2375. Use WATCHTOWER_SCOPE and WATCHTOWER_NOTIFICATION_TITLE_TAG to distinguish notifications from different hosts.
Run docker login registry.example.com on the host, then mount /root/.docker/config.json:/config.json:ro into Watchtower. One config.json file stores credentials for all registries you've logged into. For AWS ECR (rotating credentials), install the amazon-ecr-credential-helper and reference it in config.json.
Yes. In rootless Docker, the socket is at /run/user/UID/docker.sock. Mount it into Watchtower at /var/run/docker.sock, or set DOCKER_HOST=unix:///run/user/1000/docker.sock. The rest of the configuration is identical to standard Docker.