Changed TURN documentation so we can use both legacy and Element Call. Fixed a few broken internal links.

This commit is contained in:
Hans van Zijst 2025-01-08 14:51:11 +01:00
parent d85dcefbb9
commit d0c32f1ac6
Signed by: hans
GPG key ID: 43DBCC37BFDEFD72
6 changed files with 100 additions and 64 deletions

View file

@ -95,7 +95,7 @@ how to [setup and configure it](element-call).
# Element Web # Element Web
This is the fully-fledged web client, which is very [easy to set This is the fully-fledged web client, which is very [easy to set
up](element-call). up](element-web).
# TURN # TURN
@ -104,8 +104,8 @@ We may need a TURN server, and we'll use
[coturn](coturn) for that. [coturn](coturn) for that.
It's apparently also possible to use the built-in TURN server in Livekit, It's apparently also possible to use the built-in TURN server in Livekit,
which we'll use if we use [Element Call](call). It's either/or, so make sure which we'll use if we use [Element Call](element-call). It's either/or, so make
you pick the right approach. sure you pick the right approach.
You could possibly use both coturn and LiveKit, if you insist on being able to You could possibly use both coturn and LiveKit, if you insist on being able to
use both legacy and Element Call functionality. This is not documented here use both legacy and Element Call functionality. This is not documented here

View file

