Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when managing an Uncloud 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.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-19 | ✗→✓ | ▲ Improved | — | — |
| case-15 | ✗→✓ | ▲ Improved | — | — |
| case-16 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✗→✓ | ▲ Improved | — | — |
| case-11 | ✗→✓ | ▲ Improved | — | — |
Reference for the uc CLI — a decentralised self-hosting platform using Docker containers, WireGuard mesh networking, and Caddy reverse proxy.
Use this skill when working with Uncloud clusters, especially when:
uc machineuc deployx-caddy, x-ports, or --caddyfileUncloud runs Docker services across peer machines connected by a WireGuard mesh. Each machine is an equal cluster member; services communicate on the overlay network and Caddy runs globally to terminate public HTTP/HTTPS traffic. Compose files can use Uncloud extensions for ingress, placement, and generated Caddy configuration, while the uc CLI handles image distribution, scheduling, scaling, logs, and cluster state.
bashuc machine init user@host --name machine-1 uc service run --name web -p app.example.com:8080/https nginx:latest uc deploy
10.210.0.0/16 by default; DNS provided inside the meshx-caddy / --caddyfile instead| 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
| 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 deploy --no-build | Deploy already-pushed images without rebuilding | | uc deploy --recreate | Force service recreation | | 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 |
bashuc 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
bashuc volume ls # All volumes uc volume ls -m machine1 # On specific machine uc volume create NAME -m MACHINE uc volume rm NAME
bashuc caddy config # Show current generated Caddyfile (read-only) uc caddy deploy # Deploy/upgrade Caddy across cluster
bashuc 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
-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 |
-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 |
Uncloud adds these extensions on top of Docker Compose:
x-ports — publish ports with domainsyamlservices: 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 serviceyamlservices: 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 → IPsx-machines — placement constraintsyamlservices: db: image: postgres:18 x-machines: db-machine # Single machine name app: image: app:latest x-machines: - machine-1 - machine-2
yamlservices: 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:
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):
caddyfilehttps://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:
bashuc 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:
bashuc caddy config # device.example.com block should appear
> --caddyfile cannot be combined with non-@host published ports.
DNS tip: A wildcard record (*.yourdomain.com → cluster-public-ip) means any new subdomain works immediately — no DNS change needed per service.
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 |
bashuc scale web 5 # 5 replicas (spread across machines) uc scale web 1 # Scale down
yamlservices: caddy: deploy: mode: global # One container on every machine
yamlimage: 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 |
Deploy from source:
bashuc deploy # Build + push + deploy uc build --push && uc deploy --no-build # Separate steps
Inspect a service:
bashuc 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:
bashuc deploy --recreate
| 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 |
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +77 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.