README.md
June 7, 2026 · View on GitHub
Watchtower — the maintained fork
Automatic base-image updates for Docker containers.
A drop-in replacement for containrrr/watchtower, which is no longer maintained upstream.
TL;DR
- What it is: a small Go daemon that polls the Docker socket, checks registries for new image digests, and recreates stale containers with the same config (volumes, networks, env, command).
- Who it's for: homelabs, self-hosted stacks, media centers, dev environments — anywhere a running Kubernetes cluster would be overkill.
- Who it's not for: production workloads that need staged rollouts, canaries, or rollback. Use Kubernetes (or k3s / MicroK8s) for that.
- Images:
docker.io/openserbia/watchtowerandghcr.io/openserbia/watchtower(multi-arch: amd64, arm64, arm/v6, arm/v7, 386, riscv64). - Module path:
github.com/openserbia/watchtower.
Quick start
Requirements: Docker Engine 20.10 or newer. Watchtower auto-negotiates the API version, so older daemons may work but aren't tested.
docker run --detach \
--name watchtower \
--volume /var/run/docker.sock:/var/run/docker.sock \
openserbia/watchtower
That's it — Watchtower polls every 24h by default and updates any container it can see. To scope it, opt containers in with a label:
docker run --label com.centurylinklabs.watchtower.enable=true my-app:latest
docker run -v /var/run/docker.sock:/var/run/docker.sock \
openserbia/watchtower --label-enable
docker-compose
services:
watchtower:
image: openserbia/watchtower:latest
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
command:
- --interval=60
- --cleanup
- --label-enable
Full flag reference, notification setup, lifecycle hooks, HTTP API, and metrics all live on the docs site.
Why this fork
containrrr/watchtower stopped accepting changes in late 2024. This fork keeps it alive with a modern toolchain (Go 1.26, golangci-lint v2, Devbox-pinned CI) and extends the same feature set across four axes:
- Fixes real-world upstream bugs left unmerged when the project was archived — #966 (
--cleanupdeletes the replacement image), #1217 (nil-pointer panic on GC'd source image), #1413 (No such imageloop that wedges the container). - Safer updates — opt-in
--health-check-gatedwaits for the replacement container to report healthy and automatically rolls back to the previous image on failure, with per-container label overrides and a post-rollback cooldown that prevents thrash. - Flexible update strategies — a new
--update-strategyflag (recreate(default) /rolling-restart/blue-green), selectable per container via thecom.centurylinklabs.watchtower.update-strategylabel. Blue-green is true zero-downtime: it starts the new container alongside the old, waits for it to report healthy, drains, then retires the old — for stateless services behind a dynamic label-based reverse proxy (Traefik) with no published host ports. - Hardened network layer — bounded exponential backoff on registry flakes, an in-memory bearer-token cache, strict TLS by default (removing upstream's blanket
InsecureSkipVerify), constant-time bearer-token comparison, and opt-in--insecure-registry/--registry-ca-bundlefor self-signed registries. - Operational visibility — ship-ready Grafana dashboard + Prometheus alerts, a
GET /v1/auditJSON endpoint for post-deploy verification,--http-api-metrics-no-authfor trusted-network scraping, and ~20 new metrics covering every HTTP-facing surface (request counts by status/endpoint/host/outcome, retry counters, Docker API errors, bearer-cache hit rate, poll-duration histogram, and more).
Drop-in compatible — same CLI flags, labels (com.centurylinklabs.watchtower.*), HTTP API, and notification backends. Swap the image name and you're done. Migration diff, full comparison table, and roadmap: Why this fork?.
Verifying a release
# Binary checksums
sha256sum -c watchtower_<version>_checksums.txt --ignore-missing
# Verify the checksums file's keyless cosign signature (Sigstore bundle)
cosign verify-blob \
--bundle watchtower_<version>_checksums.txt.sigstore.json \
--certificate-identity-regexp '^https://github.com/openserbia/watchtower/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
watchtower_<version>_checksums.txt
# Verify a published image's keyless cosign signature
cosign verify ghcr.io/openserbia/watchtower:latest \
--certificate-identity-regexp '^https://github.com/openserbia/watchtower/' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# Inspect the SLSA build provenance attached to the image
docker buildx imagetools inspect ghcr.io/openserbia/watchtower:latest \
--format '{{ json .Provenance }}'
# Inspect the CycloneDX SBOM attached to the image
docker buildx imagetools inspect ghcr.io/openserbia/watchtower:latest \
--format '{{ json .SBOM }}'
Security
Report vulnerabilities via GitHub Security Advisories — this opens a private thread with the maintainers. Please do not file public issues for security bugs. See SECURITY.md for scope and policy.
Contributing
devbox shell # reproducible toolchain (Go 1.26, golangci-lint v2, go-task)
devbox run -- task lint # 0 findings required
devbox run -- task test # Ginkgo suites with -race
devbox run -- task build # ./build/watchtower
See CONTRIBUTING.md for PR expectations and CLAUDE.md for an architectural tour tuned for AI coding assistants (and handy for humans too).
Security scanning
Trivy + Snyk are wired through Taskfile.security.yml (see task -l security for the full list). Quick start:
task security:snyk:deps— Snyk Open Source vulnerability scantask security:snyk:code— Snyk Code SASTtask security:all— every trivy + snyk scan
Shared config across CLI and the JetBrains Snyk plugin:
.snyk— path excludes and per-issue ignores. Both the CLI and the IDE plugin read this automatically..idea/snyk.xml— project-level plugin settings; sets--severity-threshold=highto matchSNYK_SEVERITYin the Taskfile.
One-time IDE setup (per-user state): in Settings → Tools → Snyk, enable Open Source and Code. Sign in via SNYK_TOKEN env or the plugin's "Authenticate" button — the CLI and plugin share the same token store.
License
Apache 2.0. Originally © containrrr authors; fork maintained under the same license. See LICENSE.md.