@ -5,16 +5,22 @@ include_toc: true
# TURN server # TURN server
You need an TURN server to connect participants that are behind a NAT firewall. You need a TURN server to connect participants that are behind a NAT firewall.
Because IPv6 doesn't really need TURN, and Chrome can get confused if it has Because IPv6 doesn't really need TURN, and Chrome can get confused if it has
to use TURN over IPv6, we'll stick to a strict IPv4-only configuration. to use TURN over IPv6, we'll stick to a strict IPv4-only configuration.
Also, because VoIP traffic is only UDP, we won't do TCP. Also, because VoIP traffic is only UDP, we won't do TCP.
IMPORTANT! TURN can also be offered by [LiveKit](../element-call#livekit), in TURN-functionality can be offered by coturn and LiveKit alike: coturn is used
which case you should probably not run coturn (unless you don't use LiveKit's for legacy calls (only one-on-one, supported in Element Android), whereas
built-in TURN server, or want to run both to support legacy calls too). Element Call (supported by ElementX, Desktop and Web) uses LiveKit.
In our documentation we'll enable both, which is probably not the optimal
solution, but at least it results in a system that supports old and new
clients.
Here we'll describe coturn, the dedicated ICE/STUN/TURN server that needs to
be configured in Synapse, [LiveKit](../element-call#livekit) has its own page.
# Installation # Installation
@ -73,24 +79,23 @@ certbot certonly --nginx -d turn.example.com
This assumes you've already setup and started nginx (see [nginx](../nginx)). This assumes you've already setup and started nginx (see [nginx](../nginx)).
{#fixssl} {#fixssl}
The certificate files reside under `/etc/letsencrypt/live`, but coturn The certificate files reside under `/etc/letsencrypt/live`, but coturn and
doesn't run as root, and can't read them. Therefore we create the directory LiveKit don't run as root, and can't read them. Therefore we create the directory
`/etc/coturn/ssl` where we copy the files to. This script should be run after `/etc/coturn/ssl` where we copy the files to. This script should be run after
each certificate renewal: each certificate renewal:
``` ```
#!/bin/bash #!/bin/bash
# This script is hooked after a renewal of the certificate, so # This script is hooked after a renewal of the certificate, so that the
# that it's copied and chowned and made readable by coturn: # certificate files are copied and chowned, and made readable by coturn:
cd /etc/coturn/ssl cd /etc/coturn/ssl
cp /etc/letsencrypt/live/turn.example.com/{fullchain,privkey}.pem . cp /etc/letsencrypt/live/turn.example.com/{fullchain,privkey}.pem .
chown turnserver:turnserver *.pem chown turnserver:turnserver *.pem
# We should restart either coturn or LiveKit, they cannot run both! # Make sure you only start/restart the servers that you need!
systemctl restart coturn systemctl try-reload-or-restart coturn livekit-server
#systemctl restart livekit-server
``` ```
@ -102,7 +107,8 @@ renew_hook = /etc/coturn/fixssl
``` ```
Yes, it's a bit primitive and could (should?) be polished. But for now: it Yes, it's a bit primitive and could (should?) be polished. But for now: it
works. works. This will copy and chown the certificate files and restart coturn
and/or LiveKit, depending on if they're running or not.
# Configuration {#configuration} # Configuration {#configuration}
@ -121,9 +127,13 @@ Now that we have this, we can configure our configuration file under
`/etc/coturn/turnserver.conf`. `/etc/coturn/turnserver.conf`.
``` ```
# We don't use the default ports, because LiveKit uses those
listening-port=3480
tls-listening-port=5351
# We don't need more than 10000 connections: # We don't need more than 10000 connections:
min-port=50000 min-port=40000
max-port=60000 max-port=49999
use-auth-secret use-auth-secret
static-auth-secret=<previously created secret> static-auth-secret=<previously created secret>
@ -133,7 +143,7 @@ user-quota=12
total-quota=1200 total-quota=1200
# Of course: substitute correct IPv4 address: # Of course: substitute correct IPv4 address:
listening-ip=185.206.232.60 listening-ip=111.222.111.222
# VoIP traffic is only UDP # VoIP traffic is only UDP
no-tcp-relay no-tcp-relay

View file

@ -3,11 +3,17 @@
# Only IPv4, IPv6 can confuse some software # Only IPv4, IPv6 can confuse some software
listening-ip=111.222.111.222 listening-ip=111.222.111.222
# Listening port for TURN (UDP and TCP):
listening-port=3480
# Listening port for TURN TLS (UDP and TCP):
tls-listening-port=5351
# Lower and upper bounds of the UDP relay endpoints: # Lower and upper bounds of the UDP relay endpoints:
# (default values are 49152 and 65535) # (default values are 49152 and 65535)
# #
min-port=50000 min-port=40000
max-port=60000 max-port=49999
use-auth-secret use-auth-secret
static-auth-secret=<very secure password> static-auth-secret=<very secure password>

View file

@ -11,7 +11,7 @@ here's what you need.
* **lk-jwt**. This authenticates Synapse users to LiveKit. * **lk-jwt**. This authenticates Synapse users to LiveKit.
* **LiveKit**. This is the "SFU", which actually handles the audio and video, and does TURN. * **LiveKit**. This is the "SFU", which actually handles the audio and video, and does TURN.
* **Element Call widget**. This is basically the webapplication, the part you see. * **Element Call widget**. This is basically the webapplication, the user interface.
As mentioned in the [checklist](../checklist.md) you need to define these As mentioned in the [checklist](../checklist.md) you need to define these
three entries in DNS and get certificates for them: three entries in DNS and get certificates for them:
@ -20,6 +20,9 @@ three entries in DNS and get certificates for them:
* `livekit.example.com` * `livekit.example.com`
* `call.example.com` * `call.example.com`
You may already have DNS and TLS for `turn.example.com`, as it is also used
for [coturn](../coturn).
For more inspiraten, check https://sspaeth.de/2024/11/sfu/ For more inspiraten, check https://sspaeth.de/2024/11/sfu/
@ -97,8 +100,7 @@ turn:
udp_port: 3478 udp_port: 3478
external_tls: true external_tls: true
keys: keys:
# KEY: SECRET were autogenerated by livekit/generate # KEY: SECRET were generated by "livekit-server generate-keys"
# in the lk-jwt-service environment variables
<KEY>: <SECRET> <KEY>: <SECRET>
``` ```
@ -109,6 +111,15 @@ chown root:turnserver /etc/livekit/livekit.yaml
chmod 640 /etc/livekit/livekit.yaml chmod 640 /etc/livekit/livekit.yaml
``` ```
Port `7880` is forwarded by nginx: authentication is also done there, and that
bit has to be forwarded to `lk-jwt-service` on port `8080`. Therefore, we
listen only on localhost.
The TURN ports are the normal, default ones. If you also use coturn, make sure
it doesn't use the same ports as LiveKit. Also, make sure you open the correct
ports in the [firewall](../firewall).
## TLS certificate ## TLS certificate
The TLS-certificate files are not in the usual place under The TLS-certificate files are not in the usual place under
@ -124,7 +135,7 @@ read them there too.
If you don't have coturn installed, you should create a directory under If you don't have coturn installed, you should create a directory under
`/etc/livekit` and copy the files to there. Modify the `livekit.yaml` file and `/etc/livekit` and copy the files to there. Modify the `livekit.yaml` file and
the [script to copy the files](../coturn/README.md#fixssl) to use that the [script to copy the files](../coturn/README.md#fixssl) to use that
directory. Don't forget to update the `renew_hook` in Letsencrypt. directory. Don't forget to update the `renew_hook` in Letsencrypt if you do.
The LiveKit API listens on localhost, IPv6, port 7880. Traffic to this port is The LiveKit API listens on localhost, IPv6, port 7880. Traffic to this port is
forwarded from port 443 by nginx, which handles TLS, so it shouldn't be reachable forwarded from port 443 by nginx, which handles TLS, so it shouldn't be reachable
@ -158,14 +169,6 @@ WantedBy=multi-user.target
Enable and start it. Enable and start it.
<<<<<
IMPORTANT!
LiveKit is configured to use its built-in TURN server, using the same ports as
[coturn](../coturn). Obviously, LiveKit and coturn are mutually exclusive in
this setup. Shutdown and disable coturn if you use LiveKit's TURN server.
>>>>>
Clients don't know about LiveKit yet, you'll have to give them the information Clients don't know about LiveKit yet, you'll have to give them the information
via the `.well-known/matrix/client`: add this bit to it to point them at the via the `.well-known/matrix/client`: add this bit to it to point them at the
SFU: SFU:
@ -183,26 +186,13 @@ Make sure it is served as `application/json`, just like the other .well-known
files. files.
lk-jwt-service is a small Go program that handles authorization tokens. You'll need a
Go compiler, so install that:
```
apt install golang
```
# lk-jwt-service {#lkjwt} # lk-jwt-service {#lkjwt}
Get the latest source code and comile it (preferably *NOT* as root): lk-jwt-service is a small Go program that handles authorization tokens for use with LiveKit.
You'll need a Go compiler, but the one Debian provides is too old (at the time
``` of writing this, at least), so we'll install the latest one manually. Check
git clone https://github.com/element-hq/lk-jwt-service.git [the Go website](https://go.dev/dl/) to see which version is the latest, at
cd lk-jwt-service the time of writing it's 1.23.3, so we'll install that:
go build -o lk-jwt-service
```
You'll then notice that you need a newer compiler, so we'll download that and add it to
our PATH (again not as root):
``` ```
wget https://go.dev/dl/go1.23.3.linux-amd64.tar.gz wget https://go.dev/dl/go1.23.3.linux-amd64.tar.gz
@ -212,6 +202,18 @@ export PATH=`pwd`:$PATH
cd cd
``` ```
This means you now have the latest Go compiler in your path, but it's not
installed system-wide. If you want that, copy the whole `go` directory to
`/usr/local` and add `/usr/local/go/bin` to everybody's $PATH.
Get the latest lk-jwt-service source code and comile it (preferably *NOT* as root):
```
git clone https://github.com/element-hq/lk-jwt-service.git
cd lk-jwt-service
go build -o lk-jwt-service
```
Now, compile: Now, compile:
``` ```
@ -226,6 +228,7 @@ cp ~user/lk-jwt-service/lk-jwt-service /usr/local/sbin
chown root:root /usr/local/sbin/lk-jwt-service chown root:root /usr/local/sbin/lk-jwt-service
``` ```
## Systemd ## Systemd
Create a service file for systemd, something like this: Create a service file for systemd, something like this:
@ -258,8 +261,8 @@ else.
``` ```
mkdir /etc/lk-jwt-service mkdir /etc/lk-jwt-service
vi /etc/lk-jwt-service/config vi /etc/lk-jwt-service/config
chgrp -R www-data /etc/lk-jwt-service chgrp -R root:www-data /etc/lk-jwt-service
chmod -R o-rwx /etc/lk-jwt-service chmod 750 /etc/lk-jwt-service
``` ```
This is what you should put into that config file, This is what you should put into that config file,
@ -273,12 +276,20 @@ LIVEKIT_KEY=xxx
LK_JWT_PORT=8080 LK_JWT_PORT=8080
``` ```
Change the permission accordingly:
```
chown root:www-data /etc/lk-jwt-service/config
chmod 640 /etc/lk-jwt-service/config
```
Now enable and start this thing: Now enable and start this thing:
``` ```
systemctl enable --now lk-jwt-service systemctl enable --now lk-jwt-service
``` ```
# Element Call widget {#widget} # Element Call widget {#widget}
This is a Node.js thingy, so start by installing yarn. Unfortunately both npm This is a Node.js thingy, so start by installing yarn. Unfortunately both npm
@ -305,6 +316,9 @@ sudo apt install yarnpkg
/usr/share/nodejs/yarn/bin/yarn install /usr/share/nodejs/yarn/bin/yarn install
``` ```
Yes, this whole Node.js, yarn and npm thing is a mess. Better documentation
could be written, but for now this will have to do.
Now clone the Element Call repository and "compile" stuff (again: not as Now clone the Element Call repository and "compile" stuff (again: not as
root): root):
@ -315,8 +329,10 @@ cd element-call
/usr/share/nodejs/yarn/bin/yarn build /usr/share/nodejs/yarn/bin/yarn build
``` ```
After that, you can find the whole shebang under "dist". Copy that to If it successfully compiles (warnings are more or less ok, errors aren't), you will
`/var/www/element-call` and point nginx to it ([see nginx](../nginx#callwidget)). find the whole shebang under "dist". Copy that to `/var/www/element-call` and point
nginx to it ([see nginx](../nginx#callwidget)).
## Configuring ## Configuring

View file

@ -1,21 +1,25 @@
# Firewall # Firewall
This page is mostly a placeholder for now, but configuration of the firewall Several ports need to be opened in the firewall, this is a list of all ports
is -of course- very important. that are needed by the components we describe in this document.
First idea: the ports that need to be opened are: Those for nginx are necessary for Synapse to work, the ones for coturn and
LiveKit only need to be opened if you run those servers.
| Port(s) / range | IP version | Protocol | Application | | Port(s) / range | IP version | Protocol | Application |
| :-------------: | :--------: | :------: | :--------------------- | | :-------------: | :--------: | :------: | :--------------------- |
| 80, 443 | IPv4/IPv6 | TCP | nginx, reverse proxy | | 80, 443 | IPv4/IPv6 | TCP | nginx, reverse proxy |
| 8443 | IPv4/IPv6 | TCP | nginx, federation | | 8443 | IPv4/IPv6 | TCP | nginx, federation |
| 7881 | IPv4/IPv6 | TCP/UDP | coturn/LiveKit TURN | | 3478 | IPv4 | UDP | LiveKit TURN |
| 3478 | IPv4 | UDP | coturn/LiveKit TURN | | 5349 | IPv4 | TCP | LiveKit TURN TLS |
| 5349 | IPv4 | TCP | coturn/LiveKit TURN | | 7881 | IPv4/IPv6 | TCP | LiveKit RTC |
| 50000-60000 | IPv4 | TCP/UDP | coturn/LiveKit TURN | | 50000-60000 | IPv4/IPv6 | TCP/UDP | LiveKit RTC |
| 3480 | IPv4 | TCP/UDP | coturn TURN |
| 5351 | IPv4 | TCP/UDP | coturn TURN TLS |
| 40000-49999 | IPv4 | TCP/UDP | coturn RTC |
The ports necessary for TURN depend very much on the specific configuration The ports necessary for TURN depend very much on the specific configuration of
[coturn](../coturn#configuration) or [LiveKit](../element-call#livekit). [coturn](../coturn#configuration) and/or [LiveKit](../element-call#livekit).

View file

@ -49,7 +49,7 @@ list-timers` lists `certbot.timer`.
However, renewing the certificate means you'll have to restart the software However, renewing the certificate means you'll have to restart the software
that's using it. We have 2 or 3 pieces of software that use certificates: that's using it. We have 2 or 3 pieces of software that use certificates:
[coturn](../cotorun) and/or [LiveKit](../livekit), and [nginx](../nginx). [coturn](../coturn) and/or [LiveKit](../element-call#livekit), and [nginx](../nginx).
Coturn/LiveKit are special with regards to the certificate, see their Coturn/LiveKit are special with regards to the certificate, see their
respective pages. For nginx it's pretty easy: tell Letsencrypt to restart it respective pages. For nginx it's pretty easy: tell Letsencrypt to restart it