WebRTC signaling server for Music Assistant remote connections. This server enables secure peer-to-peer connections between the hosted PWA and local Music Assistant instances without requiring port forwarding.
- Fork this repository
- Connect to Render.com
- Create a new Web Service pointing to your fork
- Set root directory to
/and start command topnpm start - Your signaling server will be at
wss://your-app.onrender.com/ws
pnpm install
pnpm start
# Server runs at ws://localhost:8787/wsmise install # Install Node.js 20
mise run dev # Run locally
# Or with Docker:
mise run docker:up # Build and run with Docker
# Server runs at ws://localhost:8787/wsdocker run -p 8787:8787 ghcr.io/music-assistant/signaling-server:latest
# Server runs at ws://localhost:8787/wspnpm install
pnpm dlx wrangler login
pnpm deploy┌─────────────────────────────────────────────────────────────────────┐
│ Signaling Server (Cloudflare Workers) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Durable Object │ │
│ │ - Maintains WebSocket connections │ │
│ │ - Routes signaling messages │ │
│ │ - Manages Remote ID registry │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
↑ ↑
│ WebSocket │ WebSocket
│ (register-server) │ (connect-request)
│ │
┌─────────────┴─────────────┐ ┌────────────┴────────────┐
│ MA Server Instance │ │ PWA Client │
│ (Local Network) │ │ (app.music-assistant.io)│
│ │ │ │
│ Remote ID: MA-X7K9-P2M4 │◄──────►│ Connects to: MA-X7K9 │
└───────────────────────────┘ P2P └──────────────────────────┘
WebRTC
docker run -p 8787:8787 ghcr.io/music-assistant/signaling-server:latestOr use mise tasks for local development:
mise run docker:up # Build and run
mise run docker:up:detached # Run in backgroundPrerequisites: Cloudflare account, Node.js 20+, Wrangler CLI
pnpm install
pnpm dlx wrangler login
pnpm deploypnpm install
pnpm start
# Or with mise:
mise run devThe server will be available at http://localhost:8787
Connect via WebSocket for signaling.
Register Server
{
"type": "register-server",
"remoteId": "MA-X7K9-P2M4"
}Response:
{
"type": "registered",
"remoteId": "MA-X7K9-P2M4"
}Signaling Messages (to client)
{
"type": "answer|ice-candidate",
"sessionId": "abc123",
"data": { /* SDP or ICE candidate */ }
}Connect Request
{
"type": "connect-request",
"remoteId": "MA-X7K9-P2M4"
}Response:
{
"type": "connected",
"remoteId": "MA-X7K9-P2M4",
"sessionId": "abc123"
}Signaling Messages (to server)
{
"type": "offer|ice-candidate",
"data": { /* SDP or ICE candidate */ }
}Health Check
GET /health
Check Remote ID Status
GET /api/check/:remoteId
Response:
{
"online": true
}-
No Authentication on Signaling: The signaling server only facilitates connection establishment. Actual authentication happens over the WebRTC connection directly with the MA server.
-
Remote ID Security: Remote IDs should be sufficiently random to prevent guessing. The MA server generates these IDs.
-
Rate Limiting: Built-in rate limiting protects against brute force attacks on the
/api/checkendpoint and WebSocket connections.
Docker images are automatically published to GitHub Container Registry on each release:
# Latest version
docker run -p 8787:8787 ghcr.io/music-assistant/signaling-server:latest
# Specific version
docker run -p 8787:8787 ghcr.io/music-assistant/signaling-server:2.0.0
# Custom port
docker run -p 9000:9000 -e PORT=9000 ghcr.io/music-assistant/signaling-server:latestdocker build -t ma-signaling-server .
docker run -p 8787:8787 ma-signaling-serverservices:
signaling:
image: ghcr.io/music-assistant/signaling-server:latest
ports:
- "8787:8787"
environment:
- PORT=8787
restart: unless-stoppedThis project uses mise for version management and task running.
Run mise run to see all available tasks.
mise run docker:build # Build the Docker image
mise run docker:build:nocache # Build without cache
mise run docker:up # Build and run container
mise run docker:up:detached # Build and run in background
mise run docker:down # Stop and remove container
mise run docker:logs # Follow container logs
mise run docker:test # Test build and run
mise run docker:clean # Remove built images
mise run dev # Run local dev server
mise run build # Build TypeScriptPORT: Server port (default:8787)ENVIRONMENT: Set to "production" or "development"
To use a custom domain (e.g., signaling.music-assistant.io):
- Add the domain to Cloudflare
- Update
wrangler.toml:
routes = [
{ pattern = "signaling.music-assistant.io/*", zone_name = "music-assistant.io" }
]- Deploy with
pnpm deploy