Skip to content

Real-Time and WebRTC

Most platforms make WebRTC a research project: provision a TURN server, manage UDP port pools, wire up STUN, generate ICE credentials, hope your STUN/TURN survives a load test. On Watasu it’s a process suffix.

Name a process *-rtc and Watasu provisions a dedicated TURN gateway per process, allocates a public UDP port, gives every replica a stable public hostname, and injects TURN_* env vars into your container.

That’s the whole setup.

  • WebRTC SFUs (Selective Forwarding Units) for video conferencing
  • voice agents and call-handling backends
  • real-time gaming or low-latency multiplayer
  • live streaming ingest with WebRTC publish
  • anything where UDP, low latency, and ICE matter
web: bundle exec puma # signaling server
sfu-rtc: node sfu/server.js # the SFU
worker: bundle exec sidekiq

Push, scale, done.

Terminal window
git push watasu main
watasu pods:scale sfu-rtc=2 --app my-app

What Watasu provisions for each *-rtc process

Section titled “What Watasu provisions for each *-rtc process”

For every process whose name ends in -rtc, Watasu creates:

  • a dedicated TURN gateway
  • a per-process public TURN hostname of the form <route-token>.turn.watasuhost.com
  • a per-replica public hostname for direct-replica routing: <route-token>-01.watasuhost.com, <route-token>-02.watasuhost.com, and so on
  • a unique public UDP port allocated from a managed pool
  • the matching TURN credentials as env vars in the container

When you scale the process, every new replica gets its own stable hostname.

Each *-rtc container receives:

VariablePurpose
TURN_SHARED_SECRETUsed to mint ephemeral TURN credentials at request time
TURN_HOSTNAMEPublic TURN hostname for this process
TURN_PORTPublic UDP port allocated to this process
TURN_REALMTURN realm used by your gateway
WATASU_RTC_*Generic platform-side info (process name, replica index)

Use TURN_SHARED_SECRET to generate ephemeral credentials per session in your signaling layer (the standard ephemeral-credential pattern). Hand the resulting credentials to the browser as the ICE configuration.

Watasu provides the ICE/TURN infrastructure. The SFU itself is your code or a library you choose:

  • mediasoup (Node.js) — popular, programmable
  • Pion (Go) — pure-Go WebRTC stack
  • Janus, Jitsi Videobridge, LiveKit Server — drop-in SFU servers
  • anything else that speaks WebRTC

Build it into a container, name the process *-rtc, and it works.

*-rtc processes scale just like any other:

Terminal window
watasu pods --app my-app
watasu pods:scale sfu-rtc=4 --app my-app
watasu pods:type sfu-rtc=standard-4x --app my-app

Each replica gets its own public hostname (<route-token>-01..., -02..., etc.). Use these hostnames in your signaling layer to route a session to a specific replica when you need replica affinity.

*-rtc workloads run in nbg1 or fsn1 (the two German data centers) for low-latency UDP routing. You don’t pick — Watasu handles placement.

A shared TURN server is a shared bottleneck. Once one tenant’s call volume saturates the cluster’s TURN bandwidth, everyone suffers. Watasu provisions a dedicated TURN gateway per *-rtc process so:

  • your traffic doesn’t compete with another tenant’s
  • your failure domain is your own
  • scaling your RTC process scales your TURN capacity at the same time

This is the difference between a hosting setup that survives a viral product launch and one that doesn’t.

  • It doesn’t ship an SFU for you. You bring the WebRTC code.
  • It doesn’t handle signaling — that’s a regular web process in your app.
  • It doesn’t replace authentication or session management — that’s your app’s job.

For private service-to-service TCP (microservices, not WebRTC), see Private Networking.