Use real domains for the control API and public services, for example luma.example.com and status.example.com.
Deploy tool for small Swarm clusters
Deploy services
on your own servers.
Write one YAML file for the domain, port, exposure, and region. Luma syncs Cloudflare DNS, Traefik HTTPS routes, and Swarm services while each server joins the cluster locally.
curl -fsSL https://raw.githubusercontent.com/LiuTianjie/luma/main/scripts/install-luma.sh | sh
domain: status.example.com
exposure: cn-edge
port: 80
$ luma deploy status.yaml
ok dns status.example.com -> cn-edge
ok tls acme certificate requested
ok route Host(status.example.com) -> status:80
ok swarm status replicated x2
domain is the service address
Have these ready first.
Put the DNS zone in Cloudflare and create a token that can read the zone and edit records.
Start with one sudo-capable Linux server. A 2c2g manager is enough for testing if app resources are capped.
Skip Tailscale for a single public manager. Use it for home nodes, private joins, or tailscale-relay.
What each command updates.
name: status
image: traefik/whoami:latest
region: cn
domain: status.example.com
port: 80
exposure: cn-edge
replicas: 2
resources:
limits:
cpus: "0.50"
memory: 512M
Luma reads the manifest and updates the deploy path.
-
01
Read service entry
Read
domain,port, andexposureto get the address and target port. -
02
Write DNS record
Write the Cloudflare record so the domain points to the selected entry node.
-
03
Create HTTPS route
Traefik reads the Host rule, requests a certificate, and creates the HTTPS route.
-
04
Pull private image if needed
For private GHCR or custom registries, Luma uses saved registry credentials without writing tokens into the manifest.
-
05
Update service
Update the stack so
status.example.comforwards tostatus:80. -
06
Limit resources
Use Swarm resource limits when apps and control services share a small server.
Run the command for each machine role.
Install the CLI
Install luma on the manager first. Workers and clients install the same command later when needed.
curl -fsSL https://raw.githubusercontent.com/LiuTianjie/luma/main/scripts/install-luma.sh | sh
~/.local/bin/luma preflight
Initialize the control plane
Initialize Swarm on the first server, then start Traefik, Portainer, Luma Control, and the egress gateway.
luma bootstrap manager --domain luma.example.com
Join workload nodes
Each server runs join locally and gets a region label. Scheduling mainly follows region.
luma node join https://luma.example.com --token <join-token> --region global --name global-sg-1
Save private registry credentials
Use saved credentials when the image registry is private.
luma login https://luma.example.com --token <deploy-token>
printf '%s' "$GHCR_TOKEN" | luma registry login ghcr.io --username <user> --password-stdin
Deploy from a client
After login, the client submits the manifest. Luma prints DNS, certificate, route, and stack progress.
luma login https://luma.example.com --token <deploy-token>
luma deploy status.yaml