| src | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| flake.lock | ||
| flake.nix | ||
| README.md | ||
lightscale-client
Minimal control-plane client for Lightscale. It registers nodes, sends heartbeats, fetches netmaps, and can manage the WireGuard data plane (kernel or userspace) with basic NAT traversal.
This client already uses profile-scoped state files so multiple networks can be supported later by running separate profiles.
Configure a profile
cargo run -- --profile default init http://127.0.0.1:8080
Multiple control URLs (failover):
cargo run -- --profile default init http://10.0.0.1:8080,http://10.0.0.1:8081
Register a node
cargo run -- --profile default register <token> --node-name laptop
Register a node with an auth URL flow:
cargo run -- --profile default register-url <network_id> --node-name laptop
The command prints a one-time approval URL. Open it in a browser (or curl it) to approve the node.
Admin actions
Set an admin token when the control plane is protected (CLI flag or env var):
export LIGHTSCALE_ADMIN_TOKEN=<token>
List nodes in a network (use --pending to show only unapproved nodes):
cargo run -- --profile default admin nodes <network_id> --pending
Update a node's name or tags (admin):
cargo run -- --profile default admin node update <node_id> --name laptop --tags dev,lab
Clear tags:
cargo run -- --profile default admin node update <node_id> --clear-tags
Approve a node by ID:
cargo run -- --profile default admin approve <node_id>
Create an enrollment token:
cargo run -- --profile default admin token create <network_id> --ttl-seconds 3600 --uses 1 --tags lab
Revoke an enrollment token:
cargo run -- --profile default admin token revoke <token>
Heartbeat
cargo run -- --profile default heartbeat \
--endpoint 203.0.113.1:51820 \
--route 192.168.10.0/24
Optionally include your WireGuard listen port so the server can add the observed public endpoint from the heartbeat connection:
cargo run -- --profile default heartbeat --listen-port 51820
Use STUN to discover a public endpoint (best effort):
cargo run -- --profile default heartbeat --stun --stun-server stun.l.google.com:19302
Advertise exit node routes:
cargo run -- --profile default heartbeat --exit-node
Fetch netmap
cargo run -- --profile default netmap
Show status
cargo run -- --profile default status
Include WireGuard peer info (handshake age + endpoint):
cargo run -- --profile default status --wg
Configure WireGuard (Linux)
Bring up an interface using the latest netmap:
sudo cargo run -- --profile default wg-up --listen-port 51820
Use boringtun (userspace WireGuard) instead of the kernel module:
sudo cargo run -- --profile default wg-up --listen-port 51820 --backend boringtun
This runs the userspace tunnel inside the client process. Keep the command
running (or use agent) to keep the tunnel alive.
Apply advertised subnet/exit routes at the same time:
sudo cargo run -- --profile default wg-up --listen-port 51820 --apply-routes --accept-exit-node
Optionally probe peers to trigger NAT traversal (UDP probe, no ICMP):
sudo cargo run -- --profile default wg-up --listen-port 51820 --probe-peers
Conflicting routes are skipped by default; use --allow-route-conflicts to force them.
Select a specific exit node by ID or name:
sudo cargo run -- --profile default wg-up --listen-port 51820 --apply-routes --accept-exit-node \
--exit-node-id <peer_id>
Remove the interface:
sudo cargo run -- --profile default wg-down
If you used the boringtun backend, stop the process that created the tunnel
(for example Ctrl+C in the foreground or stopping the agent). The command
below attempts to remove the interface if needed.
sudo cargo run -- --profile default wg-down --backend boringtun
Run the agent loop
Keep WireGuard and routes updated using long-polling + periodic heartbeats:
sudo cargo run -- --profile default agent --listen-port 51820 --apply-routes --accept-exit-node \
--heartbeat-interval 30 --longpoll-timeout 30
Tune endpoint rotation (stale seconds + max rotations before relay fallback):
sudo cargo run -- --profile default agent --listen-port 51820 \
--endpoint-stale-after 15 --endpoint-max-rotations 2
Use boringtun backend in the agent:
sudo cargo run -- --profile default agent --listen-port 51820 --backend boringtun
Enable STUN discovery in the agent:
sudo cargo run -- --profile default agent --listen-port 51820 --stun \
--stun-server stun.l.google.com:19302
Enable stream relay signaling (peer probe via relay):
sudo cargo run -- --profile default agent --listen-port 51820 --stream-relay
With --stream-relay, the agent also maintains local relay tunnels that can be
used as a fallback when direct endpoints stop handshaking.
Probe peers when netmap updates arrive (UDP probe to endpoints, no ICMP):
sudo cargo run -- --profile default agent --listen-port 51820 --probe-peers
Enable subnet/exit routing (Linux)
Configure IP forwarding and (optionally) SNAT for a subnet router or exit node.
This uses nftables via libmnl/libnftnl (the Nix dev shell installs them):
sudo cargo run -- --profile default router enable --interface ls-default --out-interface eth0
Disable SNAT to require return routes on the LAN:
sudo cargo run -- --profile default router enable --interface ls-default --out-interface eth0 --no-snat
Remove forwarding/NAT rules:
sudo cargo run -- --profile default router disable --interface ls-default --out-interface eth0
DNS and relay info
Export host-style DNS entries:
cargo run -- --profile default dns
Export DNS info as JSON (debug output):
cargo run -- --profile default dns --format json --output /tmp/lightscale-dns.json
Show relay configuration (STUN/TURN/stream relay/UDP relay):
cargo run -- --profile default relay
UDP relay (best effort)
Send a test message via the UDP relay:
cargo run -- --profile default relay-udp send <peer-id> "hello"
Listen for relay messages:
cargo run -- --profile default relay-udp listen
Stream relay (best effort)
Send a test message via the stream relay:
cargo run -- --profile default relay-stream send <peer-id> "hello"
Listen for relay messages:
cargo run -- --profile default relay-stream listen