Configure your own STUN and TURN servers for Discourse Voice

AI-generated summary

This guide explains how self-hosting Discourse administrators can configure custom STUN and TURN servers for Discourse Voice, which relies on WebRTC for voice and video calls. While the platform provides public STUN servers by default, administrators can replace them or add TURN servers to support networks where direct peer-to-peer connections fail. This configuration applies to Voice’s peer-to-peer calls; rooms using LiveKit utilize LiveKit’s own ICE/TURN configuration instead.

STUN servers help browsers discover their public IP addresses for direct connections, while TURN servers relay media when direct connections are unsuccessful. The guide recommends using a dedicated TURN server with shared-secret authentication and an empty STUN setting. This setup provides public-address discovery via the server-reflexive candidate returned by authenticated TURN allocations, eliminating the need for a separate STUN server. Importantly, configuring only TURN does not force all calls through the relay; both direct and relayed connections are attempted.

For self-hosted setups, administrators can use managed services supporting the TURN REST API or run coturn themselves. Requirements include a server with a public IP, sufficient bandwidth, a dedicated hostname, and proper firewall access for TURN listeners and UDP relay ports. The guide provides an example configuration for coturn, including generating a random shared secret and configuring the server to use it.

Security and abuse prevention are emphasized. Since TURN credentials are not tied to browser origins, administrators should restrict Voice access to specific groups, monitor bandwidth and allocation counts, set quotas, block access to internal destinations, and keep coturn updated. The shared secret should be unique to the Discourse deployment. When no-stun is enabled, the server stops offering anonymous standalone STUN service.

Alternatives include replacing only public STUN servers by setting voice_stun_servers with custom URIs, or using TURN with fixed usernames and passwords if shared-secret authentication is unsupported. However, the latter approach is discouraged as it forces relay connections when the STUN list is empty and makes credentials easier to reuse outside the site.

:warning: If you are hosted by us, this is already pre-configured on your site. This guide is for admins self-hosting Discourse.

Discourse Voice uses WebRTC for voice and video calls. It ships with public STUN servers to help participants connect directly. Admins can replace those servers and add TURN to support networks where direct connections fail.

For a server dedicated to your community, we recommend TURN with shared-secret authentication and an empty STUN setting. This provides public-address discovery and a relay fallback without distributing a permanent TURN password.

This guide applies to Voice’s peer-to-peer calls. Rooms using LiveKit use LiveKit’s own ICE/TURN configuration instead. Learn about Voice’s LiveKit configuration.

What do STUN and TURN do?

  • STUN helps a browser discover its public IP address and port so it can attempt a direct connection.
  • TURN relays media when a direct connection cannot be established.

An authenticated TURN allocation also returns the browser’s public address. WebRTC can use this as a server-reflexive candidate, providing the address-discovery benefit of STUN without a separate STUN server. TURN specification.

With shared-secret TURN configured, Voice allows both direct and relayed connections even when its STUN setting is empty. Configuring only TURN servers does not force every call through the relay. Voice’s ICE configuration.

1. Prepare a TURN server

You can use a managed TURN service that supports TURN REST API shared-secret authentication, or run coturn yourself.

For a self-hosted setup, prepare:

  • A server with a public IP address and sufficient bandwidth for relayed calls.
  • A hostname such as turn.example.com, pointing directly to that server.
  • Firewall access for its TURN listener and UDP relay port range.
  • A valid certificate if you offer TURN over TLS.

Participants’ browsers connect to TURN directly. An ordinary HTTP reverse proxy or CDN proxy cannot carry TURN traffic.

Example coturn configuration

Generate a random secret:

openssl rand -hex 32

Keep the result private. You will enter the same value in coturn and Discourse.

On a server with a directly assigned public IP, use the following as a starting point in /etc/turnserver.conf:

listening-port=3478

fingerprint
realm=turn.example.com

use-auth-secret
static-auth-secret=REPLACE_WITH_YOUR_RANDOM_SECRET

# Disable standalone STUN requests.
# Authenticated TURN allocations still return the client's public address.
no-stun

min-port=49152
max-port=65535

no-multicast-peers

# This example starts without TLS.
no-tls
no-dtls

Replace the hostname and secret, protect the configuration file, and restart coturn. Remove any conflicting no-auth or static user= configuration. Coturn’s shared-secret mode enables the authentication mechanism it needs internally. Coturn configuration reference.

