Nextcloud Talk mit coturn und eigenem Signaling-Server (High Performance Backend)

Mit der „Talk“-App unterstützt Nextcloud auch Videokonferenzen. Dafür wird mindestens STUN (Session Traversal Utilities for NAT) und TURN (Traversal Using Relay NAT) benötigt, um die Kommunikation zwischen den Teilnehmern hinter NAT-Routern zu ermöglichen. Die übliche Lösung unter Linux ist dafür coturn.

Mit coturn funktioniert Talk in der Regel schon ganz gut, wenn sich nicht mehr als 4-5 Teilnehmer in einer Sitzung befinden. Allerdings erfolgt die Verbindung der Clients dann direkt untereinander ohne einen zentralen Server für den Austausch von Audio- und Video. Bei mehr als 5 Clients steigt Aufwand für die Kommunikation überproportional und ist irgendwann gar nicht mehr möglich, weshalb Nextcloud Talk auch warnt, wenn mehr als 5 Clients verbunden sind.

Die Lösung für Videokonferenzen mit vielen Clients ist ein separater Signaling-Server, das „High Performance Backend“. Damit werden die Video- und Audio-Daten der Clients über einen zentralen Server verteilt, so dass jeder einzelne Client nur noch die Verbindung zum Server benötigt. Die Zahl der möglichen Clients ist dann nur noch durch die Leistung und Netzanbindung des Servers begrenzt. In der Vergangenheit konnte man diesen Server nur kostenpflichtig als Dienst mieten, wobei die Preisgestaltung sich ganz klar an Firmennutzern orientiert. Im Mai 2020 wurde dann aber erfreulicherweise die Freigabe des Servers als Open Source bekannt gegeben, womit das auch für private Nutzer und Institutionen mit wenig Budget interessant ist.

Bei der nachfolgende Beschreibung der Installation gehe ich davon aus, dass bereits eine Nextcloud-Installation mit Apache als Webserver vorhanden ist und Linux auf Basis von Ubuntu verwendet wird. Außerdem nutze ich Docker für NATS, was man ebenfalls vorher einrichten muss. Siehe dazu auch die Anleitung bei Docker selbst.

Systemvoraussetzungen

Für den Betrieb von Nextcloud mit eigenem Signaling-Server sollte eine Umgebung mit mindestens 4 CPU-Kernen, 16 GB RAM und einer Anbindung mit 1 GBit/s (in beide Richtungen) verwendet werden. Virtuelle Server sollten kein grundsätzliches Problem sein, allerdings ist die Netzwerkanbindung hier mitunter problematisch.

Einrichten von coturn und erste Tests

Siehe dazu auch https://nextcloud-talk.readthedocs.io/en/latest/TURN/.

coturn kann als Paket installiert werden:

apt install coturn

Danach muss der Server mit folgendem Eintrag in /etc/default/coturn aktiviert werden:

TURNSERVER_ENABLED=1

Damit coturn später mit einem eigenen User läuft und nicht als root, legt man bei Bedarf einen System-User dafür wie folgt an, falls dieser nicht schon existiert:

groupadd turnserver
useradd --system --gid turnserver --shell /bin/false --comment "Coturn" turnserver

Für die Nutzung mit Nextcloud Talk sind schließlich noch folgende Einträge in der Konfigurationsdatei /etc/turnserver.conf erforderlich. Die Datei enthält viele Einträge bereits als auskommentierte Zeilen, erkennbar am „#“-Zeichen am Zeilenanfang. Hier genügt es, dieses Zeichen zu entfernen und den Rest nach Bedarf anzupassen:

listening-port=3478
listening-ip=<IPv4-Adresse des Servers>
listening-ip=<IPv6-Adresse des Servers>
fingerprint
lt-cred-mech
use-auth-secret
static-auth-secret=<Secret>
realm=<FQDN des Servers>
total-quota=0
bps-capacity=0
no-tls
no-dtls
stale-nonce
no-loopback-peers
no-multicast-peers
proc-user=turnserver
proc-group=turnserver

lt-cred-mech wird nur für Versionen unter 4.5.0.8 benötigt.

