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
ws- WebSocket serverredis- Redis client with pub/sub supportexpress- HTTP server for health checkspino- Structured loggingzod- Schema validationjsonwebtoken/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
2
Start the signaling server
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
- 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 aDockerfile in the Server/ directory:
Kubernetes / Docker Compose
- Docker Compose
- Kubernetes
Horizontal Scaling
The signaling server supports horizontal scaling via Redis pub/sub:- Each instance maintains local WebSocket connections
- Messages are published to Redis channel
room:{roomId} - All instances subscribed to that channel receive and forward messages
- 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.1and 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):PRETTY_LOGS=true for human-readable output during development.
Troubleshooting
Error: Redis connection failed
Error: Redis connection failed
Symptoms: Server crashes or readiness check failsSolutions:
- Verify Redis is running:
redis-cli ping - Check
REDIS_URLformat:redis://[user:password@]host:port[/db] - Verify network connectivity (firewall, security groups)
- For Railway: Ensure Redis service is in the same project
Error: EADDRINUSE (port already in use)
Error: EADDRINUSE (port already in use)
Solution: Change the port or kill the process using it
WebSocket connection fails with 426 Upgrade Required
WebSocket connection fails with 426 Upgrade Required
Cause: Client is making HTTP request instead of WebSocket upgradeSolution: Ensure client uses
ws:// or wss:// protocol:Connection rejected: Origin not allowed
Connection rejected: Origin not allowed
Cause:
ALLOWED_ORIGINS is configured but client origin doesn’t matchSolution: Add client origin to allowed list:High memory usage with many connections
High memory usage with many connections
Solutions:
- Lower
BACKPRESSURE_CLOSE_THRESHOLD_BYTESto close slow clients faster - Enable rate limiting with stricter limits
- Scale horizontally with more instances
- Monitor and close inactive connections
Messages not reaching clients on different instances
Messages not reaching clients on different instances
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
Next Steps
- Matchmaker Deployment - Set up host registration and matching
- Host Setup - Configure Windows hosts to connect to this signaling server
- Client Deployment - Deploy the browser client