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
uc caddy cert ls --machine machine-1
uc caddy cert ls -o jsonThis 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.comConfigure 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 shMachine 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.gzThe 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
EOFRun this command to add the socket dependency directly to /etc/systemd/system/uncloud.service:
sudo sed -i \
's/^After=network-online.target docker.service$/Requires=uncloud.socket\
After=network-online.target uncloud.socket docker.service/' \
/etc/systemd/system/uncloud.serviceStop 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.serviceAfter upgrading
Check your CLI and daemon versions:
uc version
uc machine lsChangelog
- f68c985 BREAKING CHANGE: move Uncloud API socket to /run/uncloud/api/uncloud.sock, activate it by systemd socket unit
- ad2e1a0 Ignore domain when there is no endpoint
- 81d36ed No need to call out to update anything, as set doesnt use uncloud dns
- 3fc1cdd Rebase and and generate protos again
- b28c458 Rebase and fix
- 5fb80e2 check validatity
- c58108a chore(.editorconfig): ignore formatting for release notes
- abb85f8 chore(AGENTS): do not emphasize the importance of table driven tests
- 37f817a chore(caddystorage): adjust log levels
- 4dae187 chore(caddystorage): move storage module code to a separate unlabs-dev/caddy-uncloud repo
- 6b41340 chore(cli): use cli.Cancelled when cancellikng the command to return non-zero exit code in all cases (#406)
- ebecf33 chore(dns): require minimum server version 0.21
- af27763 chore(dns): require minimum server version 0.21.0 for 'uc dns set' command
- f155525 chore(docs): update command outputs in Deploy demo app doc, add section to view logs
- 7964273 chore(experiments): go mod tidy
- 88dda43 chore(gitignore): ignore /research dir
- 6266e9e chore(nightly-build): prettier warning in description (#410)
- b9c54f1 chore(website): configure ingress Caddy as trusted proxy to forward client IPs
- e525bde chore(website): update discord members
- db55df6 chore: bump caddy Go pkg dependency to v2.11.4
- 3482eee chore: go mod tidy
- e81e130 chore: go mod tidy
- e9e7b3a chore: move legacy unused WG tunnel and client connector to experiment/wg
- d1fe23d docs
- 5d79529 docs(README): list cluster storage for certificates in features
- 87e99ae docs(caddy): new page Cluster storage for Caddy
- f78a8ca docs(caddy): regenerate CLI reference for 'caddy cert ls' command
- 4b9ea43 docs(cli): update machine init/add help with info about installing Docker and uncloudd
- c2ae11a docs(cluster): add section about SSH user permissions when connection to the cluster
- ac56754 docs(install): mise installation (#421)
- 3af9936 docs(install): update Debian repository domain (#413)
- a1957a1 docs(install): update machine init/add output that doesn't install corrosion systemd service
- 45d33d8 docs(runtime-templates): add 'Added in v0.21.0' note
- 9c21ae6 feat(caddy): CLI command to list certificates stored in the Uncloud cluster storage for Caddy
- 930e7ea feat(caddy): add ListCertificates method, refactor Caddy client layout (#31)
- 70de7b1 feat(caddy): add healthcheck to default Caddy spec and Compose deployment in docs
- bc09954 feat(caddy): mount uncloud API socket for storage module (#31)
- c7e0e36 feat(caddystorage): define CaddyStorage gRPC service API for distributed Caddy storage
- a24fc11 feat(caddystorage): generic namespace-scoped key-value storage using cluster table in Corrosion
- 7a88865 feat(caddystorage): implement the machine-local CaddyStorage gRPC service
- 9a40986 feat(caddystorage): init Caddy storage module backed by an Uncloud cluster
- c6d0371 feat(caddystorage): integrate CaddyStorage gRPC service in machine API
- 1e471d3 feat(caddystorage): lint
- f7be7c5 feat(caddystorage): minor logging formatting
- 992b819 feat(caddystorage): simplify CaddyStorage gRPC API to allow only one2one calls
- 6ab02f9 feat(caddystorage): simplify active locks tracking and cleanup
- 7c4fcde feat(cli): support env var UNCLOUD_DAEMON_VERSION to specify daemon version for "uc machine add/init" (#409)
- b7e224a feat(compose): support stdin_open and tty (#419)
- 7a7a313 feat(distlock): add gRPC Lease server that adapts a machine-local Store
- 3f86b3d feat(distlock): add integration tests for grpc transport
- 01426ca feat(distlock): add smoke e2e test for distributed lock (lease) in cluster
- 5a956e7 feat(distlock): declare Lease gRPC service API for distributed locks
- 43bf2ba feat(distlock): implement distributed Locker based on Redlock algorithm
- a5ab6e3 feat(distlock): implement in-memory lease store
- 1c29d4d feat(distlock): integrate distributed lease management into Machine API
- 613cd6e feat(distlock): refactor into a standalone package
- 9ee3ca1 feat(dns): allow setting an externally managed cluster domain
- 417e402 feat(dns): allow setting an externally managed cluster domain (uc dns set)
- 5c33e4b feat(runtime-templates): add support for runtime templates in bind mounts (#412)
- 0f6c032 feat(store): add WaitForStoreVersion API to wait for cluster store replication up to target version
- e4bd1ad feat(store): improve waiting for store replication to skip unavailable members
- cec3c75 feat: add uc dns set
- aaf6768 feat: validate remaining unsupported items of the support-matrix (#429)
- ace8cbf fix(caddyconfig): custom global Caddy config is preserved on regeneration,warn about last load error in 'uc caddy config' (fixes #412)
- 751ea97 fix(caddystorage): error formatting
- 351698c fix(cli): completion with direct connections (--connect, --context, --uncloud-config) (fixes #377)
- e4455e9 fix(cli): stop leaking terminal capability replies into the shell (#435)
- 5e01db5 fix(compose): remove unnecessary warning validating deploy.mode that is error
- dc721e5 fix(daemon): extend systemd service start timeout when pulling Docker image for corrosion service
- d36b28c fix(docs): version command instead of --version in docs (#408)
- e5f23a9 fix(install): allow to install uc CLI version <0.20 after the artifact renaming
- 50f8fbc fix(install): correctly compare installed nightly daemon version to upgrade to latest
- fa77edf fix(proxy): don't shutdown 'uc proxy' when a client connection aborts
- ae940c3 fix(test): flaky distributed lock tests by waiting for WG mesh to become ready
- 47a4a91 from main
- 25ca0a5 lint
- 54a7328 mise proto && make cli-docs
- e50c5fb refactor(api): replace map[string]uint64 with api.StoreVersion for store version handling
- 00d68d9 refactor(client): make ProxySingleMachineContext and ProxyMachinesContext package functions as well
- 0e53f50 refactor(client): speed up service list call (N -> 1 broadcast RPC)
- 8aedc2b refactor(proto): move protobuf generated API to the top-level api/pb package
- 842f796 refactor(store): unify logic and enhance logging for initial store sync (waitStoreSync)
- c65f352 test(connector): test UnixConnector reconnects after socket replacement
- d670d18 website: add new Hub page
- 054b3b8 website: change CTA link to getting started docs
- b3896ff website: minor
- 4ad4bce website: refine FAQ and form on hub page
- 4d76dd6 website: refine faq open source question, update og image
- e684795 website: refine styles for index and hub
- f8e6d1c website: send Hub early access form submission to posthog
- 0007f76 website: serve hub as /hub
- 08b24af website: split newsletter subscription into a separate section
- b99abb7 website: update docs social card and favicons
- 5b2823d website: update meta/og tags and images