Releases: psviderski/uncloud
v0.12.1
Caddy config loading
After upgrading both CLI and machine daemons to v0.12.1, you can redeploy Caddy without using the --watch
flag.
The Caddy config is now loaded automatically by the machine daemon via the Caddy Admin API. This allows to log errors not overwrite the Caddyfile
on disk if the config is invalid. uc caddy config
should now return the latest config that was successfully loaded into Caddy.
Unique context name for new clusters
When creating a new cluster, if the default context name default
is already taken, a unique name like default-1
, default-2
, etc. will be generated automatically.
Changelog
- 8358343 chore: Add GH bug report template
- 9963f9d chore: Update bug template
- 5baa808 chore: load Caddy config via admin API instead of watching Caddyfile change on fs
- d25864e feat: automatically generate a unique 'default-N' context name for new cluster (fixes #113)
- ec2787c fix: Handle implicit relative path for config
- 51ba3c7 fix: landing navbar on mobile
- 97bdb8e fix: skip validation for user-defined Caddy configs if caddy not running locally
- 7b88b8b fix: write generated Caddyfile to disk only if succesfully loaded into local Caddy (means valid)
v0.12.0
What's new
✨ Custom Caddy configuration (per-service and global)
For advanced routing and behavior, use x-caddy
instead of x-ports
in Compose files. It allows you to provide custom Caddy configuration for a service in Caddyfile format. See Ingress & HTTPS docs for details.

- Use templates like
{{upstreams 8000}}
to automatically insert healthy container IPs forreverse_proxy
. - Deploy global Caddy config with
uc caddy deploy --caddyfile
orx-caddy
in a Compose file forcaddy
service. - Invalid Caddy configs are skipped instead of breaking everything.
- View the complete generated Caddyfile served by Caddy with
uc caddy config
:

New documentation
- Concepts > Ingress & HTTPS: How Caddy works as a reverse proxy, publishing services, custom Caddy config, and managing
caddy
service. - CLI reference: Automatically generated CLI reference docs.
Improvements
- Caddy now uses Caddyfile format instead of JSON which is more human-friendly.
- Caddy keeps its data between restarts (certificates are preserved) using a persistent volume.
Upgrade to 0.12.0
caddy
service to be able to use the new custom Caddy configs. This update will also lose all the previously issued TLS certificates because a persistent data wasn't used before.
Please follow Deploying or updating Caddy.
Uncloud CLI locally
To upgrade the Uncloud CLI (uc
) locally:
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
Machine daemon
To upgrade the Uncloud daemon on your machines, run the following commands on each machine:
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.12.0/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.12.0/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
Changelog
- e99e769 chore: add Caddy gRPC service to retrieve Caddyfile config from machines
- c01365b chore: add header to generated Caddyfile that it's autogenerated
- 3cda5cc chore: caddy client to get caddy config
- 813c397 chore: change reverse_proxy upstreams from 'to' to the directive arguments
- 48dc1dd chore: delete unused image digest resolver
- 81f4e3a chore: fix mockery for linux in .mise.lock
- 455174c chore: generate sites in Caddyfile from x-ports alongside caddy.json
- 11949ee chore: include validation errors for user-defined Caddy configs as a comment in Caddyfile
- 8bf9fc0 chore: introduce mockery for generating mocks, generate for CaddyfileValidator
- db60a81 chore: lint
- 066d411 chore: parse Created time on container with CreatedTime
- 93fef88 chore: refactor Caddyfile generator to accept a validator
- 75fdbaf chore: relax ports+Caddy spec validation to allow host mode ports
- b437659 chore: update comments in generated Caddyfile
- 290e6db docs(ingress): Publishing service and Managing Caddy
- 9f5ca9a feat: add 'uc caddy config' command to show the current Caddyfile
- 3a6eef4 feat: add --caddyfile flag to 'uc caddy deploy' and 'uc run' commands
- 0397086 feat: concatenate custom Caddy configs for services into final Caddyfile (no upstream interpolation)
- b046b78 feat: migrate Caddy to generated Caddyfile, mount persistent data volume
- 5cc005a feat: validate and append custom per-service Caddy configs to generated Caddyfile
- 0107363 fix: allow host mode x-ports with x-caddy in compose
- 5a1e61c fix: broken links to completions docs in CLI reference
- 6476908 fix: format for --publish flag
- ff213e7 fix: unmarshaling of ServiceSpec in ServiceContainer struct
v0.11.1
Private registry support
Fixed authentication when pulling images from private container registries. uc deploy
or uc run
will try to retrieve the registry credentials from your local Docker config (~/.docker/config.json
), including the configured credentials store. If the credentials are not found locally, the uncloudd
daemon on the remote machine will try to retrieve the credentials from its own Docker config (/root/.docker/config.json
).
In order to configure the credentials for your private registries, you can:
- (Recommended) Run
docker login
locally (where you runuc
) if you have Docker CLI installed. - Run
docker login
on your remote machines underroot
user or usingsudo docker login
so that the credentials are stored in the root-owned Docker config.
Upgrade to 0.11.1
sudo sed -i 's/ProtectHome=true/ProtectHome=read-only/' /etc/systemd/system/uncloud.service
sudo systemctl daemon-reload
sudo systemctl restart uncloud
Newly provisioned machines will have the correct configuration automatically.
Uncloud CLI locally
To upgrade the Uncloud CLI (uc
) locally:
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
Machine daemon
To upgrade the Uncloud daemon on your machines, run the following commands on each machine:
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.11.1/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.11.1/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
Changelog
- 12c0781 chore: add Caddy config to ServiceSpec, load x-caddy to it
- 4be8339 chore: generate a minimal Caddyfile with verify handler alongside caddy.json
- 9186d31 chore: go mod tidy
- ec73f9e chore: handle x-caddy: path/to/Caddyfile to read Caddy config in compose from file
- 8dd69b4 chore: refactor docker gRPC server to use docker service for inspecting and listing containers
- 4cc1e55 chore: store ServiceContainer (includes service spec) instead of Container in Corrosion store
- dd7bc6c chore: trim spaces for x-caddy, diff Caddy configs when comparing service specs
- 5d3f1fe chore: x-caddy extension type in compose
- c67127f feat: Add basic LLM instruction files
- 1ce3e62 fix: use local and remote Docker credentials to pull image from private registry
v0.11.0
What's new
Force service redeployment
Added --recreate
flag to the deploy
command to force container recreation even if their configuration and image haven't changed. This is particularly useful when you've pushed updated images directly to machines using tools like unregistry, and need to redeploy services to use the updated images without changing their tags. Or just want to test the redeployment process without changing the service configuration.

Reset machine on initialisation
machine init
and machine add
commands now ask you whether to reset the machine if they detect that the machine is already a cluster member. This helps when:
- Repurposing a machine that was previously part of a different Uncloud cluster
- Recovering from a failed or incomplete previous installation
- Starting fresh after testing or experimentation with Uncloud

Default restart policy
Changed the default restart policy for service containers from always
to unless-stopped
. This allows you to stop containers manually and have them remain stopped even after a system reboot or Docker restart.
Upgrade to 0.11.0
Uncloud CLI locally
To upgrade the Uncloud CLI (uc
) locally:
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
Machine daemon
To upgrade the Uncloud daemon on your machines, run the following commands on each machine:
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.11.0/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.11.0/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
Changelog
v0.10.1
Changelog
- fc0bf4a chore: lint
- 6cc0611 chore: meaningful error message when passwordless sudo required on machine provisioning
- 2c02139 fix: add
ssh_key_path
for connections in uncloud config only when using SSH key explicitly (not SSH agent) - 6c244bb fix: do not try to reset machine when removing unreachable machine
v0.10.0
This release introduces new machine management commands (rm
, rename
, update
) and extends Docker Compose support.
Also, includes important bug fixes for machines using UFW firewall and race conditions during cluster initialisation.
✨ We also launched a new blog and published our first post: How to connect Docker containers across multiple hosts with WireGuard
Upgrade to 0.10.0
Uncloud CLI locally
To upgrade the Uncloud CLI (uc
) locally:
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
Machine daemon
To upgrade the Uncloud daemon on your machines, run the following commands on each machine:
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.10.0/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.10.0/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
New features
Machine management
- Added
uc machine rm
command to remove machines from the cluster and reset them to a clean state. - Added
uc machine rename
command to rename machines. - Added
uc machine update
command to update a public IP address of a machine used for registering machines in Uncloud DNS service (uc dns
).
Docker Compose enhancements
- Support for
x-machines
placement constraints in Compose files, allowing you to control which machines services are deployed to (#90). - Containers with
pull_policy: always
are now properly recreated on deployment to ensure the latest image is used (#100).
Bug fixes
- Fixed machine initialisation when UFW firewall is active by properly allowing IPv6 management traffic (#65).
- Resolved race condition during cluster initialisation by waiting for the corrosion service to be ready with schema applied (#89).
- Fixed race condition that could occur during Docker network creation.
Improvements
- Disabled masquerading for container IPs when communicating via WireGuard overlay network.
Contributors
Special thanks to our contributors for this release:
- @OrlovEvgeny - Multiple features including machine management and placement constraints
- @tonyo - Linting configuration and Docker Compose enhancements
Changelog
- da3634b E2E tests use repeated strings for test data where constants add no value (#97)
- 2d73b54 blog: proof read WireGuard overlay post, update blog description tag
- 9b48003 blog: set diagram as og image for wireguard overlay post
- 05d0078 chore: Enable more linters
- 1e750cc chore: add Blog links on landing page, fix header on small screens
- 614212a chore: clean up custom iptables chains on machine reset
- 0bd42b2 chore: do not allow to remove a machine the client is connected to, add --no-reset flag
- b39585d chore: do not masquerade container IPs when communicating via WG mesh
- a7273c8 chore: fix wide svg rendering on landing
- 8beb9e2 chore: lint
- f613d3c chore: reformat code
- 2acfafe chore: regenerate proto
- 3faaac4 chore: run machine tests in parallel
- 9a88e91 chore: simplify cluster controller initialisation, prepare for reset
- b24b55c chore: update api.MachineClient interface
- 1b61304 chore: use a new uncancelled context for stopping corrosion service
- a54555c feat(deploy): Recreate container when pull_policy set to Always (#100)
- 053d730 feat: Basic linting config
- 2714587 feat: add RemoveMachine API endpoint to remove a machine from the cluster
- fea7edc feat: add support for standard compose ports directive (#95)
- 6fb07db feat: follow-up compose 'ports' support: use ingress mode by default (closes #81)
- 2c3bea6 feat: impl of functionality for renaming and updating machines (#91)
- 7a6c5bf feat: machine Reset endpoint with asynchronous resource and data cleanup
- 65f5a71 feat: machine rm command to remove a machine from the cluster and reset it
- 31cd4c7 feat: support x-machines placement constraints in compose files (#90)
- 35d0a90 fix: add machine with UFW firewall (allow ipv6 management traffic) fixes #65
- ff7bb25 fix: custom version handling in install.sh script
- 3ab708a fix: graceful machine shutdown when not initialised
- 0c2ff49 fix: log message deleting iptables chain
- 492a0af fix: migration script for uncloud Docker network to be compatible with Docker 28.2.0+
- 10bbe9f fix: prevent race condition with Docker network creation (#89)
- 4166474 fix: race on cluster init by waiting for corrosion service to become ready with schema applied
v0.9.0
Uncloud 0.9.0 Release Notes
This release includes critical Docker 28.2.0+ compatibility fixes, sets better defaults for container logging, and includes minor housekeeping improvements.
Upgrade to 0.9.0
Uncloud CLI locally
To upgrade the Uncloud CLI (uc
) locally:
# Homebrew (macOS, Linux)
brew upgrade uncloud
# Install script (macOS, Linux)
curl -fsS https://get.uncloud.run/install.sh | sh
Machine daemon
To upgrade the Uncloud daemon on your machines, run the following commands on each machine:
# AMD64
curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.9.0/uncloudd_linux_amd64.tar.gz
# ARM64
# curl -fsSL -o uncloudd.tar.gz https://github.com/psviderski/uncloud/releases/download/v0.9.0/uncloudd_linux_arm64.tar.gz
tar -xf uncloudd.tar.gz
sudo install uncloudd /usr/local/bin/uncloudd
rm uncloudd uncloudd.tar.gz
sudo systemctl restart uncloud
Bug fixes
Docker 28.2.0+ compatibility
Fixed connectivity between containers across machines with Docker 28.2.0 and later versions. The fix only works for new clusters and new machines added to existing clusters.
Starting with Docker 28.2.0 (moby/moby#49832), Docker networks must explicitly specify from which host interfaces they allow direct routing to their containers. This is done by specifying the com.docker.network.bridge.trusted_host_interfaces
option when creating the network. We now create the uncloud
Docker network with com.docker.network.bridge.trusted_host_interfaces=uncloud
option to allow the WireGuard mesh network (uncloud
interface) to route traffic to uncloud-managed containers.
If you upgraded Docker to 28.2.0 or a later version on an existing machine, you need to manually recreate the uncloud
Docker network with the com.docker.network.bridge.trusted_host_interfaces=uncloud
option on it to fix cross-machine communication. We prepared the migration script that will do that for you.
curl -O https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/migrate_docker_28.2.0.sh
chmod +x migrate_docker_28.2.0.sh
sudo ./migrate_docker_28.2.0.sh
rm migrate_docker_28.2.0.sh
New features
- The default log driver for all service containers is set to
local
, which preserves 100MB of log messages per container and uses automatic compression to reduce the size on disk. There is no longer a need to manually specify the log driver limits to prevent logs from filling up the disk space. Contributed by @zasdaym. - Added unofficial Debian package repository maintained by @dariogriffo.
Improvements
- Uncloud-managed volumes are labeled with
uncloud.managed
to make it easier to identify and manage them. - Anonymous volumes are now properly cleaned up when removing service containers.
Developer Experience
- Protobuf compiler and Go plugins are now managed through
mise
, using consistent versions across all development environments. - Added CI checks for protobuf generation on multiple platforms.
- Added
.editorconfig
for consistent code formatting across different editors.
Contributors
Special thanks to our contributors for this release:
- @dariogriffo - Debian package repository
- @tonyo - Multiple improvements including
.editorconfig
and build fixes - @krishna-santosh - Documentation fixes
- @zasdaym - Default log driver implementation
Changelog
- f75afa0 Merge branch 'pasha/machine-rm'
- 638f320 build: Install protobuf tools via mise (#77)
- 2f35ac6 chore: Add .editorconfig
- 8e0a24e chore: add donate button in README
- e3e39dd chore: create FUNDING.yml
- 0f38b12 chore: fail 'machine rm' as not fully implemented
- a73cbfd chore: hide incomplete machine rm command from help output
- 2b4da1e chore: remove anonymous volumes created by service containers when removing
them - 4c77fe2 chore: tidy up
- 5c8beb8 chore: tidy up go.mod, remove toolchain
- 44549c0 feat: Label new volumes as managed by uncloud (#79)
- 535b91f feat: add stub for Reset method in machine API
- 59b96cc feat: init 'machine rm' command that outputs service containers that will be
removed - be8b4f0 feat: remove containers on machine before removing it
- 1abadae feat: set default log driver for service containers to 'local' (#83)
- 3b1ce42 fix(docs): add missing word to complete the sentence (#82)
- 26f34df fix: Improve output for build operations
- 89fb9ef fix: Use GITHUB_TOKEN to increase the rate limit for mise action
- 55773e9 fix: allow direct routing from WireGuard mesh to containers for Docker
28.2.0+ - 3b89af4 fix: e2e compose build test on macOS with Docker Desktop
v0.8.0
This release introduces build & push capabilities for Compose deployments, enables passive health checks for upstreams in Caddy reverse proxy, minor bug fixes and improvements.
We also launched:
New features
Initial build & push support (still experimenting) ✨
- New
uc build
command to build service images fromDockerfile
andbuild:
configuration in Compose files - Integrated build step in
uc deploy
automatically builds and pushes an image to the registry specified inimage:
before deployment - Use
--no-build
flag to skip building when deploying
Caddy reverse proxy improvements
- Enabled passive health checks to automatically detect unhealthy upstreams
- Added automatic retry logic (3 retries) for failed requests to gracefully handle temporary unavailable upstreams
- Logging enabled by default for better observability
Documentation
- Launched a new documentation website at docs.uncloud.run with a Getting started guide.
- Documentation itself is deployed using Uncloud across multiple machines (dogfooding FTW!) See the
compose.yaml
file if curious.
User experience
- Default SSH key path is now set to
~/.ssh/id_ed25519
- Added
m
alias for themachine
command
Bug Fixes
- Fixed Caddy deployment after adding new machine by using cluster client instead of machine client (#65)
Testing & CI
- Added GitHub Actions workflow for automated Go tests
- Enhanced e2e tests with build & push verification
Contributors
Thanks to @tonyo for the build & push RFC and implementation, test improvements, and the make install-dev
helper!
Changelog
- 624caf0 chore(docs): init overview page
- 2a0d31c chore: Helper make target to install protobuf/grpc plugins
- 6a4e63d chore: add Discord to landing, remove crossed out Kubernetes
- 6f9ac1f chore: add Docker image for docs and Uncloud Compose deployment (dogfooding!)
- ae04dea chore: add Docs to website navbar and footer, add other resources to footer
- f1abbbe chore: add discord and X badges to README
- 23dfe45 chore: add docs badge to github README
- d2dd5e3 chore: add inspiration & acknowledgements section to README
- 7edd8f2 chore: add m alias for machine command
- 8f00e00 chore: add social links in the footer
- 2bfcce7 chore: add uncloud-docs deploy from compose to demo section in README
- f49ec46 chore: bring terminal on landing back, update hero, move demo to bottom
- 365a5fc chore: build multiarch images for corrosion and ucind to support e2e tests on amd64
- 3aa8fea chore: configure docs custom styles, init intro page
- dfa6e00 chore: cross over kubernetes on landing hero
- 735e360 chore: delete unused ucind-image-push target in Makefile
- ff1a8fb chore: fix comment
- 59f6fa7 chore: init docusaurus docs
- fd3facb chore: minor README change
- eec7286 chore: minor README change
- bd03bb9 chore: minor README change
- 1ffe9ac chore: minor README rearrangement
- 4075f85 chore: minor website update
- fa3d992 chore: period
- 7699b53 chore: refine links
- 683ad22 chore: remove extra [FLAGS] from volume commands help, add SERVICE for inspect
- 0d820bc chore: replace github discussions with discord in subscribe section
- 009c0e1 chore: scale docs service to 2 replicas in different regions
- 1ec5184 chore: self-hosting focused front page (first screen)
- 4590a51 chore: set default ssh key path to ~/.ssh/id_ed25519 and handle home expansion
- a5fe9fb chore: update -p flag help for run command
- 8b66a11 chore: update hero
- a7d8afb chore: update value section wording
- c34542a chore: update website title
- 971b21d feat: Implement basic build & push capabilities for services (#68)
- fc61e2f feat: enable passive health checks and upstream retries in Caddy
- 4df1820 fix(doc): Tiny fixes
- 88db1cb fix: hero svg on safari
- 12c86f1 fix: use existing cluster client when deploying caddy after adding new machine #65
v0.7.2
Bug fixes
- Fixed
uc caddy deploy
to check latest Caddy image only when not explicitly specified - Fixed service name validation to properly enforce RFC 1123 label format (1-63 characters, lowercase letters, numbers, and dashes only; must start and end with a letter or number)
Changelog
- 469d6fa Fix: restrict validation to RFC1123 label name
- 11c2e64 Merge pull request #58 from Tova-Rozovsky/valid_DNS
- 5f21424 added validition for service name
- f7b079c chore: collapse how it works section in readme
- e35e69b fix: check latest Caddy image only if not specified for 'uc caddy deploy'
- bb97537 fix: format error message
- 9f4b817 valid service name
v0.7.1
This minor release improves iptables firewall management:
- Introduce a new
UNCLOUD-INPUT
iptables chain that manages rules for the Uncloud needs. - Allow DNS queries from Uncloud containers to access the embedded DNS server in case the host has restrictive
INPUT
rules. - Allow WireGuard traffic to the machine on
51820/udp
port.
Changelog
- 3648187 chore: allow DNS queries from Uncloud containers to the embedded DNS server
- 9334630 chore: clarify zero-downtime deployments feature
- cc86c86 chore: rearrange features in README
- 6e32627 chore: set up UNCLOUD-INPUT iptables chain and allow WireGuard traffic to the machine
- 2963436 chore: update available features in README