v0.21.0
This page mirrors the GitHub release, which also includes the full list of commits.
This release brings shared TLS certificate storage for Caddy, systemd socket activation, runtime templates, and a way to use your own cluster domain. It also adds a certificate inventory command, faster service listing, and fixes for proxying, container logs, and terminal output.
⚠️ Breaking changes
- The API socket moved from
/run/uncloud/uncloud.sockto/run/uncloud/api/uncloud.sock(f68c985). Update your custom tools and container mounts if you used the API socket directly. Both old and newucversions handle the socket move automatically.
Shared certificate storage for Caddy
Caddy module: caddy-uncloud, issue: #31
If you run Caddy on multiple machines behind a load balancer or a DNS record with multiple IPs, certificate issuance may not work correctly.
The new Uncloud storage module lets Caddy instances share certificates, private keys, and challenge tokens through the cluster store. Any instance can read the token to answer a challenge, and once one obtains a certificate, the others can use it too. Distributed locks coordinate issuance across machines.
Shared storage is opt-in for now. See Cluster storage for Caddy for more details.
Inspect Caddy certificates
The new uc caddy cert ls command lists certificates in Caddy's shared cluster storage. This is handy for checking which certificates have been issued and when they expire.
uc caddy cert ls
ID NAME ISSUER EXPIRES
c111e23615f7 dns.uncloud.run Let's Encrypt 2026-12-31 (2 months)
b5dcd2a03e1b nginx.2t5ex2.uncld.dev Let's Encrypt 2026-12-31 (2 months)
70707fd2fea2 test-staging.2t5ex2.uncld.dev Let's Encrypt (staging) 2026-12-31 (2 months)
c5f9301e1c06 uncloud.run Let's Encrypt 2026-12-31 (2 months)
uc caddy cert ls --machine machine-1
uc caddy cert ls -o json
This requires Caddy to first be deployed with cluster storage.
Systemd socket activation
Change: f68c985
Systemd now creates the Uncloud API socket and passes it to the daemon when it starts. The socket is available before Docker starts and stays in place across daemon restarts. This gives Caddy's cluster storage module and other extensions a stable API socket, including after a reboot.
Runtime templates for bind mounts
Change: 5c33e4b
You can now use per-container metadata in bind mount paths. Uncloud renders these Go templates on the destination machine just before creating each container, so every replica can get its own host directory:
services:
app:
image: app:latest
scale: 2
volumes:
- "/var/lib/app/{{.Container.Name}}:/data"
For now, runtime templates expose .Container.Name and work only in the host and container paths of bind mounts. They could easily be extended to other metadata fields and Compose attributes. Please share your use case on #431.
See Runtime templates for more details and examples.
Use your own cluster domain
PR: #365. Thanks to @miekg for the contribution ❤️
The new uc dns set command lets you use a domain you manage yourself as the default cluster domain for generated service hostnames:
uc dns set apps.example.com
Configure wildcard DNS records for *.apps.example.com with your DNS provider, pointing to machines running Caddy. New services published without an explicit hostname can then use addresses like web.apps.example.com. Uncloud doesn't create or manage those external records.
If your cluster already has a reserved *.uncld.dev domain, release that reservation with uc dns release first.
Improvements
uc lsnow collects services and containers with a single broadcast request instead of inspecting every service separately. This significantly speeds it up, especially when you have many services (0e53f50).- Compose now supports
stdin_openandtty(#419). Thanks to @miekg for the contribution ❤️ - Compose warns about more unsupported options, including external configs,
container_name, anddeploy.placement(#429). Thanks to @miekg for the contribution ❤️ uc machine init/addnow acceptUNCLOUD_DAEMON_VERSIONas an alternative to--version, useful for scripts and nightly setups (#409). Thanks to @tonyo for the contribution ❤️- Caddy deployments now have a healthcheck that queries the admin API, so the deployment waits for Caddy to load its config before treating a new container as healthy (70de7b1).
- The installation docs now include mise (#421).
Bug fixes
- Preserve custom global Caddy configuration during regeneration on Caddy restart.
uc caddy confignow warns when the last attempt to load the config failed (ace8cbf). - Keep
uc proxyrunning when an individual client disconnects or a forwarded connection fails. Connection errors now include more useful troubleshooting information (fa77edf). - Stream logs correctly from containers with an allocated TTY (#419).
- Stop terminal capability replies from leaking into the shell after CLI spinners finish (#435). Thanks to @tonyo for the contribution ❤️
- Fix shell completion when using
--connect,--context, or--uncloud-config(351698c). - Return a non-zero exit code consistently when a command is cancelled by declining a confirmation prompt (#406). Thanks to @miekg for the contribution ❤️
- Extend the systemd startup timeout while pulling the Corrosion image, allowing up to 5 minutes for a slow pull (dc721e5).
- Fix daemon version comparisons when upgrading from a nightly build to the latest stable release (50f8fbc).
- Avoid waiting on replication gaps from unavailable cluster members after the requested store versions have been reached (e4bd1ad).
Upgrade to v0.21.0
Upgrade your local CLI and the daemon on every machine. If you're upgrading from before v0.20.0, follow the v0.20.0 upgrade instructions first for the Corrosion migration.
Uncloud CLI locally
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | VERSION=0.21.0 sh
Machine daemon
Run the following commands over SSH on each machine to upgrade the daemon binary:
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.21.0/uncloudd_linux_${ARCH}.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
The following systemd unit updates are only needed on existing machines. New machines set up with uc machine init or uc machine add using v0.21.0 or later install these units automatically. Replacing the daemon binary alone on an existing machine doesn't install the new uncloud.socket unit or update uncloud.service.
Create /etc/systemd/system/uncloud.socket:
sudo tee /etc/systemd/system/uncloud.socket >/dev/null <<'EOF'
[Unit]
Description=Uncloud API socket
Before=docker.service
[Socket]
ListenStream=/run/uncloud/api/uncloud.sock
SocketUser=root
SocketGroup=uncloud
SocketMode=0660
DirectoryMode=0750
[Install]
WantedBy=sockets.target
EOF
Run this command to add the socket dependency directly to /etc/systemd/system/uncloud.service:
sudo sed -i \
's/^After=.*$/Requires=uncloud.socket\
After=network-online.target uncloud.socket docker.service/' \
/etc/systemd/system/uncloud.service
Stop the daemon before starting the socket unit, then reload systemd, enable the socket, and start the upgraded daemon:
sudo systemctl stop uncloud.service && \
sudo systemctl daemon-reload && \
sudo systemctl enable uncloud.socket && \
sudo systemctl start uncloud.socket && \
sudo systemctl start uncloud.service
After upgrading
Check your CLI and daemon versions:
uc version
uc machine ls