Nextcloud Talk transforms your Nextcloud server into a private video conferencing platform where every call, message, and shared screen stays on infrastructure you control. No third-party servers route your video streams. No external company can access your call recordings. Your communication data lives where your files live -- on your own server.
But getting Talk to work reliably for video calls -- especially calls with more than two participants -- requires understanding how real-time communication works at the network level and configuring several supporting services that Nextcloud Talk depends on. A basic Talk installation might work fine for text chat but produce black screens, one-way audio, or connection failures when users try to start video calls. This guide covers everything needed to go from a basic Talk installation to a production-ready video conferencing platform.
This guide assumes you have a working Nextcloud instance. If you are starting from scratch, follow our production installation guide first, then return here to add Talk capabilities.
How Nextcloud Talk Works: WebRTC, STUN, and TURN
Understanding the networking fundamentals is essential because most Talk issues are networking issues, not application issues. Nextcloud Talk uses WebRTC (Web Real-Time Communication) for audio and video transmission. WebRTC is a peer-to-peer protocol -- in a two-person call, the video and audio streams flow directly between the two participants' browsers without passing through the Nextcloud server.
This peer-to-peer model creates a problem: most users are behind NAT (Network Address Translation) routers, firewalls, or corporate proxies. Their devices have private IP addresses (like 192.168.x.x) that are not directly reachable from the internet. WebRTC needs to discover the user's public IP address and negotiate a path through the NAT -- this is where STUN and TURN come in.
STUN (Session Traversal Utilities for NAT)
STUN is a lightweight protocol that helps a client discover its own public IP address and the type of NAT it is behind. When a user joins a Talk call, the WebRTC client sends a request to a STUN server, which responds with the user's public IP and port mapping. Both participants exchange this information through the Nextcloud server (which acts as the signaling server), and if both can reach each other's public IPs directly, a peer-to-peer connection is established.
STUN works in roughly 80-85% of cases. It is fast, uses minimal bandwidth (only the initial discovery), and is free to operate. Nextcloud Talk ships with a default STUN server configuration pointing to Nextcloud's public STUN servers, which works for testing but should not be relied on for production.
TURN (Traversal Using Relays around NAT)
TURN is the fallback for the 15-20% of cases where STUN fails. When a direct peer-to-peer connection is impossible -- because one or both users are behind symmetric NAT, strict corporate firewalls, or carrier-grade NAT -- TURN acts as a relay server. All audio and video traffic flows through the TURN server, which forwards it between participants.
TURN is critical for production deployments because without it, a significant percentage of your users will experience connection failures. The most common symptom is "I can hear the other person but they can't hear me" or "the call connects but video is black." These are almost always NAT traversal failures that a TURN server resolves.
The trade-off is bandwidth: all relayed traffic passes through your TURN server, so it needs enough bandwidth to handle all simultaneous relayed streams. For a call with two participants, this means roughly 2-4 Mbps through the TURN server (incoming from one participant, outgoing to the other, for both audio and video).
High Performance Backend (HPB)
For calls with more than 3-4 participants, WebRTC's peer-to-peer model breaks down. In a 5-person call with full mesh peer-to-peer, each participant sends their stream to 4 others and receives 4 streams -- that is 20 individual video streams. At 10 participants, it is 90 streams. Each participant's upload bandwidth requirements scale linearly with the number of participants, quickly exceeding what most internet connections can handle.
Nextcloud's High Performance Backend (HPB) solves this by acting as a Selective Forwarding Unit (SFU). Instead of every participant sending their stream to every other participant, all participants send their stream once to the HPB, and the HPB forwards each stream to all other participants. In a 10-person call, each participant sends 1 stream and receives 9 -- instead of sending 9 and receiving 9. This cuts upload bandwidth requirements by roughly 90%.
The HPB consists of two components:
- Signaling server: Handles WebSocket connections for real-time presence and call signaling
- Janus WebRTC Gateway: The SFU that handles media stream routing
Step 1: Install Nextcloud Talk
If Talk is not already installed, enable it from the command line:
sudo -u www-data php /var/www/nextcloud/occ app:enable spreed
The app name spreed is the internal identifier for Nextcloud Talk (a legacy name from the project's early development). After enabling, verify it is active:
sudo -u www-data php /var/www/nextcloud/occ app:list | grep spreed
At this point, Talk will work for text chat and 1-on-1 calls between users on the same network or users with favorable NAT configurations. To make it work reliably for all users, you need a STUN/TURN server.
Step 2: Deploy Coturn as Your STUN/TURN Server
Coturn is the standard open-source STUN/TURN server. It handles both protocols and is battle-tested in production WebRTC deployments.
Installation
Install Coturn on your server. For production deployments, running Coturn on a separate server from Nextcloud is recommended -- the TURN relay bandwidth should not compete with Nextcloud's own bandwidth for file sync and web traffic:
sudo apt update
sudo apt install -y coturn
Enable Coturn to start as a system service by editing /etc/default/coturn:
TURNSERVER_ENABLED=1
Generate Authentication Credentials
TURN servers require authentication to prevent unauthorized use. Generate a strong secret that will be shared between Coturn and Nextcloud:
openssl rand -hex 32
Save this output -- you will need it for both the Coturn configuration and the Nextcloud Talk settings.
Configure Coturn
Create or edit /etc/turnserver.conf with the following configuration. Replace the placeholder values with your actual domain, IP, and secret:
# Network settings
listening-port=3478
tls-listening-port=5349
listening-ip=0.0.0.0
external-ip=YOUR_PUBLIC_IP
relay-ip=YOUR_PUBLIC_IP
# Domain and realm
realm=turn.yourdomain.com
server-name=turn.yourdomain.com
# Authentication
use-auth-secret
static-auth-secret=YOUR_GENERATED_SECRET_HERE
# TLS certificates (use the same Let's Encrypt certs)
cert=/etc/letsencrypt/live/turn.yourdomain.com/fullchain.pem
pkey=/etc/letsencrypt/live/turn.yourdomain.com/privkey.pem
# Relay port range (must be open in firewall)
min-port=49152
max-port=65535
# Performance and limits
total-quota=100
stale-nonce=600
max-bps=0
no-multicast-peers
# Security
no-cli
no-tlsv1
no-tlsv1_1
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
# Logging
log-file=/var/log/turnserver/turn.log
simple-log
new-log-timestamp
# Fingerprint and long-term credentials
fingerprint
lt-cred-mech
Key configuration notes:
external-ipmust be your server's public IP address, not a private IP. If Coturn runs behind a NAT (e.g., on a cloud VPS), this tells Coturn which IP to advertise to clients.use-auth-secretwithstatic-auth-secretenables time-limited credentials. Nextcloud generates temporary TURN credentials using this shared secret, so no static username/password is exposed to clients.- The
denied-peer-ipranges prevent TURN from being used as a proxy to access private network resources -- an important security measure. - The relay port range (49152-65535) is where actual media streams flow. These ports must be accessible from the internet.
- TLS on port 5349 is essential for users behind corporate firewalls that block non-standard ports. TURNS (TURN over TLS on 443) can also be configured as a final fallback for the most restrictive networks.
Create the log directory and start Coturn:
sudo mkdir -p /var/log/turnserver
sudo chown turnserver:turnserver /var/log/turnserver
sudo systemctl enable coturn
sudo systemctl start coturn
Firewall Configuration
Open the required ports for STUN/TURN traffic:
# STUN/TURN listening ports
sudo ufw allow 3478/tcp
sudo ufw allow 3478/udp
sudo ufw allow 5349/tcp
sudo ufw allow 5349/udp
# TURN relay port range
sudo ufw allow 49152:65535/udp
The UDP relay port range is the most critical -- this is where actual audio and video data flows. If these ports are blocked, TURN relay connections will fail silently, and users will experience call failures without useful error messages.
Verify Coturn Is Working
Test that the STUN server responds correctly using the Trickle ICE test page (https://webrtc.github.io/samples/src/content/peerconnection/trickle-ice/). Add your STUN server as stun:turn.yourdomain.com:3478 and click "Gather candidates." You should see both srflx (server reflexive, from STUN) and relay (from TURN) candidates appear.
You can also check the Coturn logs:
sudo tail -f /var/log/turnserver/turn.log
Step 3: Configure Talk to Use Your TURN Server
In the Nextcloud admin panel, navigate to Talk settings (or Administration Settings > Talk). Under the STUN/TURN server configuration, add:
STUN servers:
turn.yourdomain.com:3478
TURN servers:
turn.yourdomain.com:3478
turns:turn.yourdomain.com:5349
Set the TURN secret to the static-auth-secret value from your Coturn configuration. Select "UDP and TCP" for the TURN protocol.
Alternatively, configure via occ:
sudo -u www-data php /var/www/nextcloud/occ talk:turn:add \
"turn.yourdomain.com:3478" "udp,tcp" "YOUR_GENERATED_SECRET_HERE"
sudo -u www-data php /var/www/nextcloud/occ talk:turn:add \
"turn.yourdomain.com:5349" "tcp" "YOUR_GENERATED_SECRET_HERE" --schemes="turns"
sudo -u www-data php /var/www/nextcloud/occ talk:stun:add \
"turn.yourdomain.com:3478"
Step 4: Why TURN Server Location Matters
The physical location of your TURN server has a direct impact on call quality for relayed connections. Every packet in a relayed call takes this path: User A -> TURN server -> User B. If User A is in London and User B is in London, but the TURN server is in Singapore, every audio and video packet crosses the globe twice -- adding 300+ ms of latency to what could be a 5 ms connection.
For organizations with users in multiple geographic regions, the TURN server should be located in the same region as the majority of users -- or ideally, you should deploy multiple TURN servers in different regions. Nextcloud Talk supports multiple TURN server entries, and clients will test each one and use the fastest.
This is where multi-region deployment strategy intersects with real-time communication. A Nextcloud deployment with data centers in Europe and North America should have TURN servers in both regions. Users' WebRTC clients will automatically prefer the lowest-latency TURN server.
Network performance between data centers is equally critical. If your Nextcloud server is in Frankfurt but your TURN server is on a different network with high inter-network latency, the signaling path (Nextcloud to TURN) adds delay to call setup. Deploying both services within the same data center network eliminates this variable.
MassiveGRID's data centers in New York, London, Frankfurt, and Singapore provide low-latency connectivity for TURN servers co-located with Nextcloud deployments, ensuring that both signaling and media relay traffic take the shortest possible path.
Step 5: High Performance Backend (HPB) for Group Calls
If your organization needs group video calls with more than 4 participants, the HPB is essential. Without it, call quality degrades rapidly as participant count increases.
HPB Architecture
The HPB consists of two services that can run on the same server or on separate servers for larger deployments:
- Nextcloud Signaling Server (also called "standalone signaling server"): Handles WebSocket connections from Talk clients for presence, typing indicators, and call signaling. Written in Go, it is very efficient and can handle thousands of concurrent connections.
- Janus WebRTC Gateway: The SFU component that receives video/audio streams from participants and selectively forwards them. This is the CPU and bandwidth-intensive component.
Install Janus Gateway
Install Janus from the official packages. On Ubuntu 24.04:
sudo apt install -y janus
Configure Janus by editing /etc/janus/janus.jcfg. The critical settings for Talk integration:
general: {
configs_folder = "/etc/janus"
plugins_folder = "/usr/lib/x86_64-linux-gnu/janus/plugins"
log_to_stdout = false
debug_level = 4
admin_secret = "your-janus-admin-secret"
server_name = "nextcloud-janus"
}
media: {
rtp_port_range = "20000-40000"
}
nat: {
stun_server = "turn.yourdomain.com"
stun_port = 3478
nice_debug = false
full_trickle = true
}
Configure Janus to use WebSocket transport for communication with the signaling server. Edit /etc/janus/janus.transport.websockets.jcfg:
general: {
ws = true
ws_port = 8188
ws_ip = "127.0.0.1"
}
admin: {
admin_ws = false
}
Open the Janus RTP port range in the firewall:
sudo ufw allow 20000:40000/udp
Start Janus:
sudo systemctl enable janus
sudo systemctl start janus
Install the Signaling Server
The Nextcloud signaling server is available as a standalone binary. Download the latest release from the Nextcloud signaling server GitHub repository and install it:
wget https://github.com/strukturag/nextcloud-spreed-signaling/releases/download/v1.2.4/nextcloud-spreed-signaling_1.2.4_linux_amd64.tar.gz
tar xzf nextcloud-spreed-signaling_1.2.4_linux_amd64.tar.gz
sudo cp bin/signaling /usr/local/bin/nextcloud-signaling
sudo chmod +x /usr/local/bin/nextcloud-signaling
Create the signaling server configuration at /etc/nextcloud-signaling/server.conf:
[http]
listen = 127.0.0.1:8081
[app]
debug = false
[sessions]
hashkey = GENERATE_A_64_CHAR_HEX_SECRET
blockkey = GENERATE_A_32_CHAR_HEX_SECRET
[clients]
internalsecret = GENERATE_ANOTHER_SECRET
[backend]
backends = nextcloud
allowall = false
secret = YOUR_HPB_SHARED_SECRET
timeout = 10
connectionsperhost = 8
[backend.nextcloud]
url = https://cloud.yourdomain.com
secret = YOUR_HPB_SHARED_SECRET
[mcu]
type = janus
url = ws://127.0.0.1:8188
[turn]
apikey = YOUR_TURN_API_KEY
secret = YOUR_TURN_SECRET
servers = turn:turn.yourdomain.com:3478?transport=udp,turn:turn.yourdomain.com:3478?transport=tcp
Create a systemd service file at /etc/systemd/system/nextcloud-signaling.service:
[Unit]
Description=Nextcloud Talk Signaling Server
After=network.target
[Service]
ExecStart=/usr/local/bin/nextcloud-signaling --config /etc/nextcloud-signaling/server.conf
Restart=on-failure
User=signaling
Group=signaling
[Install]
WantedBy=multi-user.target
sudo useradd -r -s /usr/sbin/nologin signaling
sudo mkdir -p /etc/nextcloud-signaling
sudo systemctl daemon-reload
sudo systemctl enable nextcloud-signaling
sudo systemctl start nextcloud-signaling
Nginx Configuration for the Signaling Server
Add a location block to your Nextcloud Nginx configuration (or create a separate server block for a dedicated signaling domain):
location /standalone-signaling/ {
proxy_pass http://127.0.0.1:8081/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket support
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Configure Nextcloud Talk to Use the HPB
In Nextcloud admin settings under Talk, set the HPB signaling server URL:
https://cloud.yourdomain.com/standalone-signaling/
Enter the shared secret from the signaling server configuration. Alternatively, via occ:
sudo -u www-data php /var/www/nextcloud/occ config:app:set spreed stun_servers --value='[{"url":"turn.yourdomain.com:3478"}]'
sudo -u www-data php /var/www/nextcloud/occ config:app:set spreed turn_servers --value='[{"server":"turn.yourdomain.com:3478","secret":"YOUR_SECRET","protocols":"udp,tcp"}]'
sudo -u www-data php /var/www/nextcloud/occ config:app:set spreed signaling_servers --value='{"servers":[{"server":"https://cloud.yourdomain.com/standalone-signaling/","verify":true}],"secret":"YOUR_HPB_SHARED_SECRET"}'
Bandwidth Planning
Bandwidth is the most common bottleneck in video conferencing deployments. Underestimating bandwidth requirements leads to poor call quality, dropped frames, and audio breakups. Here is a practical planning guide:
Per-Participant Bandwidth Requirements
| Stream Type | Resolution | Bandwidth per Stream |
|---|---|---|
| Audio only | Opus codec | 50-100 Kbps |
| Video (low) | 320x240 | 200-400 Kbps |
| Video (standard) | 640x480 | 500 Kbps - 1 Mbps |
| Video (HD) | 1280x720 | 1.5-3 Mbps |
| Screen sharing | 1920x1080 | 1-3 Mbps |
Server-Side Bandwidth with HPB
With the HPB (SFU mode), each participant sends one stream to the server. The server then sends N-1 streams to each participant (where N is the participant count). Total server bandwidth for a call:
- Inbound: N streams (one from each participant)
- Outbound: N * (N-1) streams (forwarding each stream to all other participants)
For a 10-person HD video call: inbound is 10 * 2 Mbps = 20 Mbps, outbound is 10 * 9 * 2 Mbps = 180 Mbps. For 5 concurrent 10-person calls, the server needs approximately 1 Gbps of bandwidth.
TURN Server Bandwidth
TURN relay traffic is the most bandwidth-intensive because all media flows through the server. In the worst case, every participant in a call needs TURN relay, and the TURN server handles the full inbound and outbound load. Plan for 20-30% of your calls to use TURN relay, and size accordingly.
For organizations with heavy video conferencing usage, dedicated TURN servers with high-bandwidth network connections are essential. MassiveGRID's Cloud VPS plans with dedicated bandwidth allocations ensure that TURN relay traffic does not contend with other workloads.
Recording Backend
Nextcloud Talk supports call recording through a dedicated recording backend. When a moderator starts recording, the recording server joins the call as a hidden participant, captures all audio and video streams, and produces an MP4 file that is stored in the moderator's Nextcloud files.
The recording backend requires:
- FFmpeg: For encoding the captured streams into a video file
- Dedicated CPU: Encoding is CPU-intensive. A 10-person call recording requires approximately 2-4 CPU cores dedicated to the encoding process
- Storage: A 1-hour HD recording produces roughly 1-2 GB of video. Plan storage accordingly for organizations that record calls frequently
Install the recording backend dependencies:
sudo apt install -y ffmpeg python3 python3-pip python3-venv
python3 -m venv /opt/nextcloud-recording
source /opt/nextcloud-recording/bin/activate
pip install nextcloud-talk-recording
Configure the recording backend in /etc/nextcloud-recording/recording.conf:
[server]
listen = 127.0.0.1:8082
[backend]
url = https://cloud.yourdomain.com
secret = YOUR_RECORDING_SECRET
[ffmpeg]
outputdirectory = /tmp/nextcloud-recordings
ffmpeg = /usr/bin/ffmpeg
Configure Nextcloud to use the recording server in the Talk admin settings, specifying the recording server URL and shared secret.
Troubleshooting Common Issues
Video conferencing introduces more failure modes than typical web applications. Here are the most common issues and their solutions:
Black Screen / No Video
Symptom: Call connects, audio works, but video shows a black screen for one or both participants.
Cause: Usually a TURN/NAT traversal failure for the video stream. Audio uses less bandwidth and often succeeds through a different network path than video.
Solution: Verify TURN is configured and working. Check that UDP ports 49152-65535 (or your configured relay range) are open. Test with the Trickle ICE tool to confirm relay candidates are generated. Check Coturn logs for authentication failures.
Call Drops After 30-60 Seconds
Symptom: Call connects and works for 30-60 seconds, then drops or degrades severely.
Cause: Often a TURN credential expiration issue. Nextcloud generates time-limited TURN credentials using the shared secret. If the clocks on the Nextcloud server and TURN server are significantly out of sync, credentials expire prematurely.
Solution: Ensure NTP is running on both servers: sudo timedatectl set-ntp true. Verify the shared secret matches exactly between Nextcloud Talk settings and turnserver.conf.
One-Way Audio
Symptom: User A can hear User B, but User B cannot hear User A.
Cause: Asymmetric NAT traversal. User A's network allows the connection from STUN, but User B's more restrictive network requires TURN relay that is not working.
Solution: Ensure TURN over TCP (and ideally TURNS on port 443) is configured for users behind strict corporate firewalls. Test from the affected user's network.
HPB Connection Refused
Symptom: Talk shows "Signaling server connection failed" in the admin settings test.
Cause: Nginx is not proxying WebSocket connections to the signaling server, or the signaling server is not running.
Solution: Verify the signaling server is running: systemctl status nextcloud-signaling. Check that the Nginx location block includes the WebSocket upgrade headers (Upgrade and Connection). Test the WebSocket connection directly: curl -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" https://cloud.yourdomain.com/standalone-signaling/spreed
Poor Quality in Group Calls
Symptom: 1-on-1 calls work fine, but group calls with 4+ participants have poor quality, stuttering, or excessive CPU usage on participants' devices.
Cause: HPB is not configured, so Talk falls back to full-mesh peer-to-peer mode where each participant's bandwidth and CPU scale with participant count.
Solution: Install and configure the HPB (signaling server + Janus) as described in Step 5. Verify in the Nextcloud admin settings that the HPB shows as "OK."
Production Deployment Recommendations
For a production Nextcloud Talk deployment serving a real organization, here are the infrastructure recommendations:
- Separate TURN server from Nextcloud: TURN relay bandwidth should not compete with Nextcloud's file sync and web serving bandwidth. A dedicated VPS for Coturn is inexpensive and prevents bandwidth contention.
- Deploy HPB for any team larger than 5 people: Even if most calls are 1-on-1, the occasional team meeting with 8-10 people will fail without HPB. Install it proactively.
- Monitor bandwidth usage: Set up monitoring on your TURN and HPB servers to track bandwidth consumption over time. This data drives capacity planning as usage grows.
- Use TURNS (TLS on port 443) as a fallback: For users on restricted corporate networks, regular TURN on port 3478 may be blocked. TURNS on port 443 looks like regular HTTPS traffic and passes through almost any firewall.
- Plan for recording storage: If call recording is enabled, the storage requirements add up quickly. A 50-person organization with daily recorded standup meetings generates approximately 50-100 GB per month of recordings.
MassiveGRID's managed Nextcloud hosting includes Talk with pre-configured STUN/TURN servers co-located in the same data center as your Nextcloud instance, minimizing relay latency. The HPB is available for organizations that need reliable group video conferencing, deployed on dedicated resources that ensure consistent call quality regardless of how many file syncs are happening simultaneously.
For organizations that want a private video conferencing platform that replaces Zoom, Teams, and Google Meet -- where every call stays on infrastructure they control -- Nextcloud Talk on MassiveGRID's platform provides the infrastructure foundation with the network performance that real-time communication demands.