MCPcopy
hub / github.com/psviderski/uncloud

github.com/psviderski/uncloud @v0.20.0 sqlite

repository ↗ · DeepWiki ↗ · release v0.20.0 ↗
2,683 symbols 8,690 edges 312 files 837 documented · 31%
README

Uncloud logo Uncloud logo

▸ Deploy and scale containerised apps across servers without Swarm or Kubernetes overhead ◂

<a href="https://uncloud.run/docs"><img src="https://img.shields.io/badge/Docs-blue.svg?style=for-the-badge&logo=gitbook&logoColor=white" alt="Documentation"></a>
<a href="https://discord.gg/eR35KQJhPu"><img src="https://img.shields.io/badge/discord-5865F2.svg?style=for-the-badge&logo=discord&logoColor=white" alt="Join Discord"></a>
<a href="https://x.com/psviderski"><img src="https://img.shields.io/badge/follow-black?style=for-the-badge&logo=X&logoColor=while" alt="Follow on X"></a>
<a href="https://github.com/sponsors/psviderski"><img src="https://img.shields.io/badge/Donate-EA4AAA.svg?style=for-the-badge&logo=githubsponsors&logoColor=white" alt="Donate"></a>

Uncloud is a lightweight clustering and container orchestration tool that lets you deploy and manage web apps across cloud VMs and bare metal with minimised cluster management overhead. It creates a secure WireGuard mesh network between your Docker hosts and provides automatic service discovery, load balancing, ingress with HTTPS, and simple CLI commands to manage your apps.

Unlike traditional orchestrators, there's no central control plane and quorum to maintain. Each machine maintains a synchronised copy of the cluster state through peer-to-peer communication, keeping cluster operations functional even if some machines go offline.

Uncloud is the solution for developers who want the flexibility of self-hosted infrastructure without the operational complexity of Kubernetes.

✨ Features

  • Deploy anywhere: Combine cloud VMs, dedicated servers, and bare metal into a unified computing environment, regardless of location or provider.
  • Docker Compose: Familiar Docker Compose format for defining services and volumes. No need to learn a new bespoke DSL.
  • Zero-downtime deployments: Rolling updates without service interruption. Automatic rollback on failure is coming soon.
  • Unregistry integration: Build and push your Docker images directly to your machines without an external registry. It will transfer only the missing layers, making it fast and efficient.
  • Service discovery: Built-in DNS server resolves service names to container IPs.
  • Persistent storage: Run stateful services with Docker volumes managed across machines.
  • Zero-config private network: Automatic WireGuard mesh with peer discovery and NAT traversal. Containers get unique IPs for direct cross-machine communication.
  • No control plane: Fully decentralised design eliminates single points of failure and reduces operational overhead.
  • Imperative over declarative: Favoring imperative operations over state reconciliation simplifies both the mental model and troubleshooting.
  • Managed DNS: Automatic DNS records *.xxxxxx.uncld.dev for services with public access via managed Uncloud DNS service.
  • Automatic HTTPS: Built-in Caddy reverse proxy handles TLS certificate provisioning and renewal using Let's Encrypt.
  • Docker-like CLI: Familiar commands for managing both infrastructure and applications.
  • Remote management: Control your entire infrastructure through SSH access to any single machine in the cluster.

🎬 Quick demo

The screenshot below demonstrates how we use Uncloud to deploy https://uncloud.run website to 2 remote machines from the compose.yaml file on the local machine.

It exposes the container port 8000/tcp as HTTPS on uncloud.run domain, served by the Caddy reverse proxy on the remote machines. All managed by Uncloud.

Uncloud compose deployment demo

Here is a more advanced use case. Deploy a highly available web app with automatic HTTPS across multiple regions and on-premises in just a couple minutes.

Uncloud demo

📚 Want more examples? Check out the uncloud-recipes repository for community recipes and templates for deploying popular services on Uncloud.

💫 Why Uncloud?

Modern cloud platforms like Heroku and Render offer amazing developer experiences but at a premium price. Traditional container orchestrators like Kubernetes provide power and flexibility but require significant operational expertise. I believe there's a sweet spot in between — a pragmatic solution for the majority of us who aren't running at Google scale. You should be able to:

  • Own your infrastructure and data: Whether driven by costs, compliance, or flexibility, run applications on any combination of cloud VMs and personal hardware while controlling your data and maintaining the cloud-like experience you love.
  • Stay simple as you grow: Start with a single machine and add more whenever you need without changing your workflow. No worrying about highly-available control planes or complex YAML configurations.
  • Build with proven primitives: Get production-grade networking, deployment primitives, service discovery, load balancing, and ingress with HTTPS out of the box without becoming a distributed systems expert.
  • Support sustainable computing 🌿: Minimise system overhead to maximise resources available for your applications.

Uncloud's goal is to make deployment and management of containerised applications feel as seamless as using a cloud platform, whether you're running on a $5 VPS, a spare Mac mini, or a rack of bare metal servers.

🚀 Quick start

  1. Install Uncloud CLI:

```bash brew install psviderski/tap/uncloud

# or using curl (macOS/Linux) curl -fsS https://get.uncloud.run/install.sh | sh ```

