Skip to main content

Coturn TURN Server

TURN (Traversal Using Relays around NAT) server for WebRTC media relay.

Overview

Coturn provides NAT traversal for WebRTC connections that cannot establish direct peer-to-peer connections. This is essential for:

  • Clients behind symmetric NAT
  • Restrictive corporate firewalls
  • Mobile networks with carrier-grade NAT

Configuration

turnserver.conf

Located at ~/ravenhelm/services/coturn/turnserver.conf:

# Network settings
listening-port=3478
tls-listening-port=5349

# External IP (public-facing)
external-ip=67.198.117.118

# Relay ports for media
min-port=49152
max-port=49200

# Realm for authentication
realm=turn.ravenhelm.dev

# Use fingerprinting for TURN messages
fingerprint

# Long-term credential mechanism (required for LiveKit)
lt-cred-mech

# Disable CLI for security
no-cli

# Logging
log-file=stdout
verbose

# Security settings
no-multicast-peers
no-tlsv1
no-tlsv1_1

# Allow localhost for testing
allow-loopback-peers

Docker Configuration

services:
coturn:
image: coturn/coturn:latest
container_name: coturn
restart: unless-stopped
network_mode: host # Required for UDP relay
volumes:
- ./turnserver.conf:/etc/coturn/turnserver.conf:ro
command: -c /etc/coturn/turnserver.conf --static-auth-secret=${TURN_SECRET}

Note: network_mode: host is required because Coturn needs direct access to network interfaces for UDP relay.

Port Usage

PortProtocolPurpose
3478UDP/TCPSTUN/TURN listening
5349TCPTURNS (TLS)
49152-49200UDPMedia relay ports

Integration with LiveKit

LiveKit is configured to use Coturn for TURN relay:

# In livekit.yaml
turn:
enabled: true
domain: turn.ravenhelm.dev
tls_port: 5349
udp_port: 3478
external_tls: true

Authentication

Coturn uses static auth secret shared with LiveKit:

# Environment variable
TURN_SECRET=<shared_secret>

LiveKit generates time-limited TURN credentials using this secret for each client connection.

Testing

Test STUN connectivity

# Using webrtc-internals in Chrome
# Navigate to chrome://webrtc-internals/
# Look for ICE candidates with "srflx" type

# Or use online tester
# https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/

Test TURN relay

# Check if TURN is responding
nc -vzu 67.198.117.118 3478

# View logs
docker logs coturn

Troubleshooting

No relay candidates

Symptoms: WebRTC connections fail for some users

Diagnosis:

  1. Check firewall allows UDP 3478 and 49152-49200
  2. Verify external IP is correct
  3. Test TURN credentials

Solution:

# Verify port is reachable
nc -vzu <external_ip> 3478

# Check coturn is running
docker ps | grep coturn

# View logs
docker logs coturn --tail=50

Authentication failures

Symptoms: "401 Unauthorized" in TURN

Diagnosis:

  1. Verify TURN_SECRET matches between Coturn and LiveKit
  2. Check credential time sync

Solution:

# Verify environment variable
docker exec coturn env | grep TURN

# Restart with correct secret
docker-compose restart coturn

See Also

  • [[LiveKit]] - WebRTC infrastructure
  • [[Voice-Gateway]] - Voice agent service