icey-server includes an embedded RFC 5766 TURN relay. It runs on a second port alongside the HTTP/WebSocket server. No external TURN service needed.
TURN exists for one reason: when the browser and server cannot establish a direct UDP path (symmetric NATs, restrictive firewalls, carrier-grade NAT), the TURN relay forwards media through a reachable address.
--no-turn and add it later.Disable TURN. Direct paths work on the local network.
icey-server --no-turn --source ./demo.mp4Or in config:
{
"turn": {
"enabled": false
}
}Server has a direct public IP. Set externalIp to that address.
icey-server --turn-external-ip 203.0.113.50 --source ./demo.mp4Or in config:
{
"turn": {
"enabled": true,
"externalIp": "203.0.113.50"
}
}Make sure port 3478 (UDP + TCP) is open in your firewall.
Server is behind a NAT (AWS, GCP, most VPS providers). The server's network interface has a private IP, but there is a public IP mapped to it.
icey-server --turn-external-ip <YOUR_PUBLIC_IP> --source ./demo.mp4This is where most people get stuck. If externalIp is not set, TURN allocations advertise the private address. Browsers outside the network get an address they cannot reach, and media fails silently. The signalling will look fine. The browser will show "connecting." Video will never appear.
To find your public IP on common cloud providers:
# AWS
curl -s http://169.254.169.254/latest/meta-data/public-ipv4
# GCP
curl -s -H "Metadata-Flavor: Google" http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip
# Generic
curl -s https://ifconfig.me| Port | Protocol | Direction | Purpose |
|---|---|---|---|
| 3478 | UDP | Inbound | TURN relay (primary) |
| 3478 | TCP | Inbound | TURN relay (fallback) |
TURN uses UDP by default. TCP is a fallback for networks that block UDP. Both should be open.
If browsers connect to signalling but video never appears:
externalIp is set and correct. This is the cause 90% of the time.nc -u <ip> 3478 to test.If the browser cannot even see the server peer in the UI, the problem is signalling, not TURN. Check the WebSocket connection first.
If you are building your own TURN server using icey's turn module rather than using the embedded server in icey-server, see the TURN module guide and the TURN server recipe.