no-loopback-peers wird nur für Versionen unter 4.5.1.0 benötigt.

Bei realm= gibt man den Namen des Servers an. Man benötigt nicht zwingend eine eigene Subdomain dafür, aber ich habe mir angewöhnt, für solche Dienste eigene Namen zu reservieren, wie z.B. turnserver.example.com (statt example.com die eigene Domain), dann ist klar, wofür dieser Server verwendet wird.

Als <Secret> muss eine zufällig Zeichenfolge angegeben werden, die dann später auch in Nextcloud und im Signaling-Server eingetragen wird. Zur Erzeugung kann man ein Kommando wie openssl rand -hex 16 verwenden, mit dem ein 32 Zeichen langer Text erzeugt wird.

Ein Hinweis zu den Optionen no-tls und no-dtls, mit denen die Nutzug von TLS und DTLS deaktiviert wird: Nextcloud unterstützt die Verwendung von (D)TLS nicht, weil es keinen echten Sicherheitsgewinn bringt. Näheres dazu siehe auch hier:

https://github.com/nextcloud/spreed/issues/257

Schließlich startet man coturn:

service coturn start

Zur Angabe der IP-Adressen

Der Eintrag listening-ip kann mehrfach vorhanden sein. Jede IP-Adresse, unter der der Server erreichbar sein soll, muss hier genannt werden. Überweise ist das eine IPv4-Adresse und eine IPv6-Adresse. Hat der Server nur eine IPv4-Adresse, genügt diese natürlich auch als einziger Eintrag.

Port 80 statt 3478?

Restriktivere Firewalls in Firmennetzwerken erlauben mitunter keine Verbindungen auf Port 3478. Als Workaround wird mitunter empfohlen, auf Port 80 (und ggf. eine andere IP-Adresse als der Webserver für Nextcloud) auszuweichen. Das Problem dabei ist aber, dass häufig auch ein Proxy verwendet wird, über den nur HTTP auf Port 80 möglich ist. TURN würde in diesem Fall auch dann nicht funktionieren, wenn man es auf Port 80 konfiguriert. Hinzu kommt, dass neben diesem Port für die weitere Kommunikation über WebRTC zusätzliche Ports verwendet werden, die ebenfalls durch die Firewall gesperrt sein könnten. Eine sinnvollere Lösung ist es daher, bei Problemen mit der zuständigen Administration zu sprechen, damit die Firewall-Konfiguration angepasst wird.

Test und Konfiguration in Nextcloud

Für den Test von Coturn kann man Trickle ICE verwenden.

Dort löscht man zunächst den Eintrag für den Server bei Google und gibt dann die Adresse des eigenen Servers im Format stun:<Servername>:3478 ein. Mit „Gather candidates“ kann man dann prüfen, ob der STUN-Server eine Antwort zurückliefert. Die Antwort sollte ohne große Verzögerung erfolgen und mit „Done“ am Ende der Liste abgeschlossen sein.

In Nextcloud wird Coturn in den Einstellungen zu Talk wie folgt eingetragen:

Beim STUN-Server gibt man die Adresse im Format <Servername>:3478 ein. Beim TURN-Server fügt man zunächst mit „+“ einen neuen Eintrag hinzu und gibt dann als Server-Adresse ebenfalls <Servername>:3478 an und als Secret die Angabe für static-auth-secret aus /etc/turnserver.conf. Als Protokoll kann man die Voreinstellung für UDP and TCP belassen, da Coturn beide Protokolle unterstützt.  Nach der Eingabe wird die Verbindung jeweils geprüft und mit einem kleinen Haken bestätigt, wenn sie erfolgreich war.

Ab diesem Zeitpunkt sollte Nextcloud Talk bereits grundsätzlich nutzbar sein. Wer nur Sitzungen mit maximal 4-5 Personen braucht, sollte damit prinzipiell arbeiten können.

Erweiterung mit Signaling-Server

Für den Betrieb des Signaling-Server sind mehrere Komponenten erforderlich:

  • Janus für die Verteilung der Audio- und Video-Streams zwischen den Clients über WebRTC
  • NATS as Messaging-Server
  • Spreed Signaling-Server

