coturn stages the cert at start, so a renewal needs a container restart.
Record that the certbot deploy hook (which lives outside this repo) now
restarts coturn alongside prosody-xmpp.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
coturn drops to nobody, but Let's Encrypt keeps privkey.pem root:root
0600, so it could not read the key and started without TLS listeners --
turns: on 5349 was silently unavailable while STUN/TURN on 3478 worked.
Copy the cert at container start into a directory owned by the runtime
user, the same approach the Prosody entrypoint already uses here, rather
than relaxing permissions on the shared Let's Encrypt tree and exposing
the key to every other container on the host.
The container now starts as root for the copy and coturn drops privileges
itself via proc-user/proc-group. Since the copy happens at start, a
renewal requires a restart, matching the existing Prosody deploy hook.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Jingle A/V (XEP-0166/0167/0176) needs a STUN/TURN server for NAT
traversal. Add coturn and advertise it to clients via XEP-0215.
- coturn container, host networking (a relay needs its full UDP port
range reachable, and Docker NAT hides the peer addresses coturn needs).
- mod_turn_external in Prosody to advertise the service and mint
time-limited credentials from a shared secret.
- Advertise UDP and TCP transports plus turns: on 5349, so clients on
UDP-blocking networks can still connect.
- Deny relaying to private ranges, so this is not an open proxy into
internal services.
TURN host is guschin.info rather than turn.guschin.info because only the
former is in the certificate SANs and turns: clients validate the name.
TURN_HOST/TURN_SECRET go in .env, which is gitignored and set per
deployment; TURN_SECRET must match static-auth-secret in turnserver.conf.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- cliff.toml: git-cliff config with semantic-style grouping (no conventional commits required)
- CHANGELOG.md: initial changelog generated from full git history
- .claude/commands/release-new.md: /release-new [major|minor|patch] skill that bumps version, updates changelog, commits, tags, and pushes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Users can now register as name@guschin.info or name@xmpp.guschin.info.
Added Let's Encrypt cert mounting and install for guschin.info domain.
Refactored entrypoint cert install into reusable function.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Without CA certs, Prosody cannot verify remote servers' certificates,
causing all server-to-server connections to fail with "not trusted".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mount specific live/ and archive/ subdirectories instead of all of
/etc/letsencrypt to avoid Prosody scanning root-only directories
(accounts/, archive/ for other domains). Also remove allow_registration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
VirtualHost changed from "guschin.info" to "xmpp.guschin.info" to match
the Let's Encrypt certificate. Moved certificates directive before
VirtualHost block. Removed misplaced default_realm and global ssl block.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>