The Nestri relay is a lightweight Go service that acts as a libp2p node. It handles WebRTC signaling between browser clients and game runner containers, performs NAT hole-punching, and serves the HTTP/WebSocket/WebTransport endpoint that peers connect to. Media traffic flows directly between peers once a WebRTC connection is established — the relay is not in the media path after the initial handshake.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/nestrilabs/nestri/llms.txt
Use this file to discover all available pages before exploring further.
Docker image
The official nightly image is published to the GitHub Container Registry:containerfiles/relay.Containerfile using a two-stage Go build on Alpine Linux.
Quick start
8088 for all protocols: HTTP, WebSocket, QUIC, and WebTransport simultaneously. No extra ports are needed unless you configure a separate UDP range for WebRTC (see WEBRTC_UDP_START / WEBRTC_UDP_END below).
Environment variables
All configuration is passed via environment variables. Every variable maps to a command-line flag with the same name in lower camel case.Regenerate the relay’s libp2p identity on startup. When
false, the existing identity.key in PERSIST_DIR is reused. Set to true only if you need a fresh peer identity — this invalidates any existing peer connections that know the old identity.Enable verbose (debug-level) logging to stdout. Implied when
DEBUG=true.Enable debug mode. Implies
VERBOSE=true. Produces more detailed internal relay diagnostics.The TCP port the relay’s HTTP/WebSocket/WebTransport endpoint listens on. Expose this port in your Docker run command and firewall rules.
Start of the UDP port range allocated for individual WebRTC peer connections. Set to
0 to disable port-range mode and use the UDP mux port instead (recommended). Ignored when WEBRTC_UDP_MUX is non-zero.End of the UDP port range for WebRTC. Must be set together with
WEBRTC_UDP_START. Leave at 0 when using mux mode.The STUN server used for WebRTC ICE candidate gathering. You can replace this with a private STUN/TURN server if your network blocks Google’s servers.
The UDP port used as a single WebRTC mux. All WebRTC traffic is multiplexed through this single port, which avoids needing a large UDP port range. Defaults to the same value as
ENDPOINT_PORT.A comma-separated list of public IP addresses to advertise in WebRTC ICE candidates. Required when the relay is behind NAT and
AUTO_ADD_LOCAL_IP cannot detect the correct public IP. Example: 1.2.3.4.Automatically detect and add the machine’s non-loopback, non-private IP as a WebRTC NAT candidate. The relay source code in
packages/relay/internal/common/flags.go iterates interface addresses and picks the first non-loopback, non-private, non-unspecified address. Set to false and use WEBRTC_NAT_IPS when you need explicit control.Directory where the relay stores its libp2p identity (
identity.key) and peer store (peerstore.json). Mount a volume at this path to survive container restarts without losing the relay’s peer identity.Enable the Prometheus-compatible metrics endpoint.
Port for the metrics HTTP endpoint. Only active when
METRICS=true.Identity persistence
On each graceful shutdown, the relay saves its peer store to$PERSIST_DIR/peerstore.json. The libp2p identity key is written to $PERSIST_DIR/identity.key. Mount a named volume to preserve these files:
If you lose the
identity.key file, the relay will generate a new libp2p peer identity on the next start with REGEN_IDENTITY=true. Any runners or clients that stored the old peer ID will need to reconnect.TLS proxy setup
The relay itself does not handle TLS termination. Run it behind a reverse proxy for HTTPS/WSS. The examples below are drawn directly from the reference compose files incontainerfiles/.
- Caddy
- Traefik
The
Caddyfile proxies WebSocket upgrade requests and all other HTTP traffic to the relay container on port 8088. Replace relay.example.com and you@example.com with your domain and email.Caddyfile
docker-compose.relay.caddy.yml
Port requirements
| Port | Protocol | Purpose |
|---|---|---|
8088 | UDP | WebRTC media and mux (required, must be reachable from the internet) |
8088 | TCP | HTTP / WebSocket / WebTransport endpoint (proxied via TLS terminator) |
443 | TCP | HTTPS/WSS (handled by Caddy or Traefik in front of the relay) |
NAT traversal
When the relay container is behind a router performing NAT, WebRTC ICE candidates advertised by the relay may not be reachable from the internet. There are two ways to fix this:- Automatic detection (
AUTO_ADD_LOCAL_IP=true, the default): The relay callsnet.InterfaceAddrs()and picks the first non-loopback, non-private, non-unspecified address. This works when the container shares the host network or the host has a public IP on an interface. - Explicit IP (
WEBRTC_NAT_IPS=<public-ip>): Set this to your machine’s public IPv4 address. DisableAUTO_ADD_LOCAL_IPwhen using this option (AUTO_ADD_LOCAL_IP=false).