See Installation for more options.

There's also a nightly rolling release available if you want to try the latest features and fixes before they're included in an official release.

  1. Initialise your first machine:

bash uc machine init root@your-server-ip

  1. Deploy your app from a Docker image and publish its container port 8000 as HTTPS using app.example.com domain:

bash uc run -p app.example.com:8000/https image/my-app

  1. Create a DNS A record in your DNS provider (Cloudflare, Namecheap, etc.) that points app.example.com to your server's IP address. Allow a few minutes for DNS propagation.

That's it! Your app is now running and accessible at https://app.example.com ✨

  1. Clean up when you're done:

bash uc ls # Copy the service name from the output and run the rm command: uc rm my-app-name

If you want to fully uninstall Uncloud on a machine, run:

bash uncloud-uninstall

View the Documentation for more information.

⚙️ How it works

Check out the design document to understand Uncloud's design philosophy and goals.

Here is a diagram of an Uncloud multi-provider cluster of 3 machines:

Diagram: multi-provider cluster of 3 machines

Peek under the hood to see what happens when you run certain commands.

When you initialise a new cluster on a machine:

$ uc machine init --name oracle-vm ubuntu@152.67.101.197

Downloading Uncloud install script: https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/install.sh
⏳ Running Uncloud install script...
✓ Docker is already installed.
⏳ Installing Docker...
...
✓ Docker installed successfully.
✓ Linux user and group 'uncloud' created.
✓ Linux user 'ubuntu' added to group 'uncloud'.
⏳ Installing Uncloud binaries...
⏳ Downloading uncloudd binary: https://github.com/psviderski/uncloud/releases/latest/download/uncloudd_linux_arm64.tar.gz
✓ uncloudd binary installed: /usr/local/bin/uncloudd
⏳ Downloading uninstall script: https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/uninstall.sh
✓ uncloud-uninstall script installed: /usr/local/bin/uncloud-uninstall
✓ Systemd unit file created: /etc/systemd/system/uncloud.service
Created symlink /etc/systemd/system/multi-user.target.wants/uncloud.service → /etc/systemd/system/uncloud.service.
⏳ Downloading uncloud-corrosion binary: https://github.com/psviderski/corrosion/releases/latest/download/corrosion-aarch64-unknown-linux-gnu.tar.gz
✓ uncloud-corrosion binary installed: /usr/local/bin/uncloud-corrosion
✓ Systemd unit file created: /etc/systemd/system/uncloud-corrosion.service
⏳ Starting Uncloud machine daemon (uncloud.service)...
✓ Uncloud machine daemon started.
✓ Uncloud installed on the machine successfully! 🎉
Cluster "default" initialised with machine "oracle-vm"
Waiting for the machine to be ready...

Reserved cluster domain: xuw3xd.cluster.uncloud.run
[+] Deploying service caddy 1/1
 ✔ Container caddy-c47x on oracle-vm  Started                                                                                                                                          0.9s

Updating cluster domain records in Uncloud DNS to point to machines running caddy service...
[+] Verifying internet access to caddy service 1/1
 ✔ Machine oracle-vm (152.67.101.197)  Reachable                                                                                                                                       0.1s

DNS records updated to use only the internet-reachable machines running caddy service:
  *.xuw3xd.cluster.uncloud.run  A → 152.67.101.197
  1. The CLI SSHs into the machine and installs Docker, the uncloudd machine daemon and corrosion service, managed by systemd.
  2. Generates a unique WireGuard key pair, allocates a dedicated subnet 10.210.0.0/24 for the machine and its containers, and configures uncloudd accordingly. All subsequent communication happens with uncloudd through its gRPC API over SSH.
  3. Configures and starts corrosion, a CRDT-based distributed SQLite database to share cluster state between machines.
  4. Creates a Docker bridge network connected to the WireGuard interface.
  5. This machine becomes an entry point for the newly created cluster which is stored in the cluster config under ~/.config/uncloud on your local machine.

When you add another machine:

$ uc machine add --name hetzner-server root@5.223.45.199
Downloading Uncloud install script: https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/install.sh
⏳ Running Uncloud install script...
✓ Docker is already installed.
✓ Linux user and group 'uncloud' created.
⏳ Installing Uncloud binaries...
⏳ Downloading uncloudd binary: https://github.com/psviderski/uncloud/releases/latest/download/uncloudd_linux_amd64.tar.gz
✓ uncloudd binary installed: /usr/local/bin/uncloudd
⏳ Downloading uninstall script: https://raw.githubusercontent.com/psviderski/uncloud/refs/heads/main/scripts/uninstall.sh
✓ uncloud-uninstall script installed: /usr/local/bin/uncloud-uninstall
✓ Systemd unit file created: /etc/systemd/system/uncloud.service
Created symlink /etc/systemd/system/multi-user.target.wants/uncloud.service → /etc/systemd/system/uncloud.service.
⏳ Downloading uncloud-corrosion binary: https://github.com/psviderski/corrosion/releases/latest/download/corrosion-x86_64-unknown-linux-gnu.tar.gz
✓ uncloud-corrosion binary installed: /usr/local/bin/uncloud-corrosion
✓ Systemd unit file created: /etc/systemd/system/uncloud-corrosion.service
⏳ Starting Uncloud machine daemon (uncloud.service)...
✓ Uncloud machine daemon started.
✓ Uncloud installed on the machine successfully! 🎉
Machine "hetzner-server" added to cluster
Waiting for the machine to be ready...

