Skip to content

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.

install
$cargo install freshdock

See it first (read-only)

$freshdock check
Example freshdock check status table. Read-only, never mutates state
containerimagemodecurrent digestlatest digestupdate?
nimbusturbootzz/nimbuslivesha256:7be033sha256:7be033no
vaultwardenvaultwarden/server:1.32livesha256:1c4d0esha256:9af2b1yes
jellyfinlscr.io/linuxserver/jellyfinweeklysha256:33aa9bsha256:8e9142yes
caddycaddy:2.8nightlysha256:9f2a1csha256:9f2a1cno
postgrespostgres:16nightlysha256:b21e7apinned (no check)-
backupsghcr.io/me/backups:latestnightlysha256:e0a3f1auth required?
update available up to date pinned / 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.

See how each piece works →

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
# 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-stopped

Full 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.

freshdock update modes and what each one does
modewhen it actswhat it does
liveevery --interval (default 300s)Pull and recreate on every new digest.
nightlycron 0 4 * * * (04:00 daily)Recreate if a newer image exists.
weeklycron 0 4 * * 0 (04:00 Sunday)Recreate if a newer image exists.
monthlycron 0 4 1 * * (04:00 on the 1st)Recreate if a newer image exists.
watchevery --intervalReport only: notify, never pull or restart. The default.
offneverIgnored 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.

See the comparison
Latest release: v1.2.1 (16 Jun 2026) Read the changelog →