Skip to main content

Overview

The signaling server coordinates WebRTC connections between Windows hosts and browser clients. It uses WebSocket for real-time communication and Redis pub/sub for multi-instance coordination. Key features:
  • WebSocket signaling for SDP and ICE candidate exchange
  • Redis pub/sub for scaling across multiple instances
  • Rate limiting and circuit breakers
  • Health checks and Prometheus metrics
  • JWT authentication (optional)

Requirements

  • Node.js 16+ and npm
  • Redis 6+ (required for production, single instance OK for development)
  • 1-2 GB RAM per instance
  • WebSocket-capable hosting (Railway, Heroku, AWS, GCP, etc.)

Installation

1

Navigate to the Server directory

2

Install dependencies

This installs:
  • ws - WebSocket server
  • redis - Redis client with pub/sub support
  • express - HTTP server for health checks
  • pino - Structured logging
  • zod - Schema validation
  • jsonwebtoken / jose - JWT authentication (optional)

Configuration

Environment Variables

Create a .env file in the Server/ directory:

Configuration Reference

Core Settings

Railway, Heroku, and similar platforms automatically inject the PORT environment variable. The server listens on PORT if available, falling back to WS_PORT.

Room Settings

WebSocket Settings

Rate Limiting

Security

Running Locally

1

Start Redis

Or with Docker:
2

Start the signaling server

The server will start on port 3002 (or the port specified by PORT env var).
3

Verify it's running

Testing WebSocket Connection

Test the WebSocket endpoint:

Deploying to Production

Railway Deployment

1

Create a new Railway project

2

Add Redis service

In the Railway dashboard:
Railway will automatically inject REDIS_URL as an environment variable.
3

Configure environment variables

In Railway dashboard, add these variables:
4

Deploy

Railway will:
  • Detect the Node.js application
  • Run npm install
  • Execute npm start
  • Expose the service on a public URL
5

Note the deployment URL

Railway provides a URL like:
Update your SIGNALING_PUBLIC_URL in the matchmaker and host config:

Docker Deployment

Create a Dockerfile in the Server/ directory:
Build and run:

Kubernetes / Docker Compose

Run with:

Horizontal Scaling

The signaling server supports horizontal scaling via Redis pub/sub:
How it works:
  1. Each instance maintains local WebSocket connections
  2. Messages are published to Redis channel room:{roomId}
  3. All instances subscribed to that channel receive and forward messages
  4. Local room state is synchronized via Redis atomic operations
No sticky sessions required. Clients can connect to any instance.

Load Balancing

For multiple instances, use a load balancer with WebSocket support:
  • NGINX: Enable proxy_http_version 1.1 and upgrade headers
  • HAProxy: Use option http-server-close
  • AWS ALB: Enable WebSocket support in target group
  • Railway: Automatically load balances with 0 configuration

Monitoring

Prometheus Metrics

The server exposes metrics at /metrics:

Health Checks

  • Liveness: GET /healthz - Always returns 200 if server is running
  • Readiness: GET /readyz - Returns 200 only if Redis is connected and not draining

Logging

The server uses structured JSON logging (Pino):
Set PRETTY_LOGS=true for human-readable output during development.

Troubleshooting

Symptoms: Server crashes or readiness check failsSolutions:
  • Verify Redis is running: redis-cli ping
  • Check REDIS_URL format: redis://[user:password@]host:port[/db]
  • Verify network connectivity (firewall, security groups)
  • For Railway: Ensure Redis service is in the same project
Solution: Change the port or kill the process using it
Cause: Client is making HTTP request instead of WebSocket upgradeSolution: Ensure client uses ws:// or wss:// protocol:
Cause: ALLOWED_ORIGINS is configured but client origin doesn’t matchSolution: Add client origin to allowed list:
Solutions:
  • Lower BACKPRESSURE_CLOSE_THRESHOLD_BYTES to close slow clients faster
  • Enable rate limiting with stricter limits
  • Scale horizontally with more instances
  • Monitor and close inactive connections
Cause: Redis pub/sub not workingDiagnosis:
Solutions:
  • Verify all instances use the same REDIS_URL
  • Check Redis logs for errors
  • Ensure Redis allows pub/sub (not in cluster mode with restrictions)

Security Best Practices

For production deployments:
  • Always use WSS (secure WebSocket): REQUIRE_WSS=true
  • Restrict origins: ALLOWED_ORIGINS=https://yourgame.com
  • Enable JWT authentication for sensitive applications
  • Use managed Redis with authentication and encryption
  • Monitor rate limit violations
  • Set up alerts for circuit breaker openings
  • Keep dependencies updated: npm audit

Next Steps