This release makes cluster storage for Caddy the default, adds service and container labels, a new uc service update command to change a service without recreating its containers, uc image rm to clean up images across machines, and DNS names for machines. It also brings fixes for logs, faster stop-first deployments, and a much calmer daemon on busy clusters.
⚠️ Heads-up before upgrading
uc caddy deploynow deploys the Uncloud Caddy image with cluster storage (22b1c68). Upgrading Uncloud doesn't touch your running Caddy. But the nextuc caddy deployswitches it to the new image and storage. Caddy doesn't copy certificates between storage backends, so it will reissue them unless you migrate them first. Read Upgrading from earlier versions before you redeploy Caddy.uc caddy deployrequires the 0.22.0 daemon on all machines. Upgrade the daemons first.- Machine names must be valid DNS labels (ce1c6bd). This means lowercase letters, numbers, and hyphens, up to 63 characters. The names
rrandnearestare reserved, and a name can't look like a machine ID. This applies when you add or rename a machine.
Cluster storage for Caddy by default
Change: 22b1c68, docs: Managing Caddy
In v0.21.0, we added an opt-in cluster storage for Caddy to share TLS certificates across machines. Now it's the default.
New clusters and uc caddy deploy now use the Uncloud Caddy image ghcr.io/unlabs-dev/caddy-uncloud. It's a Caddy build with the Uncloud storage module and a few popular modules, such as caddy-l4 and cloudflare for DNS challenges. So you can get a wildcard certificate with Cloudflare without building your own image.
uc caddy deploy also remembers the --image, --caddyfile, and --machine values you passed. You no longer need to repeat them every time you upgrade Caddy. Pass an empty value to reset a flag to its default:
# Deploy with a custom global config only on two machines.
uc caddy deploy --caddyfile global.Caddyfile --machine machine1,machine2
# Later, upgrade Caddy to the latest image. The custom config and machines are kept.
uc caddy deploy
# Go back to the default global config and deploy to all machines.
uc caddy deploy --caddyfile "" --machine ""If you have an existing cluster, follow Upgrading from earlier versions. It explains how to keep your certificates when switching to cluster storage, including for Caddy managed with Compose.
Service and container labels
Changes: 81f30aa, c1a7f84, 7b48ac5
You can now set labels in Compose. Uncloud supports both kinds of labels:
labelssets Docker labels on containers, for tools like backup agents, log shippers, or monitoring agents.deploy.labelssets service labels. They're stored with the service but not applied to containers. Use them for metadata about the service itself. Uncloud already uses them, for example, to mark the Caddy service managed byuc caddy deploy.
services:
db:
image: postgres:18
labels:
docker-volume-backup.stop-during-backup: "true"
deploy:
labels:
owner: alice@example.comuc run gets the matching -l/--label and --container-label flags. And uc inspect shows the labels of a service.
The deployment plan shows exactly which labels change. Service labels are updated in place, so changing them doesn't restart your containers:
~ update service web
│ ~ labels:
│ + env=prod
│ ~ owner=alice@example.com → bob@example.com
╰── ~ update container web/0f6df6593e1b on machine-1 (in place)
Changing container labels still recreates containers because Docker can't change labels on an existing container.
Update services in place
Uncloud now updates CPU and memory limits on running containers instead of recreating them. This works with uc deploy and the new uc service update command:
# Change the CPU and memory limits.
uc service update web --cpu 0.5 --memory 512m
# Add or change a service label and remove another one.
uc service update web --label-add env=prod --label-rm ownerThis is handy when a service is running out of memory and you want to bump the previously set limit right away without a restart.
uc run and uc service update also have a new --memory-reservation flag to set the minimum amount of memory reserved for a container.
Remove images from machines
Changes: e9eab32, 7c6d1be, 7e8736f.
Old images pile up quickly when you push and deploy often. The new uc image rm command removes them from all or selected machines. It shows a removal plan and asks for confirmation first:
# Remove a tag from all machines.
uc image rm myapp:old
# Remove all tags of an image.
uc image rm myapp
# Remove matching tags from two machines without confirmation.
uc image rm 'myapp:1.*' 'otherapp:*' -m machine1,machine2 --yesDon't worry about breaking anything. Images used by running or stopped containers can't be removed.
uc image ls now lists all tags and digest references of each image too, not just the first tag.
DNS names for machines
PR: #359, issue: #340. Thanks to @miekg for the contribution ❤️
Containers can now reach machines by name or ID in the internal m.internal zone. This is handy when a container needs to reach something running directly on a machine outside of Docker.
$ dig +short machine-1.m.internal
10.210.0.1
A query for m.internal returns the IPs of all machines. See Internal DNS for more details.
Improvements
- Debounce container change notifications in the daemon. On busy clusters, every health check or container change triggered a full Caddy and DNS config reconcile on every machine. This could burn a lot of CPU and even freeze small machines (#438). Thanks to @dasunsrule32 for the contribution ❤️
- Create the new container and pull its image before stopping the old one in stop-first deployments. This shortens downtime during the cutover (#420). Thanks to @nick-potts for the contribution ❤️
--sinceand--untillog filters now support days, for example,uc logs web --since 2d(5e26cfb).uc context shownow respects theUNCLOUD_CONTEXTenvironment variable (#444). Thanks to @miekg for the contribution ❤️
Bug fixes
- Resolve
secret://references in pre-deploy hook environment and don't replicate their values to the cluster store, same as for service environment (#424, #422). Thanks to @vky5 for the contribution ❤️ - Show all matching logs when
--sinceis set instead of only the last 100 lines per replica (409dc3b). - Use your local time zone when resolving dates and times in
--sinceand--untillog filters (5fa2368). - Disable colors in logs and
uc caddy configoutput when redirected to a file or whenNO_COLORis set (a1b6b31, 80d2a32). - Don't count stopped containers as removed in the deployment plan summary (6c7ddeb).
- Fix the default protocol for published ports in the
uc runhelp. It'stcp, nothttp(99c928f).
Upgrade to v0.22.0
Upgrade your local CLI and the daemon on every machine. If you're upgrading from v0.20.x or earlier, follow the v0.21.0 upgrade instructions first for the systemd unit changes.
Uncloud CLI locally
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | VERSION=0.22.0 shMachine daemon
Run the following commands over SSH on each machine to upgrade the daemon:
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.22.0/uncloudd_linux_${ARCH}.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloudAfter upgrading
Check your CLI and daemon versions:
uc version
uc machine lsThen switch Caddy to the new image and cluster storage when you're ready. Follow Upgrading from earlier versions to keep your certificates.
Changelog
- 20e2e97 chore(docs): update documentation generation commands and regenerate reference docs
- 24b4837 chore(mise): add mise release task to release with GoReleaser
- d66ec2b chore: bump mise to 2026.10.22 on CI
- b214d23 chore: migrate linting and formatting commands to mise tasks
- a2987d3 chore: minor comments in common proto
- d04772d docs(caddy): add warning about certificate migration when changing storage
- e347940 docs(caddy): bump caddy-uncloud image to 0.1.3
- 286d0e6 docs(caddy): update description for 'uc caddy cert ls' command
- e81115e docs(caddy): update example caddy config
- 68d2bd5 docs(caddy): update managing Caddy documentation for v0.22.0 features and upgrade instructions
- cef6916 docs(caddy): update references to custom global configuration in deployment instructions, typo fixes
- 6a64bdd docs(release): add release notes for v0.22.0
- d1d496c docs(releases): copy release notes from github to docs for v0.16.0-v0.21.0
- 22b1c68 feat(caddy): make cluster storage for Caddy default, remember 'uc caddy deploy' options
- 7ecf631 feat(daemon): debounce container change notifications to avoid reconcile storms (#438)
- 0cdf721 feat(dns): implement DNS names for machines in m.internal (#359)
- e9eab32 feat(images): add 'uc image rm' command to remove images from cluster machines
- 7c6d1be feat(images): implement RemoveImage gRPC API with extra protection for used images
- 7e8736f feat(images): include all tags and digest references when listing images
- c1a7f84 feat(labels): add support for service and container labels in uc run and inspect commands
- 7b48ac5 feat(labels): include detailed labels diff in service plan
- 81f30aa feat(labels): support service and container labels, update labels and cpu/memory in-place
- 5e26cfb feat(logs): add support for days unit (d) in --since/until filters for logs
- ce1c6bd feat(machine): add validation for machine names to accept only DNS labels
- ff6ac45 feat(update): add 'uc service update' command to update service configuration in place
- 8ddbe3c fix(compose): strip and resolve pre-deploy hook secrets like service env (#424)
- ba224bb fix(deploy): prepare replacement before stop-first cutover (#420)
- 99c928f fix(docs): correct published port protocol default for 'uc run'
- 76b04dd fix(labels): allow setting 'uncloud.' prefixed labels on services using a client but not CLI or Compose
- 78facdf fix(labels): format adding new labels in service plan with + modifier
- a1b6b31 fix(logs): implement color profiling for log output streams, e.g. disable color on redirect
- 5fa2368 fix(logs): resolve time ranges using client local time zone for logs commands
- 409dc3b fix(logs): show all matched logs when --since filter specified
- 6c7ddeb fix(plan): make stop operation formatting consistent and do not count it as removal in summary
- 80d2a32 fix: handle output redirect and NO_COLOR for 'uc caddy config'
- 8160c9b move deploy.operation package to operation
- bd695f6 refactor(grpc-proxy): use Metadata.Err() method to get upstream error for a broadcasted request
- 3351111 refactor(images): simplify image name handling when listing images
- 5d640b9 uc context show: take UNCLOUD_CONTEXT into consideration (#444)