STUN, TURN and ICE, Explained Without Jargon
What actually happens when a WebRTC connection is being set up: the roles of STUN, TURN and ICE, and why a relay is sometimes unavoidable.
Every explanation of WebRTC eventually drops three acronyms — STUN, TURN, ICE — and most readers' eyes glaze over. The ideas behind them are actually simple, and knowing them tells you exactly why a transfer is fast, slow, or impossible on a given network.
The problem: your device does not know its own address
At home, your laptop's address is something like 192.168.1.23 — valid only inside your Wi-Fi. The wider internet sees your router's public address instead, and the router only forwards incoming traffic that it recognizes as a reply to something you sent. Two devices in this situation cannot simply dial each other.
STUN: a mirror
A STUN server does one tiny job: you send it a packet, and it replies “here is the public address and port your packet appeared to come from.” Now your browser knows what it looks like from the outside. If both sides learn their public addresses and start sending to each other more or less simultaneously, many routers accept the traffic as replies — the classic “hole punching” trick. STUN servers carry almost no traffic and see no file data; they are address mirrors, nothing more.
TURN: a relay for when mirrors are not enough
Some networks defeat hole punching: symmetric NATs use a different public port for every destination, carrier-grade NAT stacks multiple layers, and strict firewalls block UDP outright (why direct connections fail). TURN is the fallback: a server that both sides can reach, which forwards traffic between them. It costs real bandwidth for the operator and adds a hop of latency — but critically, in WebRTC the traffic it forwards is already encrypted end-to-end. A TURN server cannot read what it relays; it only sees packet sizes, timing and addresses (direct vs relay).
TURN itself can run over UDP, TCP, and TLS on port 443 — the last one specifically to survive networks that only allow “normal HTTPS” traffic.
ICE: the tournament
ICE is the process that ties this together. Each browser gathers every address it might be reachable at — local addresses (“host candidates”), the STUN-discovered public address (“server-reflexive”), and TURN relay addresses. Both sides exchange these candidate lists through the signaling channel, then systematically test candidate pairs with small probe packets. Working pairs are ranked — direct beats relayed, local beats internet — and the best one carries the connection. Modern implementations use “trickle ICE”: candidates are exchanged as they are found rather than all at once, which shaves seconds off connection setup.
Reading your own connection
In ShareDrop.org, the connection badge is derived from the candidate pair that actually won, read live from WebRTC statistics: two host candidates mean a LAN transfer, a reflexive pair means direct across the internet, and any relay candidate means TURN is in the path. We deliberately never infer the mode from configuration — only from what the connection reports about itself.
Field notes
A practical detail from building this: TURN servers double as STUN servers, so a single relay deployment also provides the address-mirror function. And on developer machines, macOS's local-network permission can prevent mDNS host candidates from resolving between browsers on the same computer — a relay on loopback makes an excellent workaround for local testing (we run coturn 4.15 with short-lived REST credentials for exactly this).
Standards referenced
- RFC 8489 — Session Traversal Utilities for NAT (STUN): the address-mirror protocol.
- RFC 8656 — Traversal Using Relays around NAT (TURN): allocations, permissions, and why the relay never holds keys.
- RFC 8445 — Interactive Connectivity Establishment (ICE): candidate gathering, pairing and the connectivity checks described above.
- TURN REST API draft — the short-lived credential scheme our coturn deployment uses (and most production TURN services with it).