plain-hamburger-12701
03/05/2026, 10:03 AMturns:<http://turn.dev.example.net:443?transport=tcp|turn.dev.example.net:443?transport=tcp> (TLS/TCP only — no UDP TURN URL). The client connects with iceTransportPolicy: "relay".
Browser logs show:
• ICE servers: ["turns:<http://turn.dev.example.net:443?transport=tcp%22|turn.dev.example.net:443?transport=tcp">]
iceTransportPolicy: relay
Active ICE candidate pair: local=[relay/udp] 10.x.x.x:30565 ← → remote=[host/udp] 10.x.x.x:55250
• RTT ~218ms, connection state: connected
Questions:
The local candidate shows relay/udp — does this mean the browser is sending media over UDP directly, or is relay/udp just the label for the TURN-allocated relay address (i.e. the TURN→LiveKit internal leg)?
1. Can we confirm the browser-to-TURN-server leg is definitely TCP/TLS on port 443, even though the candidate type shows relay/udp?
2. Is there any risk of AWS UDP NAT timeout (75s) with this setup, or are we fully protected because the browser→TURN leg is TCP?tall-airline-16756
03/05/2026, 10:04 AMtall-airline-16756
03/05/2026, 10:04 AMrelay/udp candidate label means, and whether you’re exposed to AWS UDP NAT timeouts when you only provide a turns: TCP/TLS URL.
Short answers up front
• The relay/udp label refers to the TURN-allocated relay address and the transport used on the TURN→origin (TURN→LiveKit/SFU) side — it does not mean the browser→TURN leg is using UDP.
• Because you provided a turns: URI with transport=tcp and the client is forced to iceTransportPolicy: "relay", the browser→TURN leg is TCP/TLS on port 443. That TCP leg is not subject to UDP NAT timeout behavior, so you are not exposed to the AWS UDP 75s NAT timeout for that browser→TURN connection.
What the candidate strings represent (more detail)
• A “relay” candidate means the client is using a TURN allocation (an address the TURN server provided). The protocol label after the slash (e.g., relay/udp) is the transport/protocol used on the relay side — i.e., how the TURN server forwards packets between its public allocation and the next hop (often the SFU or origin).
• The transport between browser and TURN is determined by the ICE server URI and ICE policy. turns:...:443?transport=tcp forces the client to connect to the TURN server over TLS/TCP on port 443. The browser will establish a TCP/TLS connection to the TURN server and send media over that TCP/TLS connection to the TURN server.
• The active candidate pair you see shows the local (allocated) relay IP/port and the remote endpoint used by the SFU; it does not override the fact that the client→TURN transport is TCP/TLS.
Why UDP NAT timeout is not a concern here
• UDP NAT mappings time out separately from TCP. If the browser→TURN leg is TCP/TLS, that connection maintains its NAT mapping by virtue of the TCP connection state (keepalive/normal TCP traffic), so the AWS UDP NAT 75s expiry is not applicable to that leg.
• The TURN→LiveKit (or TURN→SFU) leg can be using UDP (and thus could be subject to UDP mapping/timeouts on the path between the TURN and the SFU), but that internal leg is managed by your TURN/LiveKit deployment. If you need the TURN→SFU leg to avoid UDP-specific timeouts, you could configure TURN-to-SFU to use TCP as well — otherwise ensure your TURN and SFU keepalive/refresh behavior handles the internal UDP path.
If you’d like, I can:
• Check what transport the TURN server is actually using toward LiveKit in your deployment (if you can share TURN and LiveKit configuration snippets or logs).
• Suggest configuration options to force TCP between TURN and LiveKit (if that’s desired) or confirm how to monitor keepalives for the TURN→SFU UDP leg.
Would you like me to check the TURN→LiveKit leg next? If so, please paste the TURN server config and the LiveKit TURN/STUN settings (redact secrets).
Sources: Firewall Tips for LiveKit Connectivity | LiveKit | Firewall Tipsplain-hamburger-12701
03/05/2026, 10:06 AMturn.enabled: true and tls_port: 443 within the same LiveKit server deployment. This means the TURN allocation and the SFU are the same process — there is no TURN→LiveKit network leg at all.
Given this, our full path is: Browser --[TLS/TCP port 443]--> LiveKit built-in TURN (NLB)
= LiveKit SFU itself. -- Questions:
Since TURN and SFU are colocated, is there any keepalive concern at all, or is this a pure in-process relay with no UDP NAT exposure?
1. Is there any recommended LiveKit config to ensure the built-in TURN sends ICE keepalives on the allocated port range (50000–60000) to prevent any internal mapping from expiring?
LiveKit config (redacted keys): rtc:
tcp_port: 7881
port_range_start: 50000
port_range_end: 60000
use_external_ip: false
turn:
enabled: true
external_tls: true
tls_port: 443
domain: <http://turn.dev.example.net|turn.dev.example.net>tall-airline-16756
03/05/2026, 10:07 AMturns:...&transport=tcp on port 443, the browser→LiveKit leg is TCP/TLS on 443. The relay/udp candidate label only describes the TURN allocation type, not the transport used between browser and TURN.
• There is no external TURN→SFU network hop in your setup, so you are not exposed to AWS UDP NAT timeouts for the browser→server leg. No additional keepalive config is required to protect that path.
Why (slightly more detail)
• A “relay” candidate indicates the client is using a TURN allocation. The protocol shown after the slash (e.g., relay/udp) reflects the protocol used on the relay endpoint itself — in your case that’s an internal allocation label — not the browser→TURN transport.
• The turns: URI with transport=tcp forces the browser to open a TCP/TLS connection to the TURN service on port 443. That TCP/TLS connection maintains its own NAT state and is not subject to UDP NAT expiry behaviors (like the AWS 75s UDP timeout).
• Because TURN and the SFU are colocated in the same process, the relaying is effectively in-process. There is no separate networked UDP leg between TURN and SFU that could be affected by an external NAT timeout.
About the configured UDP port range (50000–60000)
• Those ports are for SFU RTP/RTCP when direct UDP candidates are used. In a forced-TURN/TLS scenario, clients will send media to the TURN port (TCP/TLS 443) instead of directly to those UDP ports, so those UDP ports are not part of the browser→server path.
• LiveKit manages allocation and port binding internally for that range. Since the TURN allocation and SFU state are in-memory and bound to the same process, you do not need to configure extra ICE keepalives for those internal ports to avoid external NAT expiry.
When you might still care
• If you later deploy a separate external TURN instance (coturn or another host) or place TURN on a different machine from the SFU, then the TURN→SFU network leg could exist and you should consider keepalive/refresh behavior for UDP mappings.
• If you want to be extra conservative for long-lived connections traversing intermediate NATs/load-balancers that might aggressively close idle TCP connections, you can look at OS-level TCP keepalive or LB idle timeouts — but that’s independent of UDP NAT timeout concerns.
If you want, I can:
• Review your load-balancer (NLB) TCP idle-timeout settings to make sure they’re compatible with long-lived TLS connections.
• Show how to verify the browser→TURN transport experimentally (what to look for in browser logs / WebRTC internals) if you want to confirm on your side.
Which would you like me to check next — NLB idle-timeouts or a quick verification checklist for browser WebRTC internals?
Sources: Improving voice AI&#39;s turn detection with transformers | How to implement call greeting retries in voice agents | LiveKit | Firewall Tips for LiveKit Connectivity | LiveKit