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:

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:

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:

  1. 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.
  2. 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:

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:

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:

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.