If you’ve ever set up your own self-hosted instance of Jitsi Meet, you might find that some of the folks using it aren’t able to connect. The root issue for this tends to be because one or more people are behind NAT and despite using STUN to try to figure out their public addresses and do NAT traversal, there’s not a path to pass media between everyone.

So how do you get this magic on your own version of Jitsi Meet? After all, this doesn’t seem to be a problem on the instance at meet.jit.si.

Let’s start by setting up your own Coturn server. Coturn is an open-source implementation of STUN and TURN and it’s conveniently dockerized. While you probably do want to set it up with TLS, for the sake of just getting it started, you can run it with some configuration like this:

docker run --network=host coturn/coturn \
           -n --log-file=stdout \
           --min-port=49160 --max-port=49200 \
           --lt-cred-mech --fingerprint \
           --no-multicast-peers --no-cli \
           --no-tlsv1 --no-tlsv1_1 \
           --external-ip= \
           --static-auth-secret=changeme \

In the above example, a static auth secret of changeme is set up for use with Jitsi. The external IP (the example one where this server is running) is set to, though this can vary based upon the host. The coturn documentation does provide a way to get this dynamically by specifying it as '$(detect-external-ip)'.

Ideally you should have this on a host that allows you to have port 443 exposed over TLS, since this will work around most restrictive firewall rules as well versus just NAT (it’s using UDP port 3478 without TLS).

With this configured, you can set it up in Jitsi Meet. For the dockerized version, you’ll need this .env configuration:

# Specify Coturn for use in getting the external IP

# Use a turn server running locally

# Specify the external IP

If you do set up coturn up with TLS, just note that all the above is the same, but replace TURN with TURNS, and the port to 443. This does mean you’ll need a reverse proxy to ship requests to the right hostname for a single IP address or multiple IP addresses.

And that’s it. Not all of this configuration and how to use it is well documented, so here’s how I got it to work.