Self-hosted service
mag37/dockcheck avatar
mag37/dockcheck

dockcheck: a Bash script that checks Docker image updates before it pulls anything

CLI tool to automate docker image updates. Interactive or unattended with notifications, image backups, autoprune, no pre-pulling and more.

2,504 stars95 forksShellGPL-3.0

At a glance

What is it?
dockcheck is a GPL-3.0 shell script for homelab and self-hosted Docker hosts that compares local image digests against registries, then optionally pulls, recreates and prunes. Its value is the separation between checking and pulling, and its cost is a dependency chain of jq, regctl and a Bash 4.3 floor.
Who is it for?
dockcheck fits operators of a handful to a few dozen Docker or Compose containers who want a script they can read end to end, run from cron or systemd, and audit before it touches anything. It does not fit clusters, Kubernetes, or anyone unwilling to install jq and regctl and keep them current.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 36 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap between 'update available' and 'update applied'

A Docker host that runs twenty containers has no built-in answer to a simple question: which of these images is actually behind its tag? The daemon tracks what it pulled, not what the registry currently serves. Watchtower-style tools close that gap by acting, which means the check and the pull happen in the same breath and you find out about a bad image after your containers are already recreated. dockcheck inverts the order. The README describes it as a CLI tool to automate docker image updates or notify when updates are available, and the second half of that sentence is the interesting half. Running ./dockcheck.sh with no flags prints two lists, containers on the latest version and containers with updates available, then asks which numbers to act on. Nothing is pulled until you answer. The audience is the self-hosted and homelab operator who wants the update decision to stay a decision, at least on the first pass. The topics on the repository (bash, docker, homelab, self-hosted) match that reading.

Registry comparison without pre-pulling

The mechanism rests on regclient's regctl binary plus jq. dockcheck queries the registry for the current manifest of each container's image and compares it against what the local daemon holds, rather than pulling the image to find out whether it changed. That is why the README can state that the Docker Hub pull limit is not an issue for checks, only for actual pulls. A host checking fifty containers consumes no pull quota; it consumes registry API calls, which is a different budget with different failure modes. The timeout flag exists for exactly this: -t N sets a per-container timeout for registry checkups, with 10 seconds as the default. On a slow link or a registry having a bad day, that default is the knob you turn first. The check phase runs asynchronously through xargs, and -x N sets the maximum number of subprocesses, defaulting to 1, with 0 to disable and 32 or more described as tested. The default of a single subprocess is a deliberate conservative choice: serial checks are slower but produce ordered, readable output and do not hammer a registry. Raising -x is the performance lever, and the README gives no number for how much it helps, so treat it as something to measure on your own host rather than a documented speedup.

Getting it installed and doing a dry run

The install instruction is to download the script into a directory in PATH, with ~/.local/ suggested, and the README points at the repository for the exact copy command. Dependencies are explicit: a running Docker with compose either standalone or as a plugin, a Bash-compatible shell of at least 4.3, POSIX xargs (from findutils) to enable async, jq, and regclient/regctl. The script prompts to install jq through the package manager or to download a static binary, and prompts to download regctl if it is not in PATH or the working directory. regctl requires amd64 or arm64, and the README links a workaround for other architectures. Once installed, the first command to run is the help text, which doubles as the flag reference: ./dockcheck.sh -h. From there the safe sequence is ./dockcheck.sh -n for a check with no updates, then ./dockcheck.sh -N to simulate updates purely to test notifications, then a real interactive run. Configuration lives in dockcheck.config, sourced before CLI arguments so that flags always take precedence, a behaviour the v0.8.3 changelog calls out as a fix. If a config file is interfering, -C temporarily falls back to defaults and ignores dockcheck.config entirely. That is a cleaner escape hatch than editing the file and forgetting to revert it.

Selecting, excluding and the -e versus -E distinction

dockcheck's filtering model is worth reading carefully because two flags look alike and behave differently. -e X excludes containers by comma-separated name, meaning they drop out of the check entirely. -E X excludes containers from applying updates while still checking them, so you keep visibility but the update path refuses to touch them. The v0.8.1 changelog notes that interactive output around -E was clarified, and v0.8.2 fixed the exclusion message so it only prints when an excluded container actually has an update. If you pin a database container to a known-good tag and want to know when upstream moves without ever auto-updating it, -E is the flag you want, not -e. Selection also runs the other way: -l includes only containers carrying a specific label, which the README says to look up in the readme itself. Names can also be passed positionally as a comma-separated include list, as in the example dockcheck.sh -y -x 10 -d 10 -e nextcloud,heimdall. The -d N flag is the most opinionated one: it only updates to images that are at least N days old, listing anything too recent with a + prefix and its age. The README warns this is twice as slow, which makes sense, since age cannot be determined from a manifest alone and requires additional registry metadata lookups.

Backups, pruning and the flags that bite

