# coturn TURN/STUN server for XMPP Jingle audio/video calls # # Credentials are NOT stored here. Prosody's mod_turn_external mints # time-limited credentials using the shared secret (see static-auth-secret), # and hands them to clients over XEP-0215. Keep the secret in sync between # this file and TURN_SECRET in .env. # Listening sockets. The container runs with network_mode: host, so these # bind directly to the server's public interface. listening-port=3478 tls-listening-port=5349 # Pin both the listening and relay addresses to the public interface. # Without these, coturn auto-discovers every interface and hands out relay # candidates on the Docker bridges (172.x, 192.168.x) and loopback, which # remote peers cannot reach and which needlessly expose internal networks. listening-ip=176.124.216.197 relay-ip=176.124.216.197 # Public address advertised in relay candidates. Without this, coturn hands # out its own view of the interface address, which breaks behind any NAT. external-ip=176.124.216.197 # Relay port range. Each concurrent call leg consumes a port from this range. min-port=49160 max-port=49200 # Authentication: long-term credentials derived from a shared secret # (REST API / TURN time-limited credentials, as used by XEP-0215). use-auth-secret static-auth-secret=e7b94c2d2af838f332a2173a5318a336bdf3cfdb812e5842266d5cd6e6e31d60 realm=guschin.info # TLS for turns:. Uses the existing multi-SAN guschin.info certificate, which # is why the advertised TURN host is guschin.info and not turn.guschin.info # (the latter is not in the cert's SANs, so TLS validation would fail). # These are the copies staged by entrypoint.sh, not the Let's Encrypt # originals: the real privkey.pem is root-only and coturn runs as nobody. cert=/var/lib/coturn/certs/fullchain.pem pkey=/var/lib/coturn/certs/privkey.pem # Drop privileges after binding. The container starts as root only so the # entrypoint can stage the certificate. proc-user=nobody proc-group=nogroup # Harden: this is a relay for our own users, not an open proxy. # Deny relaying to private ranges so TURN can't be used to reach internal # services (loopback, RFC1918, link-local, CGNAT, multicast). no-multicast-peers denied-peer-ip=0.0.0.0-0.255.255.255 denied-peer-ip=10.0.0.0-10.255.255.255 denied-peer-ip=100.64.0.0-100.127.255.255 denied-peer-ip=127.0.0.0-127.255.255.255 denied-peer-ip=169.254.0.0-169.254.255.255 denied-peer-ip=172.16.0.0-172.31.255.255 denied-peer-ip=192.0.0.0-192.0.0.255 denied-peer-ip=192.168.0.0-192.168.255.255 denied-peer-ip=198.18.0.0-198.19.255.255 denied-peer-ip=240.0.0.0-255.255.255.255 denied-peer-ip=::1 denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff # No TURN-over-plain-old-CLI admin interface, no SQLite/Redis state. no-cli # Disable legacy/weak mechanisms. no-tlsv1 no-tlsv1_1 # Per-user relay caps, to limit the blast radius of a leaked credential. user-quota=12 total-quota=1200 # Logging to stdout so `docker logs coturn` works. log-file=stdout simple-log