The flow
1
Choose where it runs
In the dashboard open Nodes, then Add node, then I already have a server. Leave Where does it run? on Auto-detect to let the node read its own provider, region and zone. Pick a provider and type a region and zone instead for a home server or a provider without a metadata service.
2
Run one command
The dialog shows a Docker command and an agent binary command. Both carry a single-use join token that expires after 15 minutes by default (
APP_NODE_JOIN_TOKEN_TTL changes it, one minute to 24 hours). Give the node a name to follow it live.3
Watch it connect
With a name set, the dialog shows four stages: join token created, agent contacted the control plane, connected over mTLS, preflight checks. It updates by itself.
4
Read the preflight
Every check shows its status. Anything that is not a pass shows a concrete fix, with the shell command collapsed under Fix via CLI. Re-check reads the latest report; the agent resends its facts every minute, so a fix you apply on the node shows up without a restart.
--preflight prints the join command, waits for the node, then prints each check and exits non-zero when one failed. nodes preflight <id-or-name> shows the last result; add --wait to wait for it.
Provider, region and zone detection
On every session the agent asks the metadata service of the cloud it runs on. Providers are probed in a fixed order, so a host that answers on more than one gives a stable result.
Values are made valid as node labels (letters, digits,
., _, -, at most 63 characters). The control plane applies a detected value only where the node has none: a label you set by hand always wins, and a detected value never overwrites it.
When there is no metadata service
A home server or an unsupported provider reports nothing, and the node simply has no labels until you set them. Three ways to set them:- Fill in the provider, region and zone in the dialog, or pass
--provider,--regionand--zonetonodes add. The join command then carriesAPP_NODE_PROVIDER,APP_NODE_REGIONandAPP_NODE_ZONE. - Set those variables on the agent yourself. They override what metadata reports, field by field.
- Label the node afterwards on its page, or with
levelrail-cli nodes labels.
APP_AGENT_METADATA_DISABLE=1 on the agent to skip the metadata probe entirely, and APP_AGENT_METADATA_TIMEOUT (default 1s) to change how long each provider is given.
Preflight checks
The agent measures facts and the control plane judges them, so thresholds and fix text live in one place.
Thresholds are read on the control plane:
A node only dials out, so the agent cannot prove that other nodes can reach its mesh port from outside. The firewall check says so and shows the rule to open. Once the mesh has two nodes, node pair diagnostics report whether the handshake actually completes. The clock check includes network latency, so it is accurate to about a second.
Failure-domain aware placement
Nodes carryprovider, region and zone. When any eligible node has one, placement spreads replicas of the same workload across them: the zone holding the fewest replicas wins, then the region, then the provider, then the zone carrying the fewest workloads, then the usual headroom order. The choice is deterministic: the same fleet and the same request always give the same answer, and offline or cordoned nodes never win for the sake of diversity.
Warnings on apps
All replicas of one app run on one node today, so an app with two or more replicas always shares fate. The app’s placement card andGET /api/v1/apps/{name}/placement list a warning when the app’s node sits in a labeled zone and another zone has an eligible node (a warning), or the same for providers (informational). Fixing it means moving the app, or running separate apps per zone with placement selectors. Spreading the replicas of one app across nodes is not built.
Capacity overview
The Nodes page shows a card with reported CPU, memory and free disk per provider, region and zone, with the number of nodes and workloads in each. Capacity sums only what nodes reported; a node that reported nothing is counted as unverified, never as zero.API, CLI and MCP
What is verified
- Metadata parsing is tested against fake servers that mimic each provider’s request and response shape, including AWS token handling and the Google
Metadata-Flavorecho. - Preflight judging, placement spread and the API are covered by unit tests.
- The two-Docker-daemon join test reports preflight facts from two real agents against two real daemons and checks that the labels reach the node rows. It runs only with
LEVELRAIL_LIVE_MULTINODE=1.
Related pages
Multi-node
Enrollment, the mesh, drains and the failure policy.
Resource-aware placement
How the scheduler fits and ranks nodes.
Node provisioning
Create a server at a cloud provider for you.