Image backups are opt-in through -b N, which enables backups and sets how many days to keep before pruning, and it overrides -p auto-prune. -B lists current backups and exits, which is the command to run when you are not sure what disk the script has been consuming. Auto-prune of dangling images is -p, and it is ignored whenever -b is used, so you cannot accidentally run both policies at once. The dangerous flags are the ones that remove the human step. -a or -y applies updates automatically without interaction. -u allows automatic self-updates, which the help text annotates with a caution: it will pull new code and autorun it. That is a meaningful trust statement. A script that can replace itself and execute the replacement is convenient on a homelab box and unacceptable on anything with a change-control process. The v0.8.2 changelog adds that self-updates are blocked entirely when running containerized, both the script and the image, which closes an obvious footgun for the Docker Compose deployment added in v0.8.1. Also worth noting: -f forces a stop and start of the whole stack after an update and warns it restarts once for every updated container in the stack, so on a large compose file it multiplies restarts. -F narrows the recreation to the specific container instead of the whole stack, which is the flag to reach for in a master-compose layout where one file holds unrelated services.

Where it stops being the right tool

The dependency on regctl's amd64 and arm64 support is a hard boundary. On any other architecture you are relying on a workaround the README links rather than a supported path, and that is a poor foundation for an unattended cron job. The Bash 4.3 floor rules out stock macOS bash without installing a newer one, and the xargs dependency means a minimal container image without findutils loses async checking, which is a silent degradation rather than an error. The Podman story is also a fork, not a flag: the README points Podman users at sudo-kraken/podcheck. If you run Podman, you are adopting a different project with a different maintainer, and dockcheck's changelog tells you nothing about it. The larger limitation is scope. dockcheck operates on a single Docker host and its compose stacks. It has no notion of a cluster, no rollout strategy, no health-gated rollback, and no coordination between nodes. If a container comes back unhealthy after an update, dockcheck's job is finished; recovery is your problem. The -s flag, which includes stopped containers and returns them to a stopped state after recreation, hints at how much of the lifecycle logic is bookkeeping rather than orchestration. And because the script recreates containers rather than orchestrating them, an update that changes required environment variables or volume paths will recreate a container that fails to start, with the old image still on disk only if you enabled -b.

How it differs from Watchtower and from Renovate

Watchtower is the closest comparison and the difference is architectural, not cosmetic. Watchtower runs as a long-lived container with its own polling loop and applies updates on its own schedule; the update is the default behaviour and notification is the side channel. dockcheck is a script you invoke, from a terminal or from cron or a systemd timer, and its default behaviour is to report and ask. You can make it behave like Watchtower with -a or -y, but you are choosing that explicitly, and the check-only mode remains available for the same binary. That matters for the Docker Hub pull limit: a Watchtower-style loop that pulls to compare consumes quota every cycle, while dockcheck's check phase, per the README, does not. The second comparison is Renovate, which works at the repository level, opening pull requests against your compose files or manifests so the change goes through review and version control before any host sees it. dockcheck never touches your repository; it mutates the running host. If your compose files are in Git and you want updates to arrive as diffs you can review, Renovate addresses that and dockcheck does not. If your compose files are hand-edited on the box and you want the box to tell you what drifted, dockcheck is the shorter path. Neither is a superset of the other.

Maintenance cost, licensing and what to check before trusting it

dockcheck is GPL-3.0, stated in the README badge and the repository metadata. For internal homelab use the practical effect is that you can run and modify it freely. If you redistribute it or ship a modified version, GPL-3.0's copyleft terms attach to what you distribute, and if that matters to your organisation, that is a question for counsel rather than for this article. The dependency licences differ and are worth separating: regctl is Apache-2.0 per the README, jq carries its own licence, and the script itself is GPL-3.0. Maintenance cost is mostly the dependency chain. regctl is a separate binary that the script will prompt to download if missing, and a stale regctl is the most likely cause of a check phase that misreports or fails, since the registry comparison runs through it. jq is stable and widely packaged. The script itself moves quickly: three releases between 2026-07-21 and 2026-08-04, mostly fixes to restart handling, config sourcing order and output conditions. That cadence is a good sign for responsiveness and a mild warning for anyone who pins a version and expects it to sit still. Pinning is easy here because it is a single script, but -u defeats pinning by design, so do not enable it if you want a frozen version. The concrete thing to verify first is the check phase on your own registries: run ./dockcheck.sh -n with your real container set and watch for timeouts, then adjust -t and -x before you trust an unattended run. After that, -N confirms your notification path end to end without pulling a single image.

Editorial conclusion

dockcheck fits operators of a handful to a few dozen Docker or Compose containers who want a script they can read end to end, run from cron or systemd, and audit before it touches anything. It does not fit clusters, Kubernetes, or anyone unwilling to install jq and regctl and keep them current. Before adopting it, run ./dockcheck.sh -n on a non-production host and confirm the check phase completes without registry timeouts, then run -N to verify your notification path fires, and only then enable -a or -y.

Official sources

  1. License: GPL-3.0
  2. mag37/dockcheck on GitHub
  3. Project website
  4. README
  5. Releases
Community notes

Community notes