Livqeno Docs

Running the SFU

How a media server joins the fleet, how rooms are allocated to it, and how to take one out of service.

The SFU is a Go service built on Pion. It forwards media and nothing else — it holds no database and issues no credentials.

How a node joins

A node registers itself with the control plane and then heartbeats:

POST /v1/rtc/servers/register           on start-up
PUT  /v1/rtc/servers/{name}/heartbeat   on an interval

Both are authenticated with SFU_REGISTRATION_SECRET — a server-to-server secret, never handed to a client and never the same value as any client-facing token secret.

A node that has not heartbeated within SFU_HEARTBEAT_TIMEOUT_SECONDS (30 by default) is treated as unhealthy and stops receiving new rooms. That window must comfortably exceed the node's own heartbeat interval or healthy nodes flap.

How rooms are allocated

When the first participant joins a room, the control plane picks a node: preferring the requested region, and falling back to any region rather than failing the call.

That fallback is worth knowing about, because it has a sharp edge on a shared database — see Known limitations.

Clients never learn which node they got. They connect to the signaling endpoint and Livqeno negotiates on their behalf. That indirection is what allowed Livqeno's media plane to be replaced wholesale without an SDK release.

Configuration

VariableWhat it is
SFU_NODE_IDThis node's name in the fleet
SFU_REGIONRegion label used for allocation
SFU_PUBLIC_IP / SFU_PUBLIC_HOSTWhat clients can actually reach
SFU_UDP_PORT_MIN / SFU_UDP_PORT_MAXMedia port range — must be open
SFU_ROOM_CAPACITYRooms this node will accept
SFU_HTTP_PORTIts own health and metrics port
SFU_CONTROL_PLANE_URLWhere to register and heartbeat
SFU_DEFAULT_REGIONControl plane setting: region used when none is requested

SFU_PUBLIC_IP being wrong is the classic failure: allocation succeeds, the client is handed an address nothing can reach, and the call fails with no obvious cause.

Inspect the fleet

raven rtc servers list
raven rtc servers get <server>
raven rtc rooms list
raven rtc participants list <room>
raven rtc diagnostics <room>

Draining a node

Before a deploy or a shutdown, stop new rooms without dropping live ones:

raven rtc servers drain <server>

Existing rooms keep running; no new ones are allocated. Wait for it to empty, then take it out. Bring it back with the undrain endpoint — POST /v1/rtc/servers/{name}/undrain.

Its own health

The SFU serves its own /readyz. One thing to expect: it reports nodeLinks: 0 and ready: false at idle, because a link to the control plane is established when a room actually needs one. That is not a fault at rest.

Graceful shutdown

The control plane installs shutdown hooks, so SIGTERM drains connections rather than dropping them: both gateways close every socket with a distinct code instead of an unannounced cut, the webhook worker stops polling, and Postgres and Redis disconnect cleanly.

Pair that with a preStop delay in your orchestrator so clients notice the pod leaving the service's endpoints and start reconnecting elsewhere before the process exits.

Next steps