mguschin c11f05481c Fix coturn TLS listeners and pin relay to public IP.
Two problems found once coturn was running:

TLS listeners never started. The live/ certificate files are relative
symlinks into ../../archive/, so mounting live/ alone left them dangling
and coturn silently fell back to no TLS, disabling turns: on 5349.
Prosody's identical mount works only because its entrypoint copies the
files; coturn reads them in place. Mount both trees at their real paths
and reference the cert through live/.

Relay used every interface. Without explicit addresses coturn discovered
all of them and offered relay candidates on the Docker bridges and
loopback -- unreachable for remote peers, and needless exposure of the
internal networks. Pin listening-ip and relay-ip to the public address.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 22:20:37 +03:00
2026-02-02 20:12:50 +03:00
2026-02-04 13:13:46 +03:00
2026-04-29 20:22:35 +03:00
2026-03-23 14:57:12 +03:00
2026-04-29 21:53:14 +03:00
2026-02-02 20:12:50 +03:00
2026-02-04 13:13:46 +03:00
2026-02-02 20:12:50 +03:00

Prosody XMPP Server

Dockerized Prosody XMPP server with MySQL backend.

Prerequisites

  • Docker and Docker Compose
  • External MySQL network: mysqlgit_mysql_network
  • Environment variables configuration (see Configuration section)

Configuration

This setup uses environment variables for configuration. Create a .env file in the project root with:

# XMPP Configuration
XMPP_DOMAIN=xmpp.guschin.info
XMPP_USER=mish
XMPP_PASSWORD=your_password

# MySQL Configuration
MYSQL_HOST=mysql
MYSQL_USER=prosody
MYSQL_PASSWORD=your_mysql_password
MYSQL_DATABASE=prosody

Starting the Server

Run from the project directory:

docker-compose up -d

This will:

  • Build and start the Prosody container
  • Connect to external MySQL network (mysqlgit_mysql_network)
  • Wait for MySQL to be ready
  • Generate self-signed SSL/TLS certificates (if not present)
  • Configure Prosody with MySQL backend

Access Points

Service Port Description
C2S (Client to Server) 5222 XMPP client connections
S2S (Server to Server) 5269 XMPP federation
Component Protocol 5347 External components
HTTP/BOSH/WebSocket 5280 Web-based connections
HTTPS 5281 Secure web connections
STUN/TURN 3478 (UDP+TCP) NAT traversal for audio/video calls
STUN/TURN over TLS 5349 (UDP+TCP) Encrypted TURN (turns:)
TURN relay range 49160-49200 (UDP) Media relay ports

Features

  • Virtual Host: xmpp.guschin.info
  • Multi-User Chat (MUC): muc.xmpp.guschin.info
  • Storage: MySQL backend with SQL storage
  • Admin User: admin@guschin.info
  • Health Checks: Automatic container health monitoring
  • Memory Limit: 200M
  • Auto-restart: Container restarts unless stopped

Enabled Modules

Core modules: roster, saslauth, tls, dialback, disco, carbons, pep, private, blocking, vcard, version, uptime, time, ping, register, last_activity, admin_adhoc, muc_mam

Data Persistence

Volumes are mounted to persist data:

  • ./data/prosody/var/lib/prosody
  • ./logs/prosody/var/log/prosody
  • ./data/prosody/configuration/etc/prosody/conf.d

Connecting Clients

Use any XMPP client with:

  • Server: xmpp.guschin.info
  • Port: 5222
  • Username: your configured user
  • Domain: xmpp.guschin.info

Audio/Video Calls (Jingle)

Voice and video calls use Jingle (XEP-0166/0167/0176). Prosody only carries the signalling; media flows directly between clients, falling back to a TURN relay when NAT prevents a direct path.

Two pieces make this work:

  • coturn (coturn container) — the STUN/TURN server. Runs with host networking because a relay needs its whole UDP port range reachable.
  • mod_turn_external in Prosody — advertises coturn to clients over XEP-0215 and issues time-limited TURN credentials.

Configuration

TURN_SECRET in .env must match static-auth-secret in coturn/turnserver.conf. .env is gitignored, so these values are set per-deployment and not committed:

TURN_HOST=guschin.info
TURN_SECRET=<same value as static-auth-secret>

TURN_HOST is guschin.info, not turn.guschin.info: turns: (TLS) clients validate the hostname against the certificate, and only guschin.info is in the current cert's SANs. To use turn.guschin.info instead, reissue the certificate with that name added and update both TURN_HOST and the external-ip/cert settings accordingly.

turnserver.conf pins the server's public address in three places: listening-ip, relay-ip, and external-ip. Update all three if the server IP changes, otherwise coturn advertises relay candidates that peers cannot reach. Pinning them also stops coturn from auto-discovering the Docker bridge interfaces and relaying on unreachable private addresses.

Verifying

Check that Prosody advertises the service and coturn answers:

docker logs coturn                       # should show listeners on 3478/5349
docker exec prosody-xmpp prosodyctl check config

From a client, place a call between two accounts. Clients that support Jingle audio/video include Conversations (Android), Dino, Gajim, and Monal (iOS). Note that Jingle A/V is client-to-client — both parties need a client that supports it.

Firewall

Ports 3478 and 5349 (both UDP and TCP) plus the UDP relay range 49160-49200 must be reachable from the internet. The host has no local firewall (iptables INPUT policy is ACCEPT), but any provider-level firewall needs these opened.

Notes

  • TLS encryption is not required by default (configurable in prosody.cfg.lua)
  • Self-signed certificates are auto-generated on first run
  • The container depends on an external MySQL network named mysqlgit_mysql_network
Description
No description provided
Readme ISC 178 KiB
Languages
Shell 57.7%
Lua 35.5%
Dockerfile 6.8%