We are running LiveKit in EKS with TURN enabled. T...
# ask-ai
p
We are running LiveKit in EKS with TURN enabled. The TURN server is configured with
turns:<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?
t
Thanks for reaching out, mithun. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — this is a great, clear question. I’m responding to your two points: what the
relay/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 Tips
p
Thanks — one important clarification about our setup: we are using LiveKit's built-in TURN server, not a separate coturn/TURN instance. The LiveKit config has
turn.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>
t
Thanks — that extra detail helps a lot. I’m replying to your two core points: whether the in-process TURN+SFU setup exposes you to UDP NAT timeouts, and whether any LiveKit configuration is needed to send keepalives for the internal port range. Short answers • Because you’re using LiveKit’s built-in TURN (TURN and SFU in the same process) and the client connects with
turns:...&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&amp;#39;s turn detection with transformers | How to implement call greeting retries in voice agents | LiveKit | Firewall Tips for LiveKit Connectivity | LiveKit