Download Latest Version v0.20.0 source code.zip (3.4 MB)
Email in envelope

Get an email when there's a new version of Uncloud

Home / v0.20.0
Name Modified Size InfoDownloads / Week
Parent folder
checksums.txt 2026-06-26 540 Bytes
uc_linux_amd64.tar.gz 2026-06-26 34.0 MB
uc_linux_arm64.tar.gz 2026-06-26 30.7 MB
uc_macos_amd64.tar.gz 2026-06-26 34.0 MB
uc_macos_arm64.tar.gz 2026-06-26 31.5 MB
uncloudd_linux_amd64.tar.gz 2026-06-26 20.4 MB
uncloudd_linux_arm64.tar.gz 2026-06-26 18.6 MB
README.md 2026-06-26 15.5 kB
v0.20.0 source code.tar.gz 2026-06-26 3.1 MB
v0.20.0 source code.zip 2026-06-26 3.4 MB
Totals: 10 Items   175.6 MB 1

This release adds secrets for passing sensitive data to services, a new uc proxy command for port-forwarding, a Prometheus metrics endpoint, uc machine ls that surfaces each machine's OS, Docker, and daemon versions. Plus daemon self-upgrade on uc machine init/add, WireGuard MTU auto-detection, shell completion, and more.

⚠️ This is a breaking release. Both the uc CLI and the uncloudd daemon on every machine must be upgraded to 0.20. See Breaking changes below before you upgrade.

⚠️ Breaking changes

