What's Up, Doc(ker)!
Ain't I a stinker?
Intro and Musings
When it comes to Docker, there’s three main “legs of the stool” I’ve been concerned with and learning about solutions for. Despite my best efforts, I’m not a CI/CD automation guy. I just haven’t found the spark to really ignite my interest yet. So my solutions are a bit more traditional at this time. If I do have that “AH HA!” moment, I’ll cover that revelation here. As always, you’re welcome to comment and point out better ways to do things that maybe I didn’t realize/think about.
Management/deployment - Solved for now with Portainer
Updating containers - Solved for now with WUD, the point of this article :)
Backing Up Containers - this is on my list. Most of my docker hosts are on VMs,
which takes care of the backup inherently with Proxmox Backup Server. I do have one physical host for my ZWAVE container/Frigate so that needs to be taken care of.
WUD - What’s Up Docker
So what is WUD? It’s a container, purpose built to update other containers. There’s other solutions out there, like Watchtower but I keep hearing about WUD. I really do like a functional GUI for things and while it is very compose/stack heavy it does the job quite well. But man, are there nuances to this solution. And the documentation, while decent really glosses over some key points in my opinion, which makes the use more difficult. I actually had a false start about six months ago and dropped it after getting frustrated.
I moved to the free license of Business Edition for Portainer, which shows when there’s an update available but over times that process got very tedious so I picked WUD back up and figured it out.
My goal, by the end of this article is that you'll be able to effectively have WUD monitor, update (either automatically or manually) and notify you of changes. Before we get going though I think we need to talk about repos and registries. We’re going to handle our containers in a much different way than maybe you're used to.
The Repo, Man
Ok so what’s a repo/container registry?
Repo: source code, documentation, issue tracking, E.G, Github,Gitlab
Container Registry: Stores pre-built Docker images (binaries)
E.G. docker.io/syncthing/syncthing
There’s several registries out there, and let’s look at what that means. In your stack/compose it’s the prefix. For FOSS apps, these are the three I primarily see:
Docker Hub:
docker.io/or noneGHCR: ghcr.io/ (GitHub’s registry, free, integrated with repos)
LinuxServer.io: lscr.io/ (LinuxServer’s own registry, with repos on Github )
So for example some of my containers:
docker.io/jc21/nginx-proxy-manager
syncthing/syncthing
ghcr.io/lukegus/termix
See? I have two different prefixes since no prefix and docker.io are identical. A good rule of thumb is to use the prefix that’s in the compose example for their documentation.
From what I understand (and am probably not 100% right on) is that each one has a reason why devs use one over the other. Workflows and such. It’s all witchcraft to me.
Most projects use GitHub for documentation regardless of which registry hosts their images. Next question, why the hell do I care about all this?
Because, when it comes to updating dockers, we need to talk about “latest”. This subject turned out to be quite the rabbit hole.
Latest, This Just In
When we’re using our containers, the format is:
registry/container:tag
So for the most part, setting the tag to be “latest” is the best practice. This allows the developer to essentially control the version you run. They will set a tag of “latest” to whatever numbered version they prefer.
But, you can also set a tag to a specific release like:
ghcr.io/homarr-labs/homarr:v1.43.0 or
ghcr.io/rcourtman/pulse-docker-agent:4.26.2
Note: see one of those values has a “v” in it. We’ll come back to that.
I posit that if you’re not doing any kind of utility like WUD, latest is fine, but you may find you’re updating pretty frequently with no real feedback. Even in WUD with latest you won’t see what version, just the new SHA value. I’ve learned not to like that so I’ve largely moved to a specific version tag. I like seeing exactly where it’s going.
Note: When we set the tag like this and use WUD to update the container, we effectively “orphan” the compose/stack in term of versions. You can get well ahead of the compose/stack over time since WUD updates the container, not our deployment file. So if you go and update your compose/stack and redeploy you should update the number to what you're currently running. If you forget, WUD will definitely remind you. Example:
If I deploy this, 1.1.2 will replace 1.2.2. When WUD detects it, it will notify you’re out of date and you’ll feel silly. Better to make them match.
In comparison, latest can include breaking changes, deprecated features, config changes, updated dependencies, digest updates, etc.
Here’s an example.
I’m using a semver tag to specify the version. WUD shows me what kind of update it is, and old>new. I also have a template that will take me to the Github for the patch. We’ll cover that later.
Note: Semver: follows the format: MAJOR.MINOR.PATCH (e.g., 2.4.1)
Using a tag with version shows a nice progression.
If the tag was “latest” is it would not show a version progression, but just the SHA. Eh, I don’t like it.
So how do you know what tags are available? For most projects, look at their github under releases.
Now if you click on releases, you’ll also see a tag button.
Now remember the v? If the v is there, usually you’ll need it. If you try the v and it doesn’t pull the image, try it without it. I’ve ran into some projects where the semver format was a bit funky.
Now one thing you should absolutely do, is subscribe to all the projects you follow for releases updates at the very least.
This way, you’ll get convenient email alerts about the details.
USING WUD
Ok, let’s get to it. So this app is very powerful and the documentation is decent, but can be confusing. There is no GUI config, just a GUI result of the compose/stack config. Everything you can configure is in the compose/stack.
Let’s take a look at my WUD stack in stages. Examples will be on my Github.
Pretty much by the numbers here.
It’s the environment variables that matter here. You primarily have Registry, Watchers, and Triggers.
Registry:
There are a number of ones that are built in, these are where WUD will pull updates from.
For dockerhub, there are a limited amount of pulls you can do on an anonymous account per day. Make a free account, spin up an API key and use it in the compose/stack. The limit is far higher.
- WUD_REGISTRY_HUB_PUBLIC_LOGIN=
- WUD_REGISTRY_HUB_PUBLIC_PASSWORD=
Watchers:
This is how often WUD polls for updates, don’t leave this as default you’ll burn through your pull requests even on an authenticated account. I set mine for every six hours.
- WUD_WATCHER_LOCAL_CRON=0 */6 * * *
Triggers: This is the fun stuff.
- WUD_TRIGGER_DOCKER_UPDATE_AUTO=false
Set to true to autoupdate, but set to false and it provides the button for manual actions.
- WUD_TRIGGER_DOCKER_UPDATE_PRUNE=true
Will auto delete the old container on update.
- WUD_TRIGGER_APPRISE
This is to setup our notifications with Apprise. Lots of other options, this is what I use. We’ll cover this soon.
LABELS
Now if we leave these at defaults, WUD will work but it’ll be messy. Let’s use labels to tell WUD exactly what to do. Now, we will place these labels on every container including WUD itself.
wud.tag.include: ^v?\d+\.\d+\.\d+$
So this is regex, and should work for most use cases and only alert of updates in standard semver context and not sha digests and other stuff. If you know there’s an update and WUD isn’t catching it you may need to tweak this. This should also account for the option of “v” at the beginning of a tag.
wud.link.template: https://github.com/getwud/wud/releases/tag/$${major}.$${minor}.$${patch}
This provides the link in the WUD output for release information. Change to the link of the container’s tag page if it exists. Not a requirement, just convenient.
Now for the containers, you just need the labels. It’s a pain to go back and retroactively edit all the containers for labels and tags, but I think it’s worth it.
Now there’s some oddballs like Exalidraw that doesn’t have anything other than latest so I went another route. That should keep me from pulling down weird intermittent releases.
wud.tag.include: ^sha-[a-f0-9]+$
Notifications
Okay, so. Lots of options here. I use Apprise to send to Home Assistant.
I cover that here:
Home Assistant Notifications With Node Red
I also cover setting up Apprise here:
Notifications for Audio Bookshelf Using Apprise and Home Assistant
Now the neat thing here, as I found out with Uptime Kuma is that I can use the exact same notify URL that I use for Home Assistant anywhere! In hind sight of course you can, but give me break. :)
So an example trigger for this:
- WUD_TRIGGER_APPRISE_MYNOTIFY_URL=http://10.0.0.x:32768
- WUD_TRIGGER_APPRISE_MYNOTIFY_CONFIG=abs
Set the IP/Port for Apprise and and the config path. Every app does this part a little different by the way. When this is deployed, you’ll get an entry in the GUI along with a very handy test button.
Let’s fire off a test alert. If it doesn’t work make sure you check your WUD logs.
Ok, it works but that’s hella wordy. I want to shorten it, and add some identifying information so I know which WUD box it’s coming from and provide something unique to grab in Node Red so I can send the message to my phone.
Note that I have “WUD Prod” and a bunch of variables, let’s see what it looks like now.
To Node Red!
Here’s my current setup for Audio Bookshelf/Kuma
I’m going to slap a debug node onto the Apprise node and fire off a notification.
Ok I need to make a new switch node, as I’m pulling from payload.event.service_data.title, not message.
Now, I’m going to make a new action node with some custom json. I used Claude to help with this.
See: Not A Programmer.
My flows now look like:
Let’s fire off an alert…
Oh, and here’s my oddball. *shrug*
Conclusion
Ok, that was a lot. I hope by the end of this you have a working configuration that works for you. Now this is the way I do it. There is much more functionality to be had if that’s your goal. Take a look at the documentation and go nuts!
Until next time.



































Couldn't agree more. That documentation struggle with WUD is real. I'd love to hear more about those nuances you mensioned. Your insight here is super helpful!