moq-relay
A stateless relay server that routes broadcasts between publishers and subscribers, performing caching, deduplication, and fan-out.
Overview
moq-relay is designed to run in datacenters, relaying media across multiple hops to improve quality of service and enable massive scale.
Features:
- Fan-out to multiple subscribers
- Caching and deduplication
- Cross-region clustering
- JWT-based authentication
- HTTP debugging endpoints
Installation
From Source
git clone https://github.com/moq-dev/moq
cd moq
cargo build --release --bin moq-relayThe binary will be in target/release/moq-relay.
Using Cargo
cargo install moq-relayUsing Nix
nix build github:moq-dev/moq#moq-relayConfiguration
Create a relay.toml configuration file:
[server]
bind = "[::]:4443" # Listen on all interfaces, port 4443
[tls]
cert = "/path/to/cert.pem" # TLS certificate
key = "/path/to/key.pem" # TLS private key
[auth]
public = "anon" # Allow anonymous access to anon/**
key = "root.jwk" # JWT key for authenticated pathsSee dev.toml for a complete example.
Running
moq-relay --config relay.tomlOr with the config path as the only argument:
moq-relay relay.tomlHTTP Endpoints
For debugging, the relay exposes HTTP endpoints on the same bind address (TCP instead of UDP):
GET /certificate.sha256
Returns the fingerprint of the TLS certificate:
curl http://localhost:4443/certificate.sha256GET /announced/*prefix
Returns all announced tracks with the given prefix:
# All announced broadcasts
curl http://localhost:4443/announced/
# Broadcasts under "demo/"
curl http://localhost:4443/announced/demoGET /fetch/*path
Returns the latest group of the given track:
curl http://localhost:4443/fetch/demo/videoWARNING
The HTTP server listens on TCP, not HTTPS. It's intended for local debugging only.
Clustering
Multiple relay instances can cluster for geographic distribution:
[cluster]
root = "https://root-relay.example.com" # Root node
node = "https://us-east.relay.example.com" # This node's addressHow Clustering Works
moq-relay uses a simple clustering scheme:
- Root node - A single relay (can serve public traffic) that tracks cluster membership
- Other nodes - Accept internet traffic and consult the root for routing
When a relay publishes a broadcast, it advertises its node address to other relays via the root.
Cluster Arguments
--cluster-root <HOST>- Hostname/IP of the root node (omit to make this node the root)--cluster-node <HOST>- Hostname/IP of this instance (needs valid TLS cert)
Benefits
- Lower latency (users connect to nearest relay)
- Higher availability (redundancy)
- Geographic distribution
Current Limitations
- Mesh topology (all relays connect to all others)
- Not optimized for large clusters (3-5 nodes recommended)
- Single root node (future: multi-root)
Authentication
The relay supports JWT-based authentication. See the Authentication guide for detailed setup.
Quick Setup
- Generate a key:
moq-token --key root.jwk generate- Configure relay:
[auth]
key = "root.jwk"
public = "anon" # Optional: allow anonymous access to anon/**- Generate tokens:
moq-token --key root.jwk sign \
--root "rooms/123" \
--publish "alice" \
--subscribe "" \
--expires 1735689600 > alice.jwt- Connect with token:
https://relay.example.com/rooms/123?jwt=<token-content>Token Claims
root- Root path for all operationspub- Publishing permissions (path suffix)sub- Subscription permissions (path suffix)cluster- Cluster node flagexp- Expiration (unix timestamp)
Anonymous Access
To allow anonymous access to a path prefix:
[auth]
public = "anon" # Allow access to anon/** without token
key = "root.jwk" # Require token for other pathsTo make everything public (not recommended):
[auth]
public = "" # Allow access to all pathsTLS Setup
The relay requires TLS certificates. Use Let's Encrypt:
# Install certbot
sudo apt install certbot # Ubuntu/Debian
brew install certbot # macOS
# Generate certificate
sudo certbot certonly --standalone -d relay.example.comUpdate relay.toml:
[tls]
cert = "/etc/letsencrypt/live/relay.example.com/fullchain.pem"
key = "/etc/letsencrypt/live/relay.example.com/privkey.pem"Production Deployment
See the Deployment guide for:
- Running as a systemd service
- Cloud deployment (Linode, AWS, GCP, etc.)
- Multi-region clustering
- Monitoring and logging
- Performance tuning
Monitoring
Logging
Set log level via environment variable:
RUST_LOG=info moq-relay relay.toml
RUST_LOG=debug moq-relay relay.toml
RUST_LOG=moq_relay=trace moq-relay relay.tomlMetrics
Metrics (Prometheus format) are planned but not yet implemented.
Current visibility:
- Check logs for connection count
- Use HTTP endpoints for track inspection
- Monitor system resources (CPU, memory, bandwidth)
Performance
Current Status
- Single-threaded - Quinn uses one UDP receive thread
- In-memory caching - Recent groups stored in RAM
- Mesh clustering - All relays connect to all others
Scaling
- Vertical - Fast CPU matters more than core count
- Horizontal - Deploy multiple relays in different regions
- Cluster size - 3-5 nodes optimal with current implementation
Future Improvements
- Multi-threaded UDP processing
- Tree-based clustering topology
- Improved memory management
- Metrics and observability
Troubleshooting
Port Already in Use
# Check what's using port 4443
lsof -i :4443
# Kill the process or use a different portCertificate Errors
Ensure:
- Certificate is valid and not expired
- Certificate matches domain name
- Private key has correct permissions
- Certificate includes full chain
Connection Timeouts
Check:
- UDP port is open in firewall
- Cloud provider allows UDP traffic
- TLS certificate is valid
- Relay is actually running
Next Steps
- Set up Authentication
- Deploy to production (Deployment guide)
- Use moq-lite client library
- Build media apps with hang