BTSBTS

Nodes

Preview environments on BTS run on nodes — servers running the BTS agent. BTS operates a shared pool of nodes that every plan includes, and you can also connect your own machines as private nodes. This page is for you if you want to run a node to host your own or your team's previews on your own hardware.

Not running a node? You can skip this page. The hosted BTS service already has a pool of nodes — just push your code and get a URL.

What Nodes Are

A node is a server that runs the BTS agent and contributes compute resources to the network. Each node runs containerd for container management and BuildKit for building Docker images.

Nodes come in two flavors. Shared nodes form the global pool — operated by BTS, they run workloads for any user without their own infrastructure. Private nodes are owned by a specific user or team and only run that owner's projects. Each project picks the pool it wants in its settings.

Nodes can be bare-metal servers, virtual machines, or even powerful developer workstations. The minimum requirements are:

  • Linux (kernel 5.4+)
  • 4 vCPU
  • 8 GB vRAM
  • 50 GB disk space
  • containerd 1.7+ installed
  • BuildKit installed

Joining the Network

To add a node to the BTS network, you need a join token. Generate one from the dashboard under Nodes > Add Node or via the API:

curl -X POST https://test.buildingswell.com/api/nodes/join-token \
  -H "Authorization: Bearer <token>"

Then on the server you want to register, install the agent and join. The one-line installer detects OS + architecture, verifies checksums, and drops the binary in /usr/local/bin:

# Install the agent
curl -fsSL https://test.buildingswell.com/install.sh | sh

# Join the network
nexos-agent join --token <join-token>
nexos-agent start

For manual downloads, systemd unit examples, pinning a specific version, or building from source, see Install the Agent.

join writes the agent's configuration (node id, token, control-plane endpoints); start opens a persistent gRPC connection to the control plane, and the node is enrolled on its first heartbeat.

A join command works for 24 hours. If the agent hasn't connected by then, it is refused and logs join token expired, and the dashboard shows the node as Join command expired: delete that node, add a new one, run its join command and restart the agent. Once the agent has connected, the token is the node's credential and does not expire, so keep its configuration file private.

Agent Configuration

The agent is configured via a YAML file at /etc/nexos/agent.yaml:

# /etc/nexos/agent.yaml
api_url: https://api.test.buildingswell.com
grpc_port: 50051

resources:
  # How much of the machine's resources to offer
  cpu_reserved: 1        # Reserve 1 core for the OS
  memory_reserved: 2048  # Reserve 2GB for the OS (in MB)
  disk_reserved: 20480   # Reserve 20GB for the OS (in MB)

containerd:
  socket: /run/containerd/containerd.sock
  namespace: nexos

buildkit:
  address: unix:///run/buildkit/buildkitd.sock

storage:
  data_dir: /var/lib/nexos
  cache_max_size: 10240  # Max image cache in MB

Resource Reporting and Heartbeats

The agent sends heartbeat messages to the control plane every 30 seconds via the gRPC bidirectional stream. Each heartbeat includes:

  • vCPU usage — Current utilization and available vCPU
  • vRAM usage — Used and available vRAM
  • Disk usage — Used and available storage
  • Running containers — Count of active environments
  • Network stats — Bandwidth usage and latency

The scheduler uses this data to select the best node for each deployment. It considers available capacity, geographic proximity to the developer, and cache affinity (preferring nodes that have previously built the same project for faster incremental builds).

Node Status Monitoring

Monitor your nodes from the dashboard under the Nodes tab. Each node shows:

  • Status — Online, offline, or draining
  • Uptime — Time since the agent started
  • Resource utilization — vCPU, vRAM, and disk graphs
  • Active environments — List of running containers
  • Build history — Recent builds executed on this node

If a node stops sending heartbeats for more than 90 seconds, it is marked as offline. Environments running on offline nodes are automatically rescheduled to healthy nodes.

To gracefully remove a node, put it in drain mode from the dashboard. This prevents new deployments from being scheduled to the node while existing environments continue to run. Once all environments have been migrated or destroyed, you can safely shut down the agent.

Nodes - BTS Docs