Allow inbound traffic to:

Port Protocol Purpose
3478 UDP and TCP Browser connections to TURN
49152–65535 UDP Relayed media

Allow the corresponding outbound traffic too. The relay range must match min-port and max-port.

If the server sits behind NAT, configure coturn’s external-ip=PUBLIC_IP/PRIVATE_IP mapping and forward the listener and relay ports. Relay ports must retain their port numbers through NAT. Coturn deployment options.

Add TLS for restrictive networks

TURN over TLS provides another connection option for participants whose networks block UDP.

Remove no-tls and configure:

tls-listening-port=5349
cert=/path/to/fullchain.pem
pkey=/path/to/privkey.pem

Open 5349/TCP, ensure coturn can read the certificate and key, and restart it after certificate renewals.

You can use 443/TCP instead if that port is available on the TURN server. This may help on restrictive networks, although some networks also inspect and block non-HTTP traffic on port 443. The UDP relay range is still required when browsers reach TURN over TCP or TLS. Coturn server documentation.

2. Configure Discourse

In Admin → Settings, search for these Voice settings:

Setting Value
voice_stun_servers Empty — remove the default entries
voice_turn_secret The value used for coturn’s static-auth-secret
voice_turn_secret_servers Your TURN URIs, separated by |
voice_turn_servers Empty
voice_turn_username Empty
voice_turn_credential Empty

For the configuration above, enter this in voice_turn_secret_servers:

turn:turn.example.com:3478?transport=udp|turn:turn.example.com:3478?transport=tcp

If you enabled TLS, add its endpoint:

turn:turn.example.com:3478?transport=udp|turn:turn.example.com:3478?transport=tcp|turns:turn.example.com:5349?transport=tcp

Use turn: and turns: URIs, without //. Only list endpoints your server actually supports.

The voice_turn_secret_servers list uses credentials generated from the shared secret. The separate voice_turn_servers list uses a fixed username and password. Voice setting definitions.

Save the settings, then have participants leave and rejoin calls to obtain the new configuration.

3. Verify the setup

Test with two participants on different networks, such as home broadband and mobile data. Confirm audio works in both directions, then test video and screen sharing.

In Chromium browsers, open chrome://webrtc-internals before joining:

  • A srflx candidate represents a discovered public address.
  • A relay candidate represents an available TURN relay.
  • The selected candidate pair shows the connection actually carrying media.

A successful direct call does not prove relaying works. Also test from a network that requires TURN, or use a WebRTC test client with iceTransportPolicy: "relay" and temporary credentials.

Check coturn’s logs for successful authenticated allocations. Requests without valid credentials must not obtain a relay allocation. An initial 401 authentication challenge is normal; repeated authentication failures need investigation.

Keep the server dedicated to your community

The shared secret stays on Discourse and the TURN server. Participants receive temporary credentials instead. Voice currently generates credentials valid for creating allocations for 12 hours; an established allocation can continue while it is refreshed. Voice’s credential generation.

This prevents an anonymous open relay, but TURN credentials are not tied to a browser origin: a participant can copy and reuse their temporary credentials. To limit abuse:

  • Restrict Voice access to the intended groups.
  • Monitor relay bandwidth and allocation counts.
  • Set coturn allocation quotas and bandwidth limits appropriate to your community.
  • Block relay access to private, link-local, and other internal destinations reachable from the TURN host.
  • Keep coturn updated and rotate the shared secret if it is exposed.

Use a dedicated secret for this Discourse deployment. With no-stun enabled, the server also stops offering anonymous standalone STUN service. Coturn authentication and access controls.

Alternatives

Replace only the public STUN servers

Set voice_stun_servers to your own STUN URIs, separated by |:

stun:stun.example.com:3478

Leave the TURN settings empty if you do not need a relay. STUN alone cannot make calls work on every network. A coturn server configured with no-stun cannot serve this endpoint.

Use TURN with a fixed username and password

If your provider does not support shared-secret authentication, configure voice_turn_servers, voice_turn_username, and voice_turn_credential. Leave the shared-secret settings empty.

Participants receive those fixed credentials, which makes them easier to reuse outside your site. Also, Voice currently forces relay connections when static TURN servers are configured and the STUN list is empty. Prefer shared-secret authentication when your provider supports it. Voice’s ICE configuration.

2 Likes