Uncloud skill
Skill suranyami/uncloud-skill
Use when managing an Uncloud homelab cluster — deploying services, configuring Caddy ingress, adding static proxy routes for non-cluster devices, publishing ports, scaling, inspecting logs, or managing machines and volumes with the `uc` CLI.From its SKILL.md
npx -y skills add suranyami/uncloud-skillAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.9 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it
Uncloud Cluster Management
Reference for the uc CLI — a decentralised self-hosting platform using Docker containers, WireGuard mesh networking, and Caddy reverse proxy.
Core Concepts
- No central control plane — all machines are equal peers connected by WireGuard
- Caddy runs as a global service on every machine; auto-obtains TLS from Let's Encrypt
- Overlay network — services communicate via
10.210.0.0/16by default; DNS provided inside the mesh - Caddyfile is autogenerated — never edit it directly; use
x-caddy/--caddyfileinstead
CLI Quick Reference
Machines
| Command | Purpose |
|---|---|
uc machine init user@host | Bootstrap first machine / new cluster |
uc machine add user@host | Join machine to existing cluster |
uc machine ls | List machines |
uc machine update NAME --public-ip IP | Update public IP for ingress |
uc machine rm NAME | Remove machine |
Key init flags: --name, --network 10.210.0.0/16, --no-caddy, --no-dns, --public-ip auto\|IP\|none
Services
| Command | Purpose |
|---|---|
uc service ls / uc ls | List services |
uc service run IMAGE | Run a single container service |
uc deploy | Deploy from compose.yaml |
uc scale SERVICE N | Set replica count |
uc service logs SERVICE | View logs |
uc service exec SERVICE | Shell into container |
uc service inspect SERVICE | Detailed info |
uc service rm SERVICE | Remove service (keeps named volumes) |
uc ps | All containers across cluster |
Images
uc image push myapp:latest # Push local image to all machines
uc image push myapp:latest -m machine1,machine2 # Push to specific machines
uc images # List images in cluster
Volumes
uc volume ls # All volumes
uc volume ls -m machine1 # On specific machine
uc volume create NAME -m MACHINE
uc volume rm NAME
Caddy
uc caddy config # Show current generated Caddyfile (read-only)
uc caddy deploy # Deploy/upgrade Caddy across cluster
DNS & Context
uc dns show # Show reserved *.uncld.dev domain
uc dns reserve # Reserve a new domain
uc ctx ls # List cluster contexts
uc ctx use prod # Switch context
Port Publishing
HTTP/HTTPS (via Caddy reverse proxy)
-p [hostname:]container_port[/protocol]
| Example | Meaning |
|---|---|
-p 8080/https | HTTPS with auto service-name.cluster-domain hostname |
-p app.example.com:8080/https | HTTPS with custom hostname |
-p 8080/http | HTTP only, no TLS |
TCP/UDP (host-bound, bypasses Caddy)
-p [host_ip:]host_port:container_port[/protocol]@host
| Example | Meaning |
|---|---|
-p 5432:5432@host | TCP 5432 on all interfaces |
-p 127.0.0.1:5432:5432@host | TCP 5432 loopback only |
-p 53:5353/udp@host | UDP |
Compose File Extensions
Uncloud adds these extensions on top of Docker Compose:
x-ports — publish ports with domains
services:
app:
image: app:latest
x-ports:
- example.com:8000/https
- www.example.com:8000/https
- api.example.com:9000/https
x-caddy — custom Caddy config for service
services:
app:
image: app:latest
x-caddy: |
example.com {
redir https://www.example.com{uri} permanent
}
www.example.com {
reverse_proxy {{upstreams 8000}} {
import common_proxy
}
basic_auth /admin/* {
admin $2a$14$...
}
}
Template functions available inside x-caddy:
{{upstreams [service] [port]}}— healthy container IPs{{.Name}}— service name{{.Upstreams}}— map of all services → IPs
x-machines — placement constraints
services:
db:
image: postgres:18
x-machines: db-machine # Single machine name
app:
image: app:latest
x-machines:
- machine-1
- machine-2
Full multi-service example
services:
api:
build: ./api
x-ports:
- api.example.com:3000/https
environment:
DATABASE_URL: postgres://db:5432/mydb
web:
build: ./web
x-ports:
- example.com:8000/https
- www.example.com:8000/https
environment:
API_URL: http://api:3000
db:
image: postgres:18
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- db-data:/var/lib/postgresql/data
x-machines: db-machine
volumes:
db-data:
Routing to External (Non-Cluster) Devices
To expose an external device (e.g. BMC, NAS, router UI) via Caddy without running a real container:
1. Create a Caddyfile snippet (e.g. ~/device.caddyfile):
https://device.example.com {
reverse_proxy https://192.168.1.x {
transport http {
tls_insecure_skip_verify # needed for self-signed BMC certs
}
}
log
}
For plaintext upstream: reverse_proxy http://192.168.1.x:port
2. Register as a named service with no-op container:
uc service run \
--name device-bmc \
--caddyfile ~/device.caddyfile \
registry.k8s.io/pause:3.9
pause is a minimal no-op container — it does nothing, but gives Uncloud a service entry to attach the Caddyfile to.
3. Verify:
uc caddy config # device.example.com block should appear
--caddyfilecannot be combined with non-@hostpublished ports.
DNS tip: A wildcard record (*.yourdomain.com → cluster-public-ip) means any new subdomain works immediately — no DNS change needed per service.
Service DNS (Internal)
Services inside the cluster resolve each other by name:
| DNS name | Resolves to |
|---|---|
service-name | Any healthy container |
service-name.internal | Same |
rr.service-name.internal | Round-robin |
nearest.service-name.internal | Machine-local first |
Scaling & Global Services
uc scale web 5 # 5 replicas (spread across machines)
uc scale web 1 # Scale down
services:
caddy:
deploy:
mode: global # One container on every machine
Image Tag Templates (in compose.yaml)
image: myapp:{{gitdate "20060102"}}.{{gitsha 7}}
image: myapp:{{gitsha 7}}.${GITHUB_RUN_ID:-local}
| Function | Output |
|---|---|
{{gitsha N}} | First N chars of commit SHA |
{{gitdate "format"}} | Git commit date in Go format |
{{date "format"}} | Current date |
Common Workflows
Deploy from source:
uc deploy # Build + push + deploy
uc build --push && uc deploy --no-build # Separate steps
Inspect a service:
uc inspect web
uc logs -f web
uc logs --since 1h web
uc exec web # Opens shell
uc exec web /bin/sh -c "env" # Run specific command
Zero-downtime deploys happen automatically; Uncloud waits for health checks before terminating old containers.
Force recreate:
uc deploy --recreate
Common Mistakes
| Mistake | Fix |
|---|---|
| Editing the Caddyfile directly | Use x-caddy in compose or --caddyfile on uc service run |
| Proxying an HTTPS upstream with self-signed cert | Add transport http { tls_insecure_skip_verify } |
uc caddy config shows no user-defined blocks | Caddy admin socket unreachable — check uc inspect caddy and uc logs caddy |
| Service can't reach external LAN IP from container | Verify Caddy container's host can route to target network |
Volumes lost after uc service rm | Named volumes persist; only anonymous volumes are auto-removed |
What ships with it: 1 file
2.0 KB alongside SKILL.md
- README.md2.0 KB