feat: relay Talk calls through Coturn - #126
Merged
Merged
Conversation
MattDHill
force-pushed
the
feat/coturn-talk-turn
branch
from
August 17, 2026 22:46
287eb61 to
70a0f6a
Compare
Nextcloud Talk places calls directly between participants, which fails when both ends are behind NAT or a strict firewall. Add an optional Coturn dependency, gated on a new "Relay Talk Calls Through Coturn" toggle in the Configure action, that points Talk's STUN and TURN settings at the Coturn package. Coturn authenticates with the TURN REST API shared-secret scheme rather than long-term accounts, which is exactly what Talk's TURN secret field expects — so the secret is handed over as-is and Talk mints its own ephemeral credentials. The plain and TLS endpoints sit on different ports and Talk stores a bare host:port per entry, so they go in as two entries (turn/udp,tcp and turns/tcp) rather than one carrying `turn,turns`. The `talk-turn` oneshot only ever touches entries this package added: it records what it applied in store.json and deletes exactly that before writing the new set, so Talk's default stun.nextcloud.com:443 and any hand-added entry survive. Deletes cover the incoming set too, which is what keeps a retry after a partial failure from leaving a duplicate. The secret is recorded as a hash, not in the clear — enough for a rotated secret to re-apply without a second copy of it on the volume. No health check is declared on the dependency: Coturn's own TURN Server check fails until a public domain is attached to it, which would surface here as a permanently unmet dependency even though Talk degrades gracefully to direct connections. 33.0.8:2 carries a migration, so it is spun off to v33.0.8_2.ts rather than bumped in place. Verified on the dev box against Talk 23.0.10 and Coturn 4.17.2: enabling the toggle added Coturn's domain as a STUN entry plus the two TURN entries, each carrying Coturn's own shared secret byte-for-byte; disabling removed exactly those three and left Talk's stun.nextcloud.com:443 in place. The oneshot ordered correctly behind nextcloud and finish-upgrade, and the dependency appeared and disappeared with the toggle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MattDHill
force-pushed
the
feat/coturn-talk-turn
branch
from
August 17, 2026 22:48
70a0f6a to
8102fbc
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Nextcloud Talk places calls directly between participants, which fails when both ends sit behind NAT or a strict firewall. This adds an optional Coturn dependency, gated on a new Relay Talk Calls Through Coturn toggle in the Configure action, that points Talk's STUN and TURN settings at the Coturn package.
Coturn authenticates with the TURN REST API shared secret rather than long-term accounts — exactly what Talk's TURN secret field expects — so the secret is handed over as-is and Talk mints its own ephemeral credentials.
Why two TURN entries
Talk stores a bare
host:portper entry, and the plain and TLS endpoints sit on different ports. So they go in as two entries rather than one carryingturn,turns:turn<domain>:3478udp,tcpturns<domain>:5349tcpCoturn serves TURN over TLS on TCP only, hence the asymmetry.
Only our own entries are ever touched
The
talk-turnoneshot records what it applied instore.jsonand deletes exactly that before writing the new set, so Talk's defaultstun.nextcloud.com:443and anything an admin added by hand survive. The deletes cover the incoming set too — without that, a partial failure re-adds a duplicate on retry. The secret is recorded as a hash rather than in the clear: enough for a rotated Coturn secret to re-apply, without a second copy of it on this volume.Talk is user-installed from the Nextcloud app store, so the oneshot is a no-op until its files are present — logged as a wait rather than an error, and applied on a later start.
Notes
TURN Servercheck fails until a public domain is attached to it, which would leave Nextcloud showing a permanently unmet dependency even though Talk works fine without a relay.33.0.8:2carries a migration, so it's spun off tov33.0.8_2.tsrather than bumped in place.Verified on the dev box
Against Talk 23.0.10 and Coturn 4.17.2: enabling the toggle produced
with the secret a byte-for-byte match for Coturn's
shared/turn-secret. Disabling removed exactly those three entries and leftstun.nextcloud.com:443standing. The oneshot ordered correctly behindnextcloudandfinish-upgrade, and the dependency appeared and disappeared with the toggle.🤖 Generated with Claude Code