Docker container auto-updater · Rust
Keep your Docker containers fresh, safely.
freshdock watches your running containers, notices when a newer image ships, and updates them health-gated. A broken update rolls back automatically instead of leaving you with a dead service. The maintained successor to the archived Watchtower.
$cargo install freshdockSee it first (read-only)
freshdock check changes nothing
| container | image | mode | current digest | latest digest | update? |
|---|---|---|---|---|---|
| nimbus | turbootzz/nimbus | live | sha256:7be033 | sha256:7be033 | no |
| vaultwarden | vaultwarden/server:1.32 | live | sha256:1c4d0e | sha256:9af2b1 | yes |
| jellyfin | lscr.io/linuxserver/jellyfin | weekly | sha256:33aa9b | sha256:8e9142 | yes |
| caddy | caddy:2.8 | nightly | sha256:9f2a1c | sha256:9f2a1c | no |
| postgres | postgres:16 | nightly | sha256:b21e7a | pinned (no check) | - |
| backups | ghcr.io/me/backups:latest | nightly | sha256:e0a3f1 | auth required | ? |
01 · detect
Resolves the latest registry digest per image and compares it to what each opted-in container is running, deduped to respect rate limits.
02 · update
On its per-container schedule, freshdock pulls the new image and recreates the container with the exact same config: networks, volumes, env, all of it.
03 · verify
It waits for the new container to prove healthy. If it doesn’t, the previous container is restored, and a failure notification goes out.
Nothing is touched until you ask.
freshdock is opt-in by design, the opposite of Watchtower’s update-everything default. A container is invisible until you set freshdock.enable=true, and an enabled container with no explicit mode defaults to watch: detect-and-notify, never restart. You graduate it to an updating mode only when you’re ready. This is what protects you from “Watchtower broke my server overnight.”
What you get
Watchtower-level capability, Cup-level footprint.
The full update cycle (check, pull, recreate, health-gate, clean up) in one small binary.
Health-gated rollback
A container counts as updated only after its healthcheck passes, or a grace period for those without one. A broken new image is reverted to the previous container automatically, and you’re notified.
Per-container modes
Drive each container with a label: live, nightly, weekly, monthly, watch, or off. Mix them freely on one daemon. Container A on live, container B on weekly.
Five registries
Docker Hub, GHCR, Quay.io, lscr.io, and any OCI bearer-token registry, anonymous or authenticated. Credentials from env vars or a config file.
Four notifiers
Webhook, Discord, Telegram, and SMTP. Each one subscribable to just the events it cares about: available, succeeded, failed.
Single static binary
≤ 10 MB, no runtime dependencies. No JVM, no Go runtime, no 100 MB image sitting next to the containers it manages.
Opt-in by design
freshdock ignores every container until you set freshdock.enable=true. Enabled with no mode? It defaults to watch: detect and notify, never restart.
Labels, not config files
Drive it with Docker labels.
Opt a container in, pick a mode, and let the daemon do the rest. A deployment needs no mounted config file. Labels plus environment variables cover it.
# docker-compose.yml
services:
vaultwarden:
image: vaultwarden/server:1.32
labels:
- "freshdock.enable=true" # opt in
- "freshdock.mode=nightly" # check 04:00, recreate if newer
- "freshdock.notify=true" # if a notifier is configured
freshdock:
image: ghcr.io/turbootzz/freshdock:latest
command: ["run"]
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stoppedFull label vocabulary lives in the configuration reference ↗.
Update modes
One label sets the cadence.
Each container picks how and when it updates. The default is the safe one.
| mode | when it acts | what it does |
|---|---|---|
| live | every --interval (default 300s) | Pull and recreate on every new digest. |
| nightly | cron 0 4 * * * (04:00 daily) | Recreate if a newer image exists. |
| weekly | cron 0 4 * * 0 (04:00 Sunday) | Recreate if a newer image exists. |
| monthly | cron 0 4 1 * * (04:00 on the 1st) | Recreate if a newer image exists. |
| watch | every --interval | Report only: notify, never pull or restart. The default. |
| off | never | Ignored by the scheduler entirely. |
Cron syntax and timing details → scheduling docs ↗.
Coming from Watchtower?
Watchtower was archived on 17 December 2025 and ships an embedded Docker SDK (API 1.25) that no longer works with Docker Engine 29+. freshdock is a from-scratch, actively maintained replacement, and the concepts map closely.