For a small setup, you can simply use a TURN server to make calls, and it will suffice. However, for large installations with many users, it is recommended to set up a separate Signaling server to reduce the load on participants joining the call. In this guide, I will walk you through the complete setup process of installing a Signaling server (High-performance backend) for your Nextcloud Talk.
What you will need:
- Minimum 8GB RAM
- Minimum 4 CPU cores (should support AES)
- Fresh Ubuntu 22.04 LTS server with public IP
- A domain or sub-domain pointed to the server IP
- Knowledge of running Linux commands
For clarity, I will use talk.myncserver.com as an example domain throughout this guide.
So let’s get started..
Looking to install Nextcloud 30 (Hub 9)? Click here
1- Prepare the system
If you haven’t updated your system yet, go ahead and do so with apt update && apt upgrade
.
Next is to enable the firewall and open a few ports. For details, check out this article.
Ports:
- 22 (your SSH port, if different use that)
- 80 (TCP)
- 443 (TCP)
- 3478 (UDP and TCP)
Port 3478 depends on your needs. If you are going to use this server as a TURN server too, then open it; otherwise, you can skip it, as we will use TURN locally on this signaling server only.
After completing the above steps, proceed to install the following packages.
apt install make protobuf-compiler git python3 docker.io zip unzip
2- Install latest Go
The signaling server will not compile with the current Go language provided by Ubuntu in the default repository. For this, we will need at least version 1.20 or above. Follow this guide to download and set up Go 1.20.
3- Setup NATS server
NATS is used to distribute messages between different instances. They provide a Docker solution, which we will use here.
docker pull nats:latest
Let’s run it in the background.
docker run -d --name nats-server -p 4222:4222 --restart=always -ti nats:latest
You can check the status with docker ps
. The port we will need later in the setup is 4222.
4- Install Janus (WebRTC gateway)
Janus is available in the Ubuntu repositories, and we will install it from there.
apt install janus
systemctl enable janus
systemctl status janus
We need to configure a few things in Janus first. You can create a random 16-character key by yourself or by using OpenSSL.
openssl rand -hex 8
Open this file for editing.
vim /etc/janus/janus.jcfg
Look for full_trickle under the nat section, which should be around line number 274.
full_trickle = true
turn_rest_api_key = <key_created_above>
Change the interface to lo in /etc/janus/janus.transport.http.jcfg. Additionally, in /etc/janus/janus.transport.websockets.jcfg, update ws_interface to ‘lo‘.
After all these changes, restart Janus.
systemctl restart janus
5- Install coTURN
apt install coturn
systemctl enable coturn
cp /etc/turnserver.conf /etc/turnserver.conf_BAK
Create a random key with:
openssl rand -hex 16
Open the /etc/turnserver.conf file for editing and add the following lines (remove everything else) to it, making the necessary changes according to your requirements.
listening-port=3478
fingerprint
use-auth-secret
static-auth-secret=<key_created_above>
realm=talk.myncserver.com
total-quota=100
bps-capacity=0
stale-nonce
no-multicast-peers
Save and restart coTURN.
systemctl restart coturn
6- Download and compile Signaling server
We will now download and prepare the Signaling server. While you can download the latest build from the main branch via git clone, I advise against it for stability reasons. Instead, we will download the most recent stable version, which is 1.2.2 at the time of writing this.
cd /opt
wget https://github.com/strukturag/nextcloud-spreed-signaling/archive/refs/tags/v1.2.2.zip
unzip v1.2.2.zip
rm v1.2.2.zip
It’s time to build the binary for the Signaling server.
cd nextcloud-spreed-signaling-1.2.2
make build
If everything goes smoothly, you will find the binary inside the bin directory. Let’s copy it to /usr/bin.
cp bin/signaling /usr/bin/
We will also copy the server.conf.in file to the /etc/signaling
location as server.conf.
mkdir /etc/signaling
cp server.conf.in /etc/signaling/server.conf
7- Prepare Signaling server
We will now add a system user with no login that will run the Signaling server.
groupadd --system signaling
useradd --system \
--gid signaling \
--shell /usr/sbin/nologin \
--comment "Standalone signaling server for Nextcloud Talk." \
signaling
Afterward, change the permissions of server.conf.
chmod 600 /etc/signaling/server.conf
chown signaling:signaling /etc/signaling/server.conf
To run the Signaling server as a daemon, copy the systemd file provided by Signaling to the systemd directory.
cp /opt/nextcloud-spreed-signaling-1.2.2/dist/init/systemd/signaling.service /etc/systemd/system/signaling.service
Next, we will edit it and add the following line after the Description line.
vim /etc/systemd/system/signaling.service
After=janus.service
You can now reload the systemd daemon.
systemctl daemon-reload
8- Configure Signaling server
Before we proceed to start the Signaling server, we will modify the configuration file to fit our needs.
At this point we will need four random keys.
Hash key:
openssl rand -hex 16
Block key:
openssl rand -hex 16
Internal secret (used for external clients like recording backend server):
openssl rand -hex 16
Nextcloud secret key:
openssl rand -hex 16
Note down the keys and from step 4 and 5 above.
vim /etc/signaling/server.conf
Do the following in this file:
- Uncomment where needed
- Change where necessary like keys etc
- You can leave nats, janus and turn server urls as is
- Double check everything before saving it
Note: I have added line numbers in front of them so you can easily locate them.
[http]
listen = 127.0.0.1:8080 (line 4)
[sessions]
hashkey = <hashkey_created_above> (line 40)
blockkey = <blockkey_created_above> (line 45)
[clients]
internalsecret = <clientkey_created_above> (line 50)
[backend]
backends = backend-1 (line 67)
[backend-1] (line 109)
url = https://your.nextcloud.domain (line 111)
secret = <nextcloud_secret_key_created_above> (line 116)
[nats]
url = nats://localhost:4222 (line 144)
[mcu]
type = janus (line 149)
url = ws://127.0.0.1:8188 (line 154)
[turn]
apikey = <turn_rest_api_key_set_in_janus_step_4_above> (line 209)
secret = <turnserver_secret_created_in_turnserver.conf_as_static-auth-secret_step_5_above> (line 209)
servers = turn:127.0.0.1:3478?transport=udp,turn:127.0.0.1:3478?transport=tcp (line 209)
Save the configuration file and proceed to start the Signaling server.
systemctl enable signaling
systemctl start signaling
Check it’s status with:
systemctl status signaling
Your output will be similar to the one below.
● signaling.service - Nextcloud Talk signaling server
Loaded: loaded (/etc/systemd/system/signaling.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2024-01-05 18:46:59 UTC; 13s ago
Main PID: 669700 (signaling)
Tasks: 6 (limit: 2237)
Memory: 3.1M
CPU: 98ms
CGroup: /system.slice/signaling.service
└─669700 /usr/bin/signaling --config /etc/signaling/server.conf
Jan 05 18:47:00 vps2617142 signaling[669700]: mcu_janus.go:316: Created Janus session 3896517509338209
Jan 05 18:47:00 vps2617142 signaling[669700]: mcu_janus.go:323: Created Janus handle 8168179460168699
Jan 05 18:47:00 vps2617142 signaling[669700]: main.go:263: Using janus MCU
Jan 05 18:47:00 vps2617142 signaling[669700]: hub.go:387: Using a timeout of 10s for MCU requests
Jan 05 18:47:00 vps2617142 signaling[669700]: backend_server.go:98: Using configured TURN API key
Jan 05 18:47:00 vps2617142 signaling[669700]: backend_server.go:99: Using configured shared TURN secret
Jan 05 18:47:00 vps2617142 signaling[669700]: backend_server.go:101: Adding "turn:127.0.0.1:3478?transport=udp" as TURN serv>
Jan 05 18:47:00 vps2617142 signaling[669700]: backend_server.go:101: Adding "turn:127.0.0.1:3478?transport=tcp" as TURN serv>
Jan 05 18:47:00 vps2617142 signaling[669700]: backend_server.go:114: No IPs configured for the stats endpoint, only allowing>
Jan 05 18:47:00 vps2617142 signaling[669700]: main.go:339: Listening on 127.0.0.1:8080
9- Proxy server
Your choice of frontend or proxy depends on your ease of use. I will use Apache. You can check the other proxies here.
apt install apache2
a2enmod ssl rewrite headers proxy proxy_http deflate cache proxy_wstunnel http2 proxy_fcgi env expires
systemctl restart apache2
systemctl enable apache2
rm /var/www/html/index.html
We will proceed to create a virtual host file.
cd /etc/apache2/sites-available/
vim signaling.conf
Add the following to it:
<VirtualHost *:80>
ServerName talk.myncserver.com
DocumentRoot /var/www/html
<Directory "/var/www/html">
AllowOverride All
Options -Indexes +FollowSymLinks
</Directory>
ErrorLog /var/log/apache2/signaling_error.log
</VirtualHost>
Enable this configuration and restart Apache.
a2dissite 000-default.conf
a2ensite signaling.conf
apachectl -t
systemctl restart apache2
10- SSL
If you have your own certificates, you can use them in the configuration file below (step 11). But for everyone else, we will install Certbot to obtain a free SSL certificate from Let’s Encrypt.
apt install certbot
Obtain a free certificate and make a note of their paths.
certbot certonly --webroot -w /var/www/html -d talk.myncserver.com
To renew the certificate automatically, you can set up a cronjob.
crontab -e
Add the following to it.
30 04 * * * certbot renew
11- Update virtual host
We can now safely update the virtual host file with the 443 block section.
Add the following to it:
<VirtualHost *:443>
ServerName talk.myncserver.com
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
ErrorLog /var/log/apache2/signaling_error.log
SSLEngine on
SSLCertificateKeyFile /etc/letsencrypt/live/talk.myncserver.com/privkey.pem
SSLCertificateFile /etc/letsencrypt/live/talk.myncserver.com/fullchain.pem
ProxyPass "/standalone-signaling/" "ws://127.0.0.1:8080/"
RewriteEngine On
RewriteRule ^/standalone-signaling/spreed/$ - [L]
RewriteRule ^/standalone-signaling/api/(.*) http://127.0.0.1:8080/api/$1 [L,P]
</VirtualHost>
Save this and restart Apache.
apachectl -t
systemctl restart apache2
12- Test and add it to Nextcloud
Once everything is set up and configured, you can now give it a shot to test.
curl -i https://talk.myncserver.com/standalone-signaling/api/v1/welcome
The output will look like the one below; ignore the version as unknown. I don’t know why it is not showing the exact version of Signaling.
HTTP/2 200
content-type: application/json; charset=utf-8
server: nextcloud-spreed-signaling/unknown
x-spreed-signaling-features: audio-video-permissions, dialout, hello-v2, incall-all, mcu, simulcast, switchto, transient-data, update-sdp, welcome
date: Mon, 08 Jan 2024 16:48:17 GMT
content-length: 61
{"nextcloud-spreed-signaling":"Welcome","version":"unknown"}
Now, navigate to the Nextcloud administration settings page, click on Talk, scroll to the High-performance backend section, and then click on the “Add a new high-performance backend server” button.
Enter the following URL in the URL field and enter your Nextcloud secret key, created above, in the Shared secret field. You can check the Validate SSL certificate checkbox.
URL = https://talk.myncserver.com/standalone-signaling/
That’s it—happy calling! 📞
13- Debugging
Once you initiate the call and encounter any issues or if something is not working, you can check the logs to further debug the issue.
tail -f /var/log/syslog
tail -f /var/log/janus.log
tail -f /var/log/apache2/signaling_error.log
docker logs --since=1h <container_name_or_id>
Note: Janus logs are disabled by default; you can enable them in /etc/janus/janus.jcfg
by providing the path as shown above.
Hi, you can add
docker update –restart unless-stopped $(docker ps -q)
to autostart docker nats-server on reboot
websocket: the client is not using the websocket protocol: ‘upgrade’ token not found in ‘Connection’ header