Nextcloud Talk: Fixing the problem with public IPv4 WebRTC candidate
Troubleshooting: Nextcloud Talk High-Performance Backend
Monday 6th October 2025
In the last post i struggled with IPv4 connectivity for external Nextcloud talk clients due to only the internal ip being advertised for WebRTC traffic. My workaround was to run IPv6 only but that is not ideal when there are still some IPv4 only clients out there.
I later realized that there doesn’t seem to be any good solution for IPv6-only WebRTC servers, so I had to make IPv4 work afterall.
Troubleshooting done
COTURN Settings
I had to repeatedly tell Leo (Brave AI) that my settings are correct:
$ sudo nano /etc/turnserver.conf
---------------------------------------------------------------------
# test to force IPv6
allocation-default-address-family=ipv6
tls-listening-port=5349
listening-ip=10.3.0.10
listening-ip=2001:db8:1234:3000::a
relay-ip=10.3.0.10
relay-ip=2001:db8:1234:3000::a
external-ip=85.167.128.189/10.3.0.10
external-ip=2001:4610:a:6::9969/2001:db8:1234:3000::a
Nextcloud Reverse Proxy settings
I suspected that the reason the internal IPv4 address gets chosen as WebRTC candidate was because the server doesn’t know it is behind NAT or a proxy. However, I followed this guide to make sure all reverse-proxy settings was in order:
Some things there are probably nice to have in place anyway, but none of it made any difference to me
The Solution
After some debugging of Janus.service, I thought there must be a way to hardcode the public IP. With no help from AI, I found it deep inside /etc/janus/janus.jcfg:
$ sudo nano /etc/janus/janus.jcfg
...
# Multiple public IP addresses can be specified as a comma separated list
# if the Janus is deployed in a DMZ between two 1-1 NAT for internal and
# external users.
nat_1_1_mapping = "85.167.128.189,2001:4610:a:6::9969"
#keep_private_host = true
The nat_1_1_mapping parameter is doing what the external-ip parameter in turnserver.conf is supposed to do.
Verification
Checking command line arguments...
Debug/log level is 4
Debug/log timestamps are enabled
Debug/log colors are disabled
[Thu Sep 18 16:44:30 2025] Adding ‘vmnet’ to the ICE ignore list...
[Thu Sep 18 16:44:30 2025] Using 2001:db8:1234:3000::a as local IP...
[Thu Sep 18 16:44:30 2025] Token based authentication disabled
[Thu Sep 18 16:44:30 2025] Initializing recorder code
[Thu Sep 18 16:44:30 2025] Using nat_1_1_mapping for public IP: 85.167.128.189,2001:4610:a:6::9969
[Thu Sep 18 16:44:30 2025] Initializing ICE stuff (Full mode, ICE-TCP candidates disabled, full-trickle, IPv6 support enabled)
[Thu Sep 18 16:44:30 2025] STUN server to use: hpb.libertassolutions.io:5349
[Thu Sep 18 16:44:30 2025] >> 2001:db8:1234:3000::a:5349 (IPv6)
[Thu Sep 18 16:44:30 2025] Testing STUN server: message is of 20 bytes
[Thu Sep 18 16:44:30 2025] >> Our public address is 2001:4610:a:6::9969And now it finally works! I noticed that some traffic takes IPv6 candidates, and some take IPv4. But it seems to work fine anyway as long as the traffic is TURNed, i.e. routed via the High-performance backend.


