Skip to main content

Overview

The matchmaker service manages the pool of available Windows hosts and assigns clients to hosts for streaming sessions. Key responsibilities:
  • Accept host registrations with heartbeat mechanism
  • Track host availability (idle/busy/offline)
  • Match clients to available hosts based on region and capacity
  • Provide ICE server configuration (STUN/TURN) to clients
  • Health monitoring and stale host cleanup

Architecture

Requirements

  • Node.js 16+ and npm
  • Redis 6+ (shared with signaling server)
  • 512 MB RAM minimum
  • HTTP hosting (Railway, Heroku, Vercel, etc.)

Installation

The matchmaker is located in Server/mm_server/:

Configuration

Environment Variables

The matchmaker uses the same config.js as the signaling server. Configure these variables:

Configuration Reference

CRITICAL: Change HOST_SECRET before production deployment!This secret authenticates Windows hosts. Use a strong random value:

Running Locally

1

Ensure Redis is running

2

Start the matchmaker

You should see:
3

Test the API

API Reference

POST /api/host/heartbeat

Hosts send heartbeats to register and maintain availability. Authentication: Bearer token with HOST_SECRET Request:
Response:
Parameters:
Hosts must send heartbeats every 20-25 seconds. If no heartbeat is received for 30 seconds, the host is removed from the available pool.
Example (curl):

POST /api/match/find

Clients request a host assignment for a streaming session. No authentication required (public endpoint) Request:
Response (success):
Response (no hosts available):
Matching algorithm:
  1. Sample up to 50 random hosts from Redis
  2. Filter by region (if specified) with 5x weight preference
  3. Select host with available capacity using weighted random
  4. Atomically decrement availableSlots using Redis transactions
  5. Return room ID and signaling configuration
Example (curl):

GET /api/hosts

List all available hosts (for monitoring). Response:

GET /api/hosts/ttl

Get TTL (time-to-live) for all hosts (debugging). Response:

Health Endpoints

  • GET / - Returns ok
  • GET /health - Returns 200 with ok
  • GET /healthz - Returns 200 (for Railway/K8s)
  • GET /readyz - Returns 200 (for Railway/K8s)

Deploying to Production

Railway Deployment

1

Create a separate Railway service

Or add to existing project:
2

Link to the same Redis instance

In Railway dashboard:
Both signaling and matchmaker should share the same Redis instance.
3

Set environment variables

4

Deploy with custom start command

Railway settings → Deploy → Custom Start Command:
Or add to package.json:
5

Note the deployment URL

Railway provides a URL like:
Update this URL in:
  • Windows host config.json: host.matchmaker.url
  • Client config.json: client.matchmakerUrl

Docker Deployment

Create Dockerfile.matchmaker in Server/:
Build and run:

Serverless / Edge Deployment

The matchmaker requires Redis for state management and is not suitable for truly stateless serverless (AWS Lambda, Vercel Serverless Functions).However, it works well on:
  • Railway (recommended)
  • Heroku
  • Google Cloud Run
  • AWS ECS/Fargate
  • Fly.io

TURN Server Configuration

For clients behind restrictive NATs, TURN servers are required for WebRTC connectivity. Metered.ca provides managed TURN servers with automatic credential rotation:
1

Sign up for Metered.ca

Visit metered.ca and create an account.
2

Get your credentials

From the dashboard, note:
  • Domain: Your subdomain (e.g., yourcompany)
  • API Key: Secret key for generating credentials
3

Configure environment variables

The matchmaker will automatically:
  1. Generate short-lived TURN credentials when a client requests a match
  2. Return ICE servers including both STUN and TURN
  3. Credentials expire after 4 hours (configurable)

Self-Hosted TURN (coturn)

For self-hosting, use coturn:
Then modify mm_server/Matchmaker.js to return your TURN server:

Monitoring and Debugging

Redis Inspection

Monitor Redis state:

Logs

Key log messages:

Testing Host Registration

Simulate a host:
Use Server/mm_server/simulate_hosts.js for automated testing:

Troubleshooting

Cause: HOST_SECRET mismatch between host and matchmakerSolution: Ensure both use the same secret:
  • Matchmaker .env: HOST_SECRET=HELLO-MFS
  • Host config.json: host.matchmaker.hostSecret: "HELLO-MFS"
Cause: Heartbeat interval too long or hosts not sending heartbeatsSolution:
  • Verify host is running and connected
  • Check host logs for heartbeat send confirmations
  • Ensure heartbeatIntervalMs in host config is under 25000 (25s)
  • Network issues may prevent heartbeats from reaching matchmaker
Diagnosis:
Causes:
  • No hosts have sent heartbeats
  • All hosts are busy (availableSlots: 0)
  • Hosts have expired (no heartbeat for 30+ seconds)
  • Region mismatch (client requests us-east, all hosts are eu-west)
Diagnosis: Check ICE servers returned by /api/match/findSolutions:
  • Verify METERED_DOMAIN and METERED_API_KEY are correct
  • Check Metered.ca dashboard for usage/errors
  • Test TURN server directly with Trickle ICE
  • Ensure TURN ports (typically 3478, 443) are not blocked
Cause: Stale host entries accumulatingSolution: The matchmaker automatically prunes stale hosts every 10 seconds. If memory still grows:

Security Best Practices

Production security checklist:
  • Generate a strong HOST_SECRET: openssl rand -base64 32
  • Use HTTPS for the matchmaker API
  • Restrict /api/host/* endpoints to internal network (if possible)
  • Rate limit /api/match/find to prevent abuse
  • Enable CORS only for your client domain
  • Monitor for abnormal host registration patterns
  • Rotate HOST_SECRET periodically using HOST_SECRET_PREVIOUS
  • Use managed Redis with authentication and encryption in transit

Next Steps

  • Host Setup - Configure Windows hosts to register with this matchmaker
  • Client Deployment - Configure client to use this matchmaker for host discovery
  • Signaling Server - Ensure signaling server is configured and accessible