Einrichten von Janus

PPA für Ubuntu

Für Janus habe ich das PPA von https://launchpad.net/~fancycode/+archive/ubuntu/janus verwendet. Dieses PPA bringt alle erforderlichen Komponenten mit. Für die Installation sind folgende Schritte nötig:

add-apt-repository ppa:fancycode/janus
apt update
apt install janus

Konfiguration

Nun trägt man in /etc/janus/janus.jcfg folgende Optionen im Abschnitt nat: { ein:

nat: {
        stun_server = "<server>"
        stun_port = 3478
        nice_debug = false
        full_trickle = true
# ...
        turn_rest_api_key = "<key>"
# ...
}

Für <server> ist der Name des Servers anzugeben, über den Coturn erreichbar ist.

Für <key> gibt man eine zufällige Zeichenfolge ein, die man sich wie bei Coturn auch mit openssl rand -hex 16 erzeugen kann.

Desweiteren in /etc/janus/janus.transport.http.jcfg folgendes:

general: {
# ...
        base_path = "/janus"
        http = true
        port = 8088
        ip = 127.0.0.1
        https = false
# ...
}

Falls Port 8088 auf dem eigenen Server bereits für andere Dienste belegt ist, muss dieser entsprechend angepasst werden. Der Port wird später auch im Signaling-Server angegeben.

In /etc/janus/janus.transport.websockets.jcfg ist auch noch die IP-Adresse anzupassen, damit nur lokale Verbindungen möglich sind:

general: {
# ...
        ws = true
        ws_port = 8188
        ws_ip = 127.0.0.1
        wss = false
# ...
}

Auch hier gilt, dass man statt Port 8188 bei Bedarf auch einen anderen Port verwenden kann. Der Port muss später nur korrekt im Signaling-Server angegeben werden.

Am Ende startet man Janus wie folgt:

systemctl start janus

Einrichten von NATS

Die einfachste Variante, NATS einzurichten, ist die Verwendung von Docker.

Docker sollte man vorzugsweise anhand der offiziellen Anleitung von Docker installieren und nicht das Paket verwenden, was Ubuntu mitliefert. Damit ist sichergestellt, dass man eine aktuelle Version von Docker verwendet.

Die Installation von NATS ist dann mit zwei Befehlen erledigt:

docker pull nats:latest
docker run --name=natsserver -d -p 127.0.0.1:4222:4222 -ti --restart=always nats:latest

NATS ist dann lokal auf Port 4222 ansprechbar und wird beim Systemstart automatisch gestartet. Weiter ist nichts erforderlich.

Einrichten des Signaling-Servers

Herunterladen der Quellen und erzeugen der Server-Binaries

Für den Signaling-Server muss man sich die Quellen von Github herunterladen und den Server daraus selbst erstellen:

apt install golang-go
cd /etc/
git clone https://github.com/strukturag/nextcloud-spreed-signaling.git
cd /etc/nextcloud-spreed-signaling
make build

Erzeugen der lokalen Konfiguration

Nach dem erfolgreichen Durchlauf erstellt man sich eine lokale Konfiguration in /etc/nextcloud-spreed-signaling/server.conf:

cd /etc/nextcloud-spreed-signaling
cp server.conf.in server.conf

Diese wird dann noch wie folgt angepasst:

[http]
listen = 127.0.0.1:8086

[sessions]
hashkey = <session-hashkey>
blockkey = <session-blockkey>

[backend]
backends = backend1

[backend1]
url = <URL des Nextcloud-Servers>
secret = <Nextcloud-Secret>

[nats]
url = nats://localhost:4222

[mcu]
type = janus
url = ws://127.0.0.1:8188

[turn]
apikey = <API-Key von Janus (turn_rest_api_key)>
secret = <Secret von Coturn (static-auth-secret)>

Für <session-hashkey> und <session-blockkey> verwendet man jeweils die Ausgabe von openssl rand -hex 16.

<Nextcloud-Secret> ist das Secret, das man auch in Nextcloud angeben muss. Auch hier kann man openssl rand -hex 16 zur Erzeugung verwenden.

Erstellen der Systemd-Unit

Damit der Signaling-Server als Dienst nutzbar ist, ist wie bei Coturn ein eigener System-User erforderlich:

groupadd signaling
useradd --system --gid signaling --shell /bin/false --comment "Nextcloud Signaling" signaling

Danach erstellt man die Datei /etc/systemd/system/nextcloud-signaling.service mit folgendem Inhalt:

[Unit]
Description=Nextcloud Talk signaling server

[Service]
ExecStart=/etc/nextcloud-spreed-signaling/bin/signaling --config /etc/nextcloud-spreed-signaling/server.conf
User=signaling
Group=signaling
Restart=on-failure

[Install]
WantedBy=multi-user.target

Die Unit wird dann wie folgt aktiviert und gestartet:

systemctl daemon-reload
systemctl enable nextcloud-signaling
systemctl start nextcloud-signaling

Kontrolle der Dienste

Mit folgenden Kommandos kann man prüfen, ob die Dienste korrekt laufen:

Janus

journalctl -u janus

Warnungen wie [WARN] HTTPS webserver disabled kann man ignorieren. Es sollten aber keine Fehlermeldungen vorliegen.

Signaling-Server

journalctl -u nextcloud-signaling

Hier sollte man darauf den Eintrag Listening on 127.0.0.1:8086 achten und prüfen, ob der TURN-Server korrekt verwendet wird (Adding "turn:server.example:3478?transport=udp" as TURN server und Adding "turn:server.example:3478?transport=tcp" as TURN server). Falls später der Verbindunsaufbau dennoch nicht klappt, hat man eventuell das Secret von Coturn nicht korrekt eingetragen.

Coturn als Systemd-Unit

Coturn wird nur mit einem init-Script installiert. Wer statt dessen eine Systemd-Unit bevorzugt, kann dazu die Datei /etc/systemd/system/turnserver.service mit folgendem Inhalt erstellen:

[Unit]
Description=coturn
Documentation=man:coturn(1) man:turnadmin(1) man:turnserver(1)
After=syslog.target network.target

[Service]
Type=forking
User=turnserver
Group=turnserver
RuntimeDirectory=turnserver
RuntimeDirectoryMode=0750
EnvironmentFile=/etc/default/coturn
PIDFile=/run/turnserver/turnserver.pid
ExecStart=/usr/bin/turnserver --daemon --pidfile /run/turnserver/turnserver.pid --syslog -c /etc/turnserver.conf $EXTRA_OPTIONS
Restart=on-failure
LimitCORE=infinity
LimitNOFILE=1000000
LimitNPROC=60000
LimitRTPRIO=infinity
LimitRTTIME=7000000
CPUSchedulingPolicy=other
UMask=0007

[Install]
WantedBy=multi-user.target

Danach deaktiviert man das init-Script und stellt auf die Nutzung der Systemd-Unit um:

update-rc.d coturn disable
systemctl daemon-reload
systemctl disable coturn
systemctl enable turnserver
systemctl start turnserver

Zur Sicherheit sollte man prüfen, dass die Unit korrekt gestartet wurde:

systemctl status turnserver

Apache-Proxy konfigurieren

Für den Signaling-Server habe ich eine eigene Subdomain in Apache mit HTTPS auf Basis von Let’s Encrypt angelegt. Darin wurde ein Reverse-Proxy konfiguriert, der den Zugang zum Signaling-Server über HTTPS ermöglicht. Dazu sind auch folgende Module erforderlich die man jeweils mit a2enmod aktivieren kann:

  • rewrite
  • proxy
  • proxy_http
  • proxy_wstunnel
RewriteEngine On
RewriteRule ^/standalone-signaling/spreed$ - [L]
RewriteRule ^/standalone-signaling/api/(.*) http://127.0.0.1:8086/api/$1 [L,P]
ProxyPass "/standalone-signaling/" "ws://127.0.0.1:8086/"

Falls man statt 8086 in der Konfiguration des Signaling-Servers einen anderen Port verwendet, muss dieser natürlich hier entsprechend angegeben werden.

Konfiguration des Signaling-Servers in Nextcloud

In Nextcloud fügt man den Signaling-Server ähnlich wie STUN/TURN in der Konfiguration von Talk hinzu.

Dabei gibt man die URL im Format https://<servername>/standalone-signaling an. Das Secret ist die Angabe aus der Backend-Konfiguration des Signaling-Servers.

Nachdem man Server-Adresse und Secret angegeben hat, sollte zur Bestätigung auch „OK: Running version:“ gefolgt von einer längeren Zeichenfolge erscheinen.

Update 2020-12-13: Praktische Erfahrungen

Mittlerweile konnte ich Erfahrungen in der Praxis sammeln. Der verwendete Server ist eine virtuelle Maschine mit 6 Kernen, 24 GB RAM und einer Netzanbindung mit 1 GBit/s Sitzungen mit bis zu 9 Personen gleichzeitig, die alle Audio und Video verwendet haben, waren überhaupt kein Problem. Größere Sitzungen gab es bisher nicht. Dabei wurden sowohl Browser wie Firefox, Chrome und Safari wie auch die Talk-Apps für Android und iOS verwendet.

Generell empfehle ich, aktuelle Software und nicht zu alte Hardware zu nutzen, besonders wenn man auch Videoübertragung nutzen will.

Update 2021-01-11: Kleine Anpassungen

Mittlerweile habe ich den Signaling-Server auf einen anderen Server umgezogen, da auf dem bisherigen Server bei gut besuchten Sitzungen andere Dienste durch die hohe Last von Janus spürbar eingeschränkt wurden, insbesondere Nextcloud selbst.

Ich habe in diesem Rahmen auch die Anleitung etwas angepasst:

  1. Bei dem Kommando zum Anlegen der User hat sich ein Tippfehler eingeschlichen – die Option --comment war nur mit einem Bindestrich angegeben.
  2. In der systemd-Units für coturn habe ich die Option restart=on-abort geändert zu restart=on-failure. Damit wird sichergestellt, dass coturn bei einem Fehler immer neu gestartet wird.

Update 2021-04-07: Weitere Anpassungen

Die an diversen Stellen benötigten Keys dürfen nur 16 bzw. 32 Zeichen lang sein, daher habe ich den Aufruf von OpenSSL entsprechend angepasst, da hier nicht die Zahl der auszugebenen Zeichen übergeben wird, sondern die Anzahl der Bytes, die in hexadezimaler Schreibweise aber doppelt so viele Zeichen ergeben.

11 Gedanken zu „Nextcloud Talk mit coturn und eigenem Signaling-Server (High Performance Backend)“

  1. T
    Tom

    Hallo Arno,
    hallo zusammen!

    Ich möchte mich für die tolle Beschreibung, Beteiligung und die Gedanken aller bedanken. Es ist sehr schön, wenn Menschen ihr Wissen teilen und es anderen Menschen dadurch leichter machen.

    Persönlich werde ich erst in den nächsten 2-3 Wochen mit dem Thema beginnen. Es war mir aber ein Bedürfnis, diese Zeilen loszuwerden.

    Beste Grüße
    Tom

  2. C
    Christian Stornowski

    Nach längeren Testen mit unterschiedlichen Geräten, Browsern und Teilnehmeranzahl habe ich eine Anmerkung für diese Anleitung.

    Laut diesem Dateien

    https://github.com/meetecho/janus-gateway/blob/v0.10.9/turnrest.c
    https://github.com/meetecho/janus-gateway/blob/v0.10.9/ice.c
    https://github.com/strukturag/nextcloud-spreed-signaling/blob/master/src/signaling/backend_server.go

    müssen folgende Angaben für diese Anleitung noch angepasst werden:

    /etc/janus/janus.jcfg:

    turn_rest_api = „/standalone-signaling/turn/credentials“
    turn_rest_api_method = „GET“
    turn_rest_api_timeout = 10

    Ohne diese Einstellungen wird das TURN REST API backend in Janus deaktiviert und

    turn_rest_api_key = „“

    hat einen Effekt. Dies kann im Start Log vom Janus Server nachvollzogen werden.

    1. Arno Welzel

      Danke für die Ergänzung.

      Für turn_rest_api muss allerdings eine vollständige Adresse inklusive URL angegeben werden – zumindest bei mir war das nötig, weil Janus sonst einen Fehler meldet, dass für diese Option keine URL angegeben ist:

      turn_rest_api = "https://server.example/standalone-signaling/turn/credentials"

      Desweiteren funktioniert das Backend auch ohne diese Option, auch wenn Janus im Log meldet, dass die REST-API für TURN nicht aktiviert wird.

  3. Hallo Arno,

    Erstmal vielen Dank für deine tolle Anleitung.
    Zur Zeit bin ich dabei (ehrenamtlich) eine NextCloud für eine (noch zu gründende) Freikirche zu basteln.
    Aufgrund der derzeitigen Situation wollen wir uns auf absehbare Zeit auf virtuelle Kontakte beschränken.
    Jetzt bin ich da seit Tagen am herumschrauben an diesem Signaling-Server.
    Der Signaling-Server läuft auf einer VPS bei einem einschlägigen Provider (mit Docker-Unterstützung).
    Ich bin nach deiner Anleitung vorgegangen. Ich habe mehrfach des Server neu installiert weil ich an Konfigurationsfehler meinerseits geglaubt habe. Bisher aber immer mit dem unschönen Ergebnis, dass meine Nextcloud beim Hochleistungs-Backend „Fehler: Der Server antwortete mit: 404“ meldet. Der Turn-Server ist OK. Die Fehlermeldung ist im Webbrowser aufgerufen übrigens nicht html sondern einfach nur eine Textzeile. Ds scheint mir eher nicht von apache zu stammen sondern eher vom janus???
    Die journalctl -u für cotalk, janus, nextcloud-signaling und apache2 sehen sauber aus. Auch die Portzuordnungen scheinen zu passen.
    Ich bin am verzweifeln und für jede Hilfe sehr dankbar. Hast du noch eine Idee?

    Bernd

    1. Arno Welzel

      Ohne den Server genauer zu sehen, kann ich da leider nicht viel sagen. Wir können uns das gerne zusammen ansehen, ich bin auch per E-Mail erreichbar (siehe Impressum).

  4. T
    Tobias

    Hallo Arno,
    danke für die tolle Anleitung. Wir bauen uns gerade eine NextCloud Instanz für unseren Raspberry Club, da waren die vielen Tipps echt hilfreich. Aktuell hängen wir aber gerade bei der Signaling Server Einrichtung… Irgendwie scheint das nicht zu klappen. Hast Du den Signaling Server auf einem anderen Root Server laufen oder läuft bei Dir auch beides auf dem gleichen Server?

    1. Arno Welzel

      Nextcloud und der Signaling Server laufen gemeinsam auf einem Server.

    2. Arno Welzel

      Nachtrag: nachdem heute recht umfangreiche Sitzung (mehr als 10 Personen) den Server spürbar ausgelastet hat, so dass Nextcloud nicht mehr sinnvoll benutzbar war, habe ich mich entschieden, den Signaling-Server auf eine eigene Maschine umzuziehen.

  5. S
    Sebastian

    Tolle Anleitung. Wäre es möglich, dass du auf die Konfiguration von Apache etwas genauer eingehst? Das Signaling über den Proxy ist nämlich mein einziges Problem.

    1. Arno Welzel

      Was genau willst Du zu Apache wissen?

      Die relevanten Einträge für den Proxy habe ich ja beschrieben – die müssen in die Host-Konfiguration, also innerhalb des VirtualHost-Abschnitts der Website, über die das Signaling laufen soll. Das kann prinzipiell auch der Nextcloud-Server selbst sein, dann wäre die URL https://meine-nextcloud.example/standalone-signaling

      1. Arno Welzel

        Ergänzung: ich habe noch das rewrite-Modul in der Beschreibung ergänzt, das muss natürlich ebenfalls vorhanden sein.

Öffentlichen Kommentar zu Tobias hinterlassen Kommentar abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Dies ist kein Kontaktformular! Wenn Du mir eine persönliche Nachricht schreiben möchtest, benutze die E-Mail-Adresse in meinem Impressum.

Du kannst die folgenden HTML-Tags im Kommentar verwenden:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>