Skip to main content

Overview

Crosslink’s signaling nodes are horizontally scalable with Redis. Relay channels are ephemeral and process-local, with region catalogs and host-side fallback for scale-out.

Quick start

This starts both services on localhost:
  • Signaling: ws://127.0.0.1:8081
  • Relay: http://127.0.0.1:8082

Services

Signaling service

The signaling service helps devices find each other and route pairing codes. What it sees:
  • Hashed pairing codes
  • Opaque signed blobs (not readable without private keys)
  • Device fingerprints (for routing)
What it cannot see:
  • Plaintext content
  • Session keys
  • Private keys

Relay service

The relay service forwards encrypted traffic when a direct connection isn’t possible. What it sees:
  • Ciphertext (encrypted frames)
What it cannot see:
  • Plaintext content
  • Session keys
  • Message content

Building your own container image

Crosslink does not publish Docker images or Dockerfiles today. Each service is a plain Node.js CLI (@crosslink/signaling’s crosslink-signaling bin, @crosslink/relay’s crosslink-relay bin) built with npm run build, so it packages into a container however you already build Node services — copy services/signaling (or services/relay) and its built dist/ into a node:20-slim (or similar) base image and run the bin. Both services require a bind before phones can reach them from anywhere but the machine they’re on; use your normal container port-mapping.

Environment variables

Signaling

Relay

Outside of local development, both services refuse to start without an auth token (CROSSLINK_SIGNALING_TOKEN / CROSSLINK_RELAY_TOKEN) or the per-machine dev tokens written to .crosslink-data/dev-tokens.json. Set these explicitly for any deployment other services will connect to.

Production considerations

TLS termination

Use a reverse proxy (nginx, Caddy, Cloudflare) for TLS:

Load balancing

Signaling can be horizontally scaled when every replica uses the same Redis deployment. Relay WebSockets require channel affinity; deploy independent regional relay pools and let hosts allocate using ordered regional fallback:
Do not round-robin an allocated relay channel across processes. Either keep WebSocket affinity for the channel or publish each relay pool as a distinct regional allocation endpoint.

Monitoring

Monitor these metrics:

Backup

Relay channel state and signaling presence are ephemeral. Redis persistence is not required for correctness after a restart, but production configuration must be recoverable. Back up:
  • Environment variables (including auth tokens)
  • TLS certificates
  • Your deployment manifests

Security checklist

  • Use TLS termination (nginx, Caddy, Cloudflare)
  • Use rediss://, Redis ACLs, and a private Redis network
  • Set channel, client, lifetime-byte, bandwidth, and edge connection quotas
  • Run in a DMZ or private network
  • Monitor connection counts and error rates
  • Set CROSSLINK_SIGNALING_TOKEN / CROSSLINK_RELAY_TOKEN explicitly
  • Enable health checks
  • Keep secrets out of source control (env vars, a secrets manager, or Docker/Kubernetes secrets)
  • Regularly update the packages
  • Restrict network access with firewall rules

Custom deployment

Kubernetes

Systemd service