From c29add074804b14fb75452fe8fd6f5adc1be7b4c Mon Sep 17 00:00:00 2001 From: bvn13 Date: Sat, 28 Feb 2026 01:20:43 +0300 Subject: [PATCH] add snikket-turn (coturn) container for voice/video calls - Add snikket_turn service (coturn/coturn) with STUN/TURN/TURNS support - Mount snikket_data volume read-only for TLS certificates from snikket_certs - Add TURN_SECRET to secrets.env.example - Enable mod_external_services in Prosody and configure STUN/TURN/TURNS endpoints so clients receive time-limited credentials via XMPP IQ Co-Authored-By: Claude Sonnet 4.6 --- server/docker-compose.yml | 28 ++++++++++++++++++++++++++++ server/prosody.cfg.lua.example | 34 ++++++++++++++++++++++++++++++++++ server/secrets.env.example | 4 ++++ 3 files changed, 66 insertions(+) diff --git a/server/docker-compose.yml b/server/docker-compose.yml index 1acb7c3..75bb728 100644 --- a/server/docker-compose.yml +++ b/server/docker-compose.yml @@ -61,6 +61,34 @@ services: PRESIGN_EXPIRE: "3600" restart: "unless-stopped" + snikket_turn: + container_name: snikket-turn + image: coturn/coturn:latest + network_mode: host + env_file: + - snikket.conf + - secrets.env + volumes: + - snikket_data:/snikket:ro + entrypoint: ["/bin/sh", "-c"] + command: >- + turnserver + --use-auth-secret + --static-auth-secret=$TURN_SECRET + --realm=$SNIKKET_DOMAIN + --listening-port=3478 + --tls-listening-port=5349 + --cert=/snikket/letsencrypt/live/$SNIKKET_DOMAIN/fullchain.pem + --pkey=/snikket/letsencrypt/live/$SNIKKET_DOMAIN/privkey.pem + --min-port=49152 + --max-port=65535 + --fingerprint + --no-cli + --log-file=stdout + restart: "unless-stopped" + depends_on: + - snikket_certs + postgres: container_name: snikket-postgres image: postgres:17 diff --git a/server/prosody.cfg.lua.example b/server/prosody.cfg.lua.example index 152b783..dea7dcc 100644 --- a/server/prosody.cfg.lua.example +++ b/server/prosody.cfg.lua.example @@ -26,6 +26,7 @@ modules_disabled = { modules_enabled = { "http_upload_external"; + "external_services"; } -- URL of the external upload service that handles S3 interaction. @@ -56,3 +57,36 @@ webrtc = { } } } + +---------------------------------------------------------------------- +-- TURN/STUN for voice/video calls (via mod_external_services) +-- Credentials are generated on-the-fly using TURN REST API (RFC 8489 ยง9.2) +-- Shared secret must match TURN_SECRET in secrets.env +---------------------------------------------------------------------- + +external_services = { + { + type = "stun"; + host = os.getenv("SNIKKET_DOMAIN"); + port = 3478; + transport = "udp"; + }, + { + type = "turn"; + host = os.getenv("SNIKKET_DOMAIN"); + port = 3478; + transport = "udp"; + secret = os.getenv("TURN_SECRET"); + algorithm = "turn"; + ttl = 86400; + }, + { + type = "turns"; + host = os.getenv("SNIKKET_DOMAIN"); + port = 5349; + transport = "tcp"; + secret = os.getenv("TURN_SECRET"); + algorithm = "turn"; + ttl = 86400; + }, +}; diff --git a/server/secrets.env.example b/server/secrets.env.example index 967323c..36eb028 100644 --- a/server/secrets.env.example +++ b/server/secrets.env.example @@ -5,3 +5,7 @@ AWS_SECRET_ACCESS_KEY=change-me # PostgreSQL secrets POSTGRES_PASSWORD=change-me + +# TURN server shared secret (used by both coturn and Prosody mod_external_services) +# Generate with: openssl rand -hex 32 +TURN_SECRET=change-me