Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Build Server & Connection Setup

The build server is a public, stateless HTTP service. It issues build permissions, brokers WebRTC connection setup, and assigns jobs to build machines. It does not see the contents of any build, and does not have the ability to read user data flowing over WebRTC channels.

Endpoints

The build server exposes a small REST surface:

MethodPathPurpose
POST/grant/requestRequest a build permission.
POST/signaling/{job_id}/offerSubmit a WebRTC SDP offer.
POST/signaling/{job_id}/candidateSubmit an ICE candidate.
GET/signaling/{job_id}/eventsLive updates stream of the build machine’s answer and candidates.
GET/healthLiveness check.
GET/metricsPrometheus metrics.

There are also /agents/* and /services/* endpoints used by build machines and operators, but those aren’t part of the user-facing build flow.

A permission request in detail

POST /grant/request
{
  "peer_fingerprint": "sha-256:XX:XX:...",
  "required_channels": ["espctl", "pty", "firmware"],
  "cpu_cores": 2.0,
  "memory_mb": 1024,
  "timeout_secs": 600
}
FieldMeaning
peer_fingerprintThe SHA-256 certificate fingerprint of the requesting peer. The build server embeds this in the permission token so the build machine can later verify “the peer I’m talking to is the same peer the permission was issued to”.
required_channelsThe exact list of WebRTC data channels the requester needs. The build machine will refuse to open any channel not in this list.
cpu_cores / memory_mbResource requirements used to schedule the job to a capable build machine.
timeout_secsHow long the session is allowed to live. Capped at the operator’s policy (typically 5-30 seconds for permission tokens, longer for build sessions specifically).

The build server responds with:

{
  "job_id": "01H...uuid",
  "grant": "<signed permission token>",
  "candidates": ["agent-id-1", "agent-id-2"],
  "ice_servers": [
    { "urls": "stun:stun.example.com:3478" },
    {
      "urls": "turn:stun.example.com:3478?transport=tcp",
      "username": "...",
      "credential": "..."
    }
  ],
  "expires_at": 1712340060
}

grant is a signed permission token (a digital signature over an encoded body) that names the user, the allowed channels, the bandwidth/rate limits, and the expiration time. The build machine verifies this signature locally before honoring the permission – see Permissions & Security.

Connection setup – what the build server does and doesn’t see

The build server relays the SDP offer/answer and ICE candidates between the two peers. It does not parse the contents – it stores the body as raw bytes, broadcasts them on the live updates stream for the matching job_id, and discards the state after the session ends (default 60 seconds TTL).

What the build server sees:

  • That a session was requested at time T by peer with fingerprint X.
  • That an SDP offer of N bytes was posted.
  • That an SDP answer of M bytes was relayed.
  • A handful of ICE candidates with their addresses (the candidate addresses are the only network metadata exposed; this is fundamental to how WebRTC works).

What the build server does not see:

  • The build request body (it’s encrypted on the data channel).
  • The build logs (data channel).
  • The firmware binary (data channel).
  • The contents of the user’s project files (data channel).

Job assignment

When a build permission is issued, the build server runs a small scheduler to pick which build machine should run the job. Inputs to the scheduler:

  • Liveness – build machines send heartbeats every few seconds; only live machines are candidates.
  • Capacitycpu_cores and memory_mb from the permission request.
  • Capabilities – does this build machine have the requested IDF version installed? Does it support the requested chip target?
  • Past performance – a small “learning engine” prefers build machines that recently ran similar jobs successfully.

The chosen build machine receives the permission via live updates and is then responsible for opening its half of the WebRTC peer connection.

Operator concerns

If you’re running your own build server:

  • CORS: the /grant/* and /signaling/* endpoints are called from a browser, so CORS must allow the relevant origins. Edit ALLOWED_ORIGINS in /etc/aegis/control.env and restart the service.
  • TLS: the public endpoint should be behind HTTPS in production. esphome.cloud uses Caddy as a reverse proxy with automatic Let’s Encrypt certificates; the IP-mode setup uses plain HTTP on port 80 (development only).
  • Relay ports: the fallback relay needs UDP ports 49152-49231 open for peer traffic, and TCP+UDP 3478 for the relay control channel.
  • Health monitoring: GET /health returns 200 + a small JSON blob; GET /metrics returns Prometheus-format metrics.

See the aegis repo’s deploy/ directory for full systemd unit files, Caddyfile templates, and the provision-store.sh script.

See also