[+] Deploying service caddy 1/1
 ✔ Container caddy-d36c on hetzner-server  Started                                                                                                                                     1.0s

Updating cluster domain records in Uncloud DNS to point to machines running caddy service...
[+] Verifying internet access to caddy service 2/2
 ✔ Machine hetzner-server (5.223.45.199)  Reachable                                                                                                                                    0.2s
 ✔ Machine oracle-vm (152.67.101.197)     Reachable                                                                                                                                    0.1s

DNS records updated to use only the internet-reachable machines running caddy service:
  *.xuw3xd.cluster.uncloud.run  A → 152.67.101.197, 5.223.45.199

$ uc machine ls
NAME             STATE   ADDRESS         PUBLIC IP        WIREGUARD ENDPOINTS
oracle-vm        Up      10.210.0.1/24   152.67.101.197   10.0.0.95:51820, 152.67.101.197:51820
hetzner-server   Up      10.210.1.1/24   5.223.45.199     5.223.45.199:51820, [2a01:4ff:2f0:128b::1]:51820
  1. The second machine gets provisioned just like the first. A non-root SSH user will need sudo access.
  2. Allocates a new subnet 10.210.1.0/24 for the second machine and its containers.
  3. Registers the second machine in the cluster state and exchanges WireGuard keys with the first machine.
  4. Both machines establish a WireGuard tunnel between each ot

Extension points exported contracts — how you extend this code

Operation (Interface)
Operation represents a single atomic operation in a deployment process. Operations can be composed to form complex deplo [8 …
pkg/client/deploy/operation/operation.go
Store (Interface)
Store is the interface required by MachineMapper to access the cluster store. [6 implementers]
internal/machine/api/proxy/mapper.go
ImageClient (Interface)
(no doc) [5 implementers]
pkg/api/client.go
Client (Interface)
The dns package code is based on https://github.com/acorn-io/runtime/blob/main/pkg/dns. Client handles interactions with [1 …
internal/dns/client.go
Executor (Interface)
(no doc) [2 implementers]
internal/sshexec/executor.go
APIClientOption (FuncType)
(no doc)
internal/corrosion/client.go
Connector (Interface)
Connector is an interface for establishing a connection to the cluster. [5 implementers]
pkg/client/client.go
CaddyfileValidator (Interface)
CaddyfileValidator is an interface for validating Caddyfile configurations. [15 implementers]
internal/machine/caddyconfig/caddyfile.go

Core symbols most depended-on inside this repo

Errorf
called by 1333
experiment/logger.go
Equal
called by 303
internal/secret/secret.go
Run
called by 222
internal/sshexec/executor.go
String
called by 180
pkg/client/deploy/operation/operation.go
Error
called by 174
internal/machine/api/proxy/mapper.go
Len
called by 115
pkg/client/logmerger.go
Info
called by 102
internal/machine/machine.go
Close
called by 99
internal/sshexec/executor.go

Shape

Method 1,349
Function 933
Struct 341
Interface 42
TypeAlias 17
FuncType 1

Languages

Go92%
TypeScript8%

Modules by API surface

internal/machine/api/pb/docker.pb.go313 symbols
website/landing/js/vendors/alpinejs.min.js226 symbols
internal/machine/api/pb/machine.pb.go184 symbols
internal/machine/api/pb/docker_grpc.pb.go106 symbols
internal/machine/api/pb/cluster.pb.go93 symbols
internal/machine/api/pb/common.pb.go79 symbols
internal/machine/api/pb/machine_grpc.pb.go66 symbols
internal/machine/api/pb/cluster_grpc.pb.go46 symbols
internal/machine/docker/server.go35 symbols
pkg/api/client.go33 symbols
pkg/api/service.go32 symbols
internal/machine/machine.go31 symbols

Dependencies from manifests, versioned

charm.land/bubbles/v2v2.0.0 · 1×
charm.land/bubbletea/v2v2.0.2 · 1×
charm.land/huh/v2v2.0.1 · 1×
charm.land/lipgloss/v2v2.0.1 · 1×
cloud.google.com/go/kmsv1.19.0 · 1×
cloud.google.com/go/longrunningv0.6.0 · 1×
cunicu.li/go-rosenpassv0.4.0 · 1×
filippo.io/edwards25519v1.1.0 · 1×
github.com/AlecAivazis/survey/v2v2.3.7 · 1×
github.com/AndreasBriese/bbloomv0.0.0-2019082515265 · 1×
github.com/Azure/go-ansitermv0.0.0-2025010203350 · 1×
github.com/BurntSushi/tomlv1.5.0 · 1×

Datastores touched

myappDatabase · 1 repos
mydbDatabase · 1 repos
postgresDatabase · 1 repos

For agents

$ claude mcp add uncloud \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact