# WUD watches your containers across four orchestrators, then can replace them

> getwud/wud is a container update monitor and automation tool written in TypeScript. It discovers workloads through watchers for Docker, Swarm, Kubernetes and Nomad, compares what the registry offers against what is running by version and by digest, and then either notifies you through one of more than thirty triggers or recreates the container itself. The same design that makes it useful is what makes its permissions worth reading.

**getwud/wud** — Keep your containers up-to-date!

- Repository: https://github.com/getwud/wud
- Website: https://getwud.app/
- Stars: 3,987 · Forks: 154
- Language: TypeScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/getwud-wud

## The quick start mounts the Docker socket and hands out a fixed password

Everything about the security model is visible in the first command the page asks you to run.

```bash
docker run -d \
  --name wud \
  -p 3000:3000 \
  -e WUD_AUTH_ADMIN_USER="admin" \
  -e WUD_AUTH_ADMIN_PASSWORD="MySecurePassword123" \
  -v /var/run/docker.sock:/var/run/docker.sock \
  getwud/wud:latest
```

Two of those lines matter. The socket bind gives the container control of the Docker daemon on the host, which in practice is control of every container on that host, and the tool needs it because that is how it discovers workloads and recreates them. The port publish exposes the web UI, the REST API and the metrics endpoint on port 3000 of the host. The credentials are passed as environment variables, and the page then tells you to open the UI on localhost and log in as `admin` with the password from the command, so the documented first run ships with a known account. Authentication itself is not the weak point: there are roles for admin, read write and read only, database backed user management, personal API tokens, and single sign on through OpenID Connect with Keycloak, Authentik or Authelia named as examples, or local accounts instead.

## One-shot mode turns the monitor into a pipeline gate

There is a second mode, and it is the one that fits CI. With `WUD_RUN_MODE` set to `oneshot`, the container runs as a stateless headless tool with no web server and no database file, which is a different contract from the long running service.

```bash
# Run a single scan and print container status as JSON
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e WUD_RUN_MODE=oneshot \
  getwud/wud:latest watch

# Gate CI/CD pipelines: exit with code 1 if at least one update is available
docker run --rm \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e WUD_RUN_MODE=oneshot \
  getwud/wud:latest watch --update-available --fail-on-update
```

The second invocation is the interesting one: it turns a scan into a pipeline condition by exiting non zero when an update exists, so the decision about whether to rebuild lives in your pipeline rather than in the tool. The socket is still bind mounted, even though nothing is being served on a port. The page points at separate documentation for the full flag list, for NDJSON output and for cron examples, which means the two commands above are the short form of a larger surface, not the whole of it.

## Watchers decide what is scanned, and only Docker is on by default

Discovery is separated by orchestrator, and each entry in the table carries the credential it needs. Docker covers a local socket, a remote engine over TLS and Compose setups, and it is the one marked built in and active by default, which is why the quick start needs no watcher configuration at all. Docker Swarm adds services, stacks, and both replicated and global workloads over the same socket or remote TCP connection. Kubernetes covers Deployments, StatefulSets, DaemonSets and CronJobs, authenticated either through in-cluster RBAC or a kubeconfig. Nomad covers jobs of the service, batch and system types along with their task groups, over an HTTP API with an ACL token. The engine diagram in the README makes the direction explicit: watchers scan, the engine compares versions and digests, registries are inspected, triggers execute. That separation is why a mixed estate is supported at all, and it is also why the configuration surface is large, since four orchestrators means four sets of credentials to keep current.

## Registries are enumerated next to the credential each one expects

The registry table is the most concrete part of the documentation because it pairs every service with how you authenticate to it. Docker Hub takes anonymous access, a token or a password. GitHub Container Registry takes a personal access token. AWS ECR takes IAM keys or IAM roles, and Google Container Registry and Artifact Registry take a service account key as JSON. Docker Hardened Images at `dhi.io` takes a token or a password. The list goes on past the part the repository's own page shows, which ends partway into the Azure Container Registry row, and the feature list above it names the rest of the set: Quay, GitLab, Gitea, Forgejo, Codeberg, the LinuxServer registry, and any custom or self hosted OCI registry. That last clause is the one that matters for a private setup, since an internal registry does not have to be one of the named vendors to be watched, and the version and digest comparison in the engine works the same way against it.

## Thirty triggers mix a message with a container replacement

The trigger list is where a notification tool becomes an automation tool, and the two categories are interleaved in the same list of thirty plus entries. The notification side covers Discord, Matrix, Mattermost, Zulip, Telegram, Slack, Signal, WhatsApp, Bark, Prowl, Home Assistant, Gotify, Ntfy, Pushover, Apprise, plain webhooks, SMTP email, and the observability and paging services Opsgenie, PagerDuty and Uptime Kuma. The pipeline side covers GitHub Actions, GitLab CI, shell scripts, Kafka, AMQP with RabbitMQ, and NATS. The automation side covers native updaters for Docker, Docker Compose and Nomad, which pull the new image and recreate the container. Those last three are the ones to think about: a trigger that posts a message is reversible, while a trigger that recreates a workload changes what is running on your host, on the same socket mount that one-shot mode already needed for a read only scan.

## What counts as an update is a policy you write, not a default

The engine compares two things, versions and digests, and the version half is configurable in four different ways. You can target a semver level, meaning major, minor or patch, so that a rebuilt tag with the same version but a new digest can be told apart from an actual version bump. You can match a custom regular expression instead, which is how you handle registries whose tags are dates or commit hashes. You can pin a version, which turns the monitor into an alert that something drifted from your choice. And you can write include and exclude rules over tags, which is the mechanism that keeps a floating tag or a nightly build from looking like an update on every scan. The README describes this as flexible versioning strategies and points at a separate configuration page for triggers. Nothing in the visible material states a default policy, so which of the four applies on a fresh install is not something the repository answers.

## The image is a three stage Node 24 build whose healthcheck can stand down

The Dockerfile in the repository describes more about the deployment than the page does. There are three stages on node:24-alpine. The app stage installs python3, make and g++ with apk before running `npm ci` with dev dependencies included and optional dependencies omitted, then builds and prunes dev packages away. The UI stage builds from `$BUILDPLATFORM` with the same npm flags and does not install those extra build tools. The release stage copies the app's `node_modules`, its `dist` and its manifest, copies the UI's built output into a `ui` directory, adds tzdata, openssl, curl, bash and libstdc++, and installs a shell entrypoint. Version information is passed in as a build argument defaulting to `unknown`, so an image built outside the release pipeline reports an unknown version. The healthcheck curls `/health` every 30 seconds with a 5 second timeout, and it deliberately steps aside when `WUD_SERVER_ENABLED` is unset or false, because in one-shot mode there is no server to ask.

## Observability is a metrics endpoint and a directory of dashboards

Monitoring WUD is a first class path in the repository rather than an afterthought. The feature list promises a built in Prometheus endpoint at `/metrics` and pre-built Grafana dashboards, and the root of the repository carries a `grafana` directory next to `app`, `ui`, `test`, `e2e`, `ui-e2e`, `scripts` and `website`. The web UI is described as a dashboard for inspecting container status and triggering manual update checks, with a full REST API for querying the same data, which means the update decision is reachable from three directions: the browser, an HTTP client, and metrics scraping. Around the code sit the agent and editor configuration files, an `AGENTS.md`, a `CLAUDE.md`, a `GEMINI.md`, a `.cursorrules` directory and `.openhands`, so the repository is set up to be worked on by tools as well as by people. Releases move quickly for a project of this size: 9.2.0 on 2026-09-25, 9.2.1 on 2026-09-30, 9.3.0 on 2026-10-04.

## Conclusion

WUD is worth running if you have more containers than you can afford to audit by hand and you want a single place that says which image has moved, with a policy for when that counts as an update. Treat the permission model as part of the feature set rather than an afterthought, because the documented quick start mounts the Docker socket into the container and the trigger list includes updaters that recreate running workloads, which together are close to root on the host. Before you deploy it, check four things. Which watcher you actually need, since Docker is active by default and the others need their own configuration. Which trigger class you allow, separating a notification from an updater. Whether the version policy is written down, since targeting a semver level, a custom regular expression, a pinned version or include and exclude rules give very different update behaviour on the same registry. And whether you replace the documented admin password before the first start, since the quick start ships a fixed one and the tool exposes a web UI, a REST API and a Prometheus endpoint on port 3000.

## FAQ

### What does WUD stand for and what does it do?

WUD is short for What's Up Docker, a container update monitoring and automation tool. It scans your container environments, detects image updates across public and private registries, performs semantic version analysis, and then alerts you or triggers automatic container updates.

### Which orchestrators can WUD watch?

Standalone Docker daemons including Compose setups, Docker Swarm clusters, native Kubernetes clusters with Deployments, StatefulSets, DaemonSets and CronJobs, and HashiCorp Nomad clusters with service, batch and system jobs. Only the Docker watcher is active by default; the rest need their own configuration and credentials.

### Can WUD be used to fail a CI pipeline when an update exists?

Yes. In one-shot mode the container runs headless with no web server and no database file, and running watch with the update-available and fail-on-update flags makes it exit with code 1 when at least one update is available. Documentation covers further flags, NDJSON output and cron examples.

### Does WUD need the Docker socket mounted into its container?

The documented quick start bind mounts /var/run/docker.sock into the container, and the one-shot examples do the same. That socket is how watchers discover running containers and how the Docker, Compose and Nomad updaters recreate them, so the same mount covers both scanning and changing workloads.

### How does WUD decide that an image has a new version?

The engine compares versions and digests, and the version rule is configurable four ways: target a semver level of major, minor or patch, match a custom regular expression, pin a version, or define include and exclude tag rules. The repository's own page does not state which policy applies on a fresh install.

## Sources

- [getwud/wud on GitHub](https://github.com/getwud/wud)
- [License: MIT](https://github.com/getwud/wud/blob/main/LICENSE)
- [Project website](https://getwud.app/)
- [README](https://github.com/getwud/wud/blob/main/README.md)
- [Releases](https://github.com/getwud/wud/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/getwud-wud
