# Configure your own STUN and TURN servers for Discourse Live

**URL:** <https://meta.discourse.org/t/configure-your-own-stun-and-turn-servers-for-discourse-live/414625>\
**Category:** Integrations\
**Tags:** live\
**Created:** [October 13, 2026, 10:44pm UTC](https://meta.discourse.org/t/configure-your-own-stun-and-turn-servers-for-discourse-live/414625 "2026-10-13T22:44:52Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)\
**Post date:** [October 13, 2026, 10:44pm UTC](https://meta.discourse.org/t/configure-your-own-stun-and-turn-servers-for-discourse-live/414625/1 "2026-10-13T22:44:52Z")

</div>

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

Discourse Live 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 running coturn as both your STUN and TURN server, with shared-secret authentication for TURN.** This provides public-address discovery and a relay fallback without distributing a permanent TURN password or relying on third-party STUN servers.

This guide applies to Live’s peer-to-peer calls. Rooms using LiveKit use LiveKit’s own ICE/TURN configuration instead. [Learn about Live’s LiveKit configuration](https://github.com/discourse/discourse/blob/main/plugins/live/docs/livekit.md).

## 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.

A browser that learns its public address can offer it as a **server-reflexive (`srflx`) candidate**, which is what makes direct connections through home and office NATs possible. Without one, most calls fall back to the TURN relay, adding latency and relay bandwidth.

**STUN must stay open even when you run TURN.** A TURN allocation response also contains the browser’s public address, but only some browsers (such as Firefox) use it as a candidate. Chromium-based browsers and Safari only learn their public address from a separate STUN Binding request, and browsers never attach credentials to Binding requests. If the server disables STUN (`no-stun`) or requires authentication for it (`secure-stun`), those browsers get no `srflx` candidate and every call they join is relayed.

With shared-secret TURN configured, Live allows both direct and relayed connections. **Configuring TURN does not force every call through the relay.** [Live’s ICE configuration](https://github.com/discourse/discourse/blob/main/plugins/live/lib/live/ice_config.rb).

## 1. Prepare a TURN server

You can use a managed TURN service that supports **TURN REST API shared-secret authentication** , or run [coturn](https://github.com/coturn/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:

```bash
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`:

```ini
listening-port=3478

fingerprint
realm=turn.example.com

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

# Do not add no-stun or secure-stun: browsers send STUN Binding requests
# without credentials, and many rely on them to discover their public address.

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](https://github.com/coturn/coturn/blob/master/examples/etc/turnserver.conf).

Anonymous STUN only reports a client’s own address back to it; it cannot relay traffic, so it does not turn your server into an open relay. Recent coturn versions keep the optional RFC 5780 and `MAPPED-ADDRESS` response attributes off by default, which keeps Binding responses close to request size and limits their usefulness for reflection attacks. Leave `rfc5780` and `stun-backward-compatibility` disabled.

Allow inbound traffic to:

| Port | Protocol | Purpose |
| --- | --- | --- |
| `3478` | UDP | STUN and TURN |
| `3478` | TCP | 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](https://github.com/coturn/coturn/wiki/turnserver).

### Add TLS for restrictive networks

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

Remove `no-tls` and configure:

```ini
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](https://github.com/coturn/coturn/wiki/turnserver).

## 2. Configure Discourse

In **Admin → Settings** , search for these Live settings:

| Setting | Value |
| --- | --- |
| `live_stun_servers` | Your coturn server’s STUN URI — replace the default entries |
| `live_turn_secret` | The value used for coturn’s `static-auth-secret` |
| `live_turn_secret_servers` | Your TURN URIs, separated by `|` |
| `live_turn_servers` | Empty |
| `live_turn_username` | Empty |
| `live_turn_credential` | Empty |

For the configuration above, enter this in `live_stun_servers`:

```plaintext
stun:turn.example.com:3478

```

And this in `live_turn_secret_servers`:

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

```

If you enabled TLS, add its endpoint:

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

```

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

Chromium-based browsers also send STUN requests to the TURN servers you list, so an empty `live_stun_servers` can work as long as coturn answers anonymous STUN. Listing the STUN URI explicitly makes the setup clearer, covers other browsers, and lets Live’s connection diagnostics test it on its own.

The `live_turn_secret_servers` list uses credentials generated from the shared secret. The separate `live_turn_servers` list uses a fixed username and password. [Live setting definitions](https://github.com/discourse/discourse/blob/main/plugins/live/config/locales/server.en.yml).

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, and **in more than one browser** — at least one Chromium-based browser and Firefox. Confirm audio works in both directions, then test video and screen sharing.

While in a peer-to-peer room, open the room’s **⋮** menu and choose **Connection diagnostics** :

- Under **STUN/TURN servers** , each server should show **Reachable**. TURN servers should list a **Relay address** , and UDP servers should list a **Public address**. “Public address: None” means STUN requests got no answer — check for `no-stun`/`secure-stun` and that `3478/UDP` is open.
- Under **Peers** , the route shows how each connection carries media: **Direct (same network)**, **Direct (through NAT via STUN)**, or **Relayed through TURN**. Most participants on ordinary home networks should connect directly.
- **Copy report** produces a text report you can share with whoever is troubleshooting. It includes participants’ IP addresses, so share it privately.

In Chromium browsers, `chrome://webrtc-internals` shows the same details at a lower level:

- 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. Live currently generates credentials valid for creating allocations for 12 hours; an established allocation can continue while it is refreshed. [Live’s credential generation](https://github.com/discourse/discourse/blob/main/plugins/live/lib/live/ice_config.rb).

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 Live 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. Your server will also answer anonymous STUN requests from anyone; this is expected, uses little bandwidth, and does not grant relay access. [Coturn authentication and access controls](https://github.com/coturn/coturn/blob/master/README.turnserver).

## Alternatives

### Replace only the public STUN servers

Set `live_stun_servers` to your own STUN URIs, separated by `|`:

```plaintext
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.

### Use TURN with a fixed username and password

If your provider does not support shared-secret authentication, configure `live_turn_servers`, `live_turn_username`, and `live_turn_credential`. Leave the shared-secret settings empty.

Participants receive those fixed credentials, which makes them easier to reuse outside your site. Also, Live 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. [Live’s ICE configuration](https://github.com/discourse/discourse/blob/main/plugins/live/lib/live/ice_config.rb).