0.20 changes the internal gRPC API proxy format and migrates the cluster store to a new Corrosion version, so a mixed 0.19/0.20 cluster will not work. The built-in version check rejects requests between incompatible CLI and daemon versions, so upgrade everything together. See Upgrade to 0.20.0 for instructions.

  • Server-side gRPC proxy resolution (#247). API proxy targets (machines) are now resolved on the daemon instead of the CLI. This changes the request format on the wire, so old and new components can't talk to each other. Thanks to @jabr for the contribution ❤️
  • Corrosion now runs as a managed container (71da325). The Corrosion cluster store moved from a systemd unit to a Docker container and was upgraded to Corrosion v1 (2026.6.15). Existing data is migrated to the new format automatically on first daemon start. Auth is now enabled for local Corrosion API requests too (#110).
  • CLI artifact renamed uncloud_*uc_* (a5d73fe). Homebrew and the install script handle this for you. Only update your own scripts if you download the CLI archive directly. The daemon archive name (uncloudd_*) is unchanged.
  • Unregistry image proxy moved from port 5000 to 51500 (d36ff67). uc handles this automatically when pushing images. Only update your setup if you reach this proxy port directly in your own tooling.

Secrets support

PR: #403, docs: e01c8d3

You can now keep sensitive data like passwords, API tokens, and private keys out of your Compose file. Define a secret with the new x-command extension and reference it from a service's environment with secret://<name>. The command runs locally at deploy time and pulls the value from your password manager, cloud secrets store, or any CLI you already use.

:::yaml title="compose.yaml"
services:
  api:
    image: myapp:latest
    environment:
      DB_PASSWORD: secret://db_password

secrets:
  db_password:
    x-command: op read "op://prod/myapp/db_password"

The value never lands in your Compose file or git. See the new Secrets doc for supported sources, caveats, and examples.

Proxy a service port locally

PR: #384. Thanks to @miekg for the contribution ❤️

The new uc proxy command forwards a service port to a local port over the cluster network, similar to kubectl port-forward. This is handy for reaching an internal database or admin UI from your laptop without exposing them publicly.

Richer uc machine ls

Changes: 8aa0a96, ad43569, 1d5c717, 23d6b44

uc machine ls now shows the OS, KERNEL, ARCH, DOCKER, and VERSION (daemon) of each machine. You can spot version drift and outdated daemons at a glance.

:::shell
$ uc machine ls
NAME        STATE   ADDRESS         PUBLIC IP      WIREGUARD ENDPOINTS   OS                   KERNEL              ARCH    DOCKER   VERSION
machine-1   Up      10.210.0.1/24   203.0.113.10   203.0.113.10:51820    Debian 12.12         6.1.0-41-amd64      amd64   29.4.0   0.20.0
machine-2   Up      10.210.1.1/24   198.51.100.7   198.51.100.7:51820    Debian 12.5          6.1.0-18-amd64      amd64   26.0.0   0.20.0
machine-3   Up      10.210.2.1/24   -              192.0.2.44:51820      Ubuntu 22.04.5 LTS   6.8.0-1050-oracle   arm64   29.5.3   0.20.0

Pass -o json for machine-readable output to use in scripts.

Prometheus metrics

PR: #304. Thanks to @miekg for the contribution ❤️

Each daemon now serves the initial set of Prometheus metrics on http://<machine-ip>:51090/metrics, listening on the machine's internal IP. Point your scraper at it to monitor the cluster.

Daemon self-upgrade on machine init/add

Change: a26af3b

uc machine init and uc machine add now upgrade the installed daemon binary to the latest (or a specified --version) if the daemon was already installed on the machine.

Improvements

  • WireGuard now auto-detects the optimal interface MTU, with a new --wg-mtu flag to override it (0c3b8b1).
  • New --wg-port flag for uc machine init/add to customise the WireGuard listen port (#366). Thanks to @dasunsrule32 for the contribution ❤️
  • x-ports can bind to multiple host IP addresses given as a CIDR prefix (#358). Thanks to @miekg for the contribution ❤️
  • New uc version and uncloudd version commands that print full build information, replacing the --version flag (2f15915).
  • uc machine init/add installs curl on the remote machine if it's missing (#402).
  • New uc caddy logs alias for uc logs caddy (#381).
  • Shell/argument completion for the uc and ucind CLIs (machines, services, volumes) (#309, #344, #352). Thanks to @miekg for the contributions ❤️
  • Support rootless Docker locally when pushing images to the cluster (#347). Thanks to @tonyo for the contribution ❤️
  • The CLI strips ANSI colors from table output and skips interactive TUI elements when stdout is not a TTY (e3823c2, #386).

Bug fixes

  • Reject relative volume source paths in Compose with a clear error (#353). Thanks to @miekg for the contribution ❤️
  • Return a non-zero exit code when a uc command is cancelled by declining a confirmation prompt (#354).
  • Don't include outdated containers from a removed machine in the DNS and Caddy configs (07acb31).
  • Improve context cancellation and Corrosion resubscription handling during watch and sync operations (328d175, 83256b5, 99e1ae0, 5f07bc5).
  • Use a forked Bubble Tea that drains pending TTY input on shutdown (#286).

Upgrade to 0.20.0

Upgrade all machines and your local CLI to 0.20. Corrosion data migrates automatically on the first daemon restart.

[!IMPORTANT] On the first restart, each daemon pulls the Corrosion container image ghcr.io/unlabs-dev/corrosion:2026.6.15. Make sure your machines can reach ghcr.io, or pre-pull the image, otherwise the cluster store won't start.

Uncloud CLI locally

:::bash
# Homebrew (macOS, Linux)
brew upgrade uncloud

# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh

Machine daemon

Run the following commands on each machine:

:::bash
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.20.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 uncloud

After upgrading

On the first restart, the daemon migrates the Corrosion store and stops the legacy systemd service. A couple of leftovers need manual cleanup on each machine:

  • The old store is preserved at /var/lib/uncloud/corrosion.backup-<timestamp>. Once you've verified the cluster is healthy (uc machine ls), you can remove it:

bash sudo rm -rf /var/lib/uncloud/corrosion.backup-*

  • The legacy Corrosion systemd unit and binary are left in place because the daemon's sandbox doesn't have permission to delete them. Remove them manually:

bash sudo rm /etc/systemd/system/uncloud-corrosion.service /usr/local/bin/uncloud-corrosion sudo systemctl daemon-reload

Changelog

  • [c95136] BREAKING CHANGE: resolve gRPC API proxy targets (machines) on server instead of client, needs upgrade to v0.20 (#247)
  • [03ff4c] add netbird embed experiment
  • [eebb7b] add tsnet experiment
  • [e9762d] chore(api): add TODO to refactor Machine* domain types in api/client packages
  • [15e3e3] chore(grpc): update min client/server versions to 0.20.0
  • [0dd4bc] chore: build a use new corrosion image 2026.5.14 (pointing to v1.0.0 upstream) for ucind
  • [a040ce] chore: make retry log debug
  • [7f7d09] chore: make the reset machine prompt a bit clearer
  • [2aaaa7] chore: mod tidy
  • [e7a62f] chore: use 'lb_policy first' for uncloud.run to always route traffic to local replica
  • [73d515] cli: add -m/--machine flag completion for 'uc machine logs' (#352)
  • [2f717a] cli: do not use interactive TUI elements when control terminal (tty) is not available (fixes [#386])
  • [e3823c] cli: strip ANSI sequences (colors, styles) from table output when stdout is not a TTY
  • [247154] cli: use forked bubbletea with a fix to drain pending TTY input on shutdown (#286)
  • [7bac40] client: refactor ListImages to return an error per machine
  • [0c42a7] cluster: derive default machine name from its hostname when adding to cluster
  • [2f7618] corrosion: use Corrosion 2026.6.15 with fixed API authz for CLI query/exec commands
  • [e01c8d] docs(secrets): add new Concepts/Secrets doc about passing sensitive data to services, including x-command extension
  • [1d5c71] feat(cli): add JSON output format for 'uc machine ls', remove MACHINE ID column from table output
  • [8aa0a9] feat(machine ls): add ARCH, VERSION, DOCKER columns in the output table
  • [ad4356] feat(machine): add OS and kernel version information to machine info, show in 'machine ls'
  • [8b95db] feat(machine): sync machine arch, daemon and docker versions to store, sync machine info on schedule
  • [925695] feat(secrets): initial support for 'x-command' and 'driver: exec' secrets, referenced as secret://name in environment (#403)
  • [28c88e] feat(version): collect build-time metadata for uncloud binaries in version pkg
  • [2f1591] feat(version): replace --version with 'version' command to print build information for uc and uncloudd
  • [11df8e] feat: add 'uc caddy logs' alias for 'uc logs caddy' (#381)
  • [3586a3] feat: add 'uc proxy' command to proxy a service port to a local port (#384)
  • [24b81a] feat: add :51090/metrics endpoint with Prometheus metrics listening on machine IP (#304)
  • [269517] feat: add created_at/updated_at columns to cluster and machines store tables
  • [dd6807] feat: add shell completion for ucind CLI (#344)
  • [4a1221] feat: add uc CLI argument completion for machines, services, volumes (#309)
  • [1247f9] feat: allow to bind to multiple host IP addresses specified as CIDR prefix in x-ports (#358)
  • [424263] feat: allow to customise WireGuard listen port with --wg-port for machine init/add (#366)
  • [9424da] feat: enable auth for local requests to Corrosion API (resolves [#110])
  • [a26af3] feat: make machine init/add upgrade installed daemon binary to latest or specified version
  • [4503b1] feat: support rootless docker when pushing images to cluster (#347)
  • [35191c] fix(cluster): improve error handling on failed machine subscription in cluster store
  • [83256b] fix(corrosion): handle 404 errors during resubscription and stop retrying
  • [99e1ae] fix(corrosion): handle resubscription with from_change=0 that streams rows in new corrosion version
  • [e5b205] fix(install): install curl on machine init/add if missing (fixes [#402])
  • [5f07bc] fix(machine): correctly recreate machine in store if missing, improve context handling
  • [328d17] fix(machine): improve context cancellation handling during watch and sync operations
  • [07acb3] fix: do not include outdated containers from the removed machine in DNS and Caddy configs
  • [7616f1] fix: reject extra args in context commands (#376)
  • [5ecd09] fix: return non-exit code when uc commands cancelled by not confirming prompt (fixes [#354])
  • [7bb3cb] logs: stream corrosion logs with 'uc machine logs corrosion' from container instead of journal (fixes [#392])
  • [23d6b4] machine: make each machine the source of truth for its configuration, sync it to cluster store
  • [0c3b8b] network: add auto-detection of optimal MTU for WireGuard interface, --wg-mtu flag, set max_mtu for Corrosion to 1232
  • [a5d73f] refactor(cli): move cmd/uncloud to cmd/uc, change the artifact name uncloud_ -> uc_
  • [9ea30e] refactor(corrosion): reduce transport retry time for corrosion 10s->2s, move some logs to error level
  • [b08cee] refactor(machine): improve startup and shuitdown logic, shutdown corrosion in one place
  • [442b5c] refactor: cleanup Corrosion container on reset, move admin socket to runtime dir
  • [d23f1b] refactor: manually modernize Go (#349)
  • [9236aa] refactor: migrate to latest Corrosion version 2026.5.14 for ucind (compare versions vector for store sync)
  • [71da32] refactor: migrate to run Corrosion service as managed container instead of systemd unit, automatically migrate data to v1
  • [cccb86] ucind: add command aliases rm/delete (#396)
  • [18b411] ucind: use corrosion image tag 2026.6.15
  • [d36ff6] unregistry: change the listening port on each machine 5000 -> 51500
  • [cffa03] volumes: error when using relative volumes sources in compose (#353)
  • [f275a3] website: include js in the image
  • [fffc6a] website: landing revamp with deploy demo and testimonial
  • [e622c0] website: landing update: Multi-machine Docker Compose for production with terminal examples
  • [3841da] website: node instead of machine in header, cut subheader
Source: README.md, updated 2026-06-26