# Real-Time and WebRTC

> Run SFUs, voice agents, and real-time apps with \*-rtc processes. Each gets a dedicated TURN gateway, a public UDP port, and stable per-replica hostnames.

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.

## When to use `*-rtc`

* 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

## A minimal example

```text
web:     bundle exec puma                      # signaling server
sfu-rtc: node sfu/server.js                    # the SFU
worker:  bundle exec sidekiq
```

Push, scale, done.

```bash
git push watasu main
watasu pods:scale sfu-rtc=2 --app my-app
```

## 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.

## Environment variables

Each `*-rtc` container receives:

| Variable             | Purpose                                                 |
| -------------------- | ------------------------------------------------------- |
| `TURN_URL`           | Full TURN URL, e.g. `turn:<host>:<port>?transport=udp`  |
| `TURN_HOST`          | Public TURN hostname for this process                   |
| `TURN_PORT`          | Public UDP port allocated to this process               |
| `TURN_TRANSPORT`     | Transport for the allocated port (`udp`)                |
| `TURN_REALM`         | TURN realm used by your gateway                         |
| `TURN_AUTH_TYPE`     | Credential scheme (ephemeral shared-secret)             |
| `TURN_SHARED_SECRET` | Used to mint ephemeral TURN credentials at request time |
| `TURN_TTL_SECONDS`   | Recommended lifetime for minted credentials             |

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.

Each replica can also derive its own public hostname from the `WATASU_RTC_*` vars:

| Variable                                           | Purpose                                      |
| -------------------------------------------------- | -------------------------------------------- |
| `WATASU_RTC_BASE_HOST`                             | The process's base public hostname           |
| `WATASU_RTC_BASE_LABEL` / `WATASU_RTC_BASE_DOMAIN` | The hostname split into its parts            |
| `WATASU_RTC_INSTANCE_ORDINAL`                      | This replica's index (0-based)               |
| `WATASU_RTC_INSTANCE_INDEX_WIDTH`                  | Zero-padding width for per-replica hostnames |

For example, ordinal `0` with width `2` means this replica is reachable at `<base-label>-01.<base-domain>`.

## Bring your own SFU

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.

## Scaling RTC processes

`*-rtc` processes scale just like any other:

```bash
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.

## Region constraints

`*-rtc` workloads run in Watasu's German data centers for low-latency UDP routing. You don't pick — Watasu handles placement.

## Why per-process TURN matters

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.

## What this doesn't do

* 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](https://docs.watasu.io/apps/private-networking.md).

[View this page on the web](https://docs.watasu.io/apps/realtime/)
