Advanced
TURN with hairpin
A browser phone on a network that lets no UDP out cannot reach the server's audio ports and needs a relay. hairpin is sidetone's TURN server: one binary, a state file, a REST API, and a quickstart that prints what to paste into sidetone.
When you need it
You do not need it for desk phones, nor for browser phones on the office network or at home: the server is the public party and the browser sends audio straight to it. You need it when a user opens the Phone page or Offhook from a hotel, a conference centre or a strict corporate network, where UDP is blocked and sometimes everything but HTTPS. The browser then sends its audio to the relay, over TCP 443 if it must, and the relay passes it on to the server.
The relay has to stand where such a network can reach it: on the internet, with a public address, not on the office LAN. A small VM is plenty. Run two, with one secret, for a relay that is always there; a browser tries every server it is given, so one that is down costs nothing.
1. Install hairpin
$ git clone https://github.com/eNetIdeas/hairpin && cd hairpin && make build $ ./bin/hairpin quickstart -data-dir /var/lib/hairpin Admin API token (shown once, store it now): hairpin_… Public address: 203.0.113.10 (as stun.l.google.com:19302 sees this machine) Shared secret (shown once; it is what mints time-limited credentials): 4f9c… For sidetone (PUT /v1/settings, or the console's Settings page): ice_servers [{"urls":["stun:203.0.113.10:3478","turn:203.0.113.10:3478?transport=udp"]}] and turn_secret, the shared secret above. $ ./bin/hairpin -data-dir /var/lib/hairpin -listen udp://0.0.0.0:3478,tcp://0.0.0.0:3478
Or the container, ghcr.io/enetideas/hairpin, with host networking like sidetone's. Open 3478 over UDP and TCP, and the relay range, 49152 to 65535 over UDP, in the firewall. The admin page is on 127.0.0.1:3479; everything is set through its API, live, as in sidetone.
2. Give the servers to sidetone
Settings → Browser phones, one server a line, or:
$ api -X PUT -d '{"ice_servers":[{"urls":["stun:203.0.113.10:3478","turn:203.0.113.10:3478?transport=udp","turn:203.0.113.10:3478?transport=tcp"]}], "turn_secret":"4f9c…"}' localhost:8080/v1/settings
From then on the Phone page and Offhook ask the server for its ICE servers at every call and get credentials minted for that user, good for a day: the TURN REST API scheme, which coturn calls static-auth-secret, so a coturn you already have works the same way. The secret is write-only. An entry with a username and credential of its own is handed over as it is, to every user.
3. The hotel case: TURN over TLS on 443
A network that allows only HTTPS out needs the relay on port 443 with a certificate, so that the browser's traffic looks like any other. Give the relay a DNS name, let hairpin obtain a certificate, and add a tls listener:
$ ./bin/hairpin -data-dir /var/lib/hairpin -acme-domain turn.example.com \ -listen udp://0.0.0.0:3478,tcp://0.0.0.0:3478,tls://0.0.0.0:443
Port 80 must be reachable for the certificate challenge, and binding 80 and 443 as a non-root user needs setcap cap_net_bind_service=+ep hairpin. Then add turns:turn.example.com:443?transport=tcp to the list in sidetone. One name per relay, not a round-robin name for several: a browser resolves a name to one address, and the certificate authority validates a name on the host it points to.
What it costs, and what it does not
Only calls from browsers that cannot reach the server go through the relay, and only their audio; desk phones and trunks are untouched. A relayed call's audio arrives at sidetone from the relay's address on the usual audio ports. hairpin bounds what one user may use (allocations, bandwidth) and bans addresses that guess at it; it relays to public addresses only unless told otherwise, so a relay on the internet is not a way into your network. A restart drains first, so a relay can be updated without cutting calls. Its own operator guide is one page.