FlatRun supports clustering multiple agents together, giving you a unified view of deployments and system health across all your servers from a single dashboard.
How It Works
Clustering uses an invitation-based model. One node generates an invite token, another node accepts it, and they exchange API keys for secure bidirectional communication.
Once connected, each node periodically health-checks its peers. The UI and API can aggregate data from all nodes — listing deployments, viewing stats, and proxying requests across the cluster.
Configuration
Add the cluster section to your agent config on each node:
# /etc/flatrun/config.yml
cluster:
enabled: true
server_name: "node-1"
advertise_url: "https://node-1.example.com:8090"
health_interval: "30s"
request_timeout: "10s" | Field | Default | Description |
|---|---|---|
enabled | false | Enable clustering |
server_name | OS hostname | Unique name for this node in the cluster |
advertise_url | — | URL other nodes use to reach this agent (must be reachable by peers) |
health_interval | 30s | How often to health-check peers |
request_timeout | 10s | Timeout for requests to peers |
Joining Nodes
Clustering is managed entirely via the API (or the UI). Here's the flow:
1. Generate an Invite
On the node you want others to join:
curl -X POST http://localhost:8090/api/cluster/invite \
-H "Authorization: Bearer $TOKEN" This returns a one-time invite token that expires in 1 hour.
2. Accept the Invite
On the joining node:
curl -X POST http://localhost:8090/api/cluster/accept \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"invite_token": "THE_INVITE_TOKEN",
"peer_url": "https://node-1.example.com:8090",
"callback_url": "https://node-2.example.com:8090"
}' Both nodes exchange API keys and begin monitoring each other.
3. Verify the Connection
# Check cluster status
curl http://localhost:8090/api/cluster/status \
-H "Authorization: Bearer $TOKEN"
# List all peers
curl http://localhost:8090/api/cluster/peers \
-H "Authorization: Bearer $TOKEN" Cluster API
| Endpoint | Method | Description |
|---|---|---|
/api/cluster/status | GET | Cluster info: enabled, server name, peer count |
/api/cluster/peers | GET | List all peers with online status and last seen time |
/api/cluster/invite | POST | Generate a 1-hour invite token |
/api/cluster/accept | POST | Accept an invite and join a peer |
/api/cluster/peers/:name | DELETE | Remove a peer from the cluster |
/api/cluster/deployments | GET | Aggregated deployments from all nodes |
/api/cluster/stats | GET | Aggregated system stats from all nodes |
/api/cluster/peers/:name/proxy/* | ANY | Forward any request to a specific peer |
Aggregated Responses
Cluster endpoints like /api/cluster/deployments and /api/cluster/stats return data grouped by node:
{
"servers": {
"node-1": {
"name": "node-1",
"online": true,
"data": [... deployments ...]
},
"node-2": {
"name": "node-2",
"online": true,
"data": [... deployments ...]
}
}
} If a peer is offline, it appears with "online": false and an error message.
Security
- Encrypted Keys Peer API keys are encrypted at rest with AES-256-GCM
- One-Time Invites Invite tokens are single-use and expire after 1 hour
- Hashed Storage Only token hashes are stored in the database
- Independent Keys Each peer-to-peer connection uses independent API keys
Removing a Peer
curl -X DELETE http://localhost:8090/api/cluster/peers/node-2 \
-H "Authorization: Bearer $TOKEN" Requirements
- Each node must be reachable by its peers at the
advertise_url - Port 8090 (or your configured API port) must be open between nodes
- Each node needs a unique
server_name - All nodes should run compatible agent versions