PiKVM v4 Plus - WebRTC TURN Relay Not Working for Restrictive Networks

Hello everyone,

I’m experiencing a critical issue with PiKVM v4 Plus where WebRTC video streams fail on restrictive networks (mobile hotspots, certain international ISPs) despite correct TURN server configuration.

Setup:

  • PiKVM v4 Plus running kvmd-platform-v4plus-hdmi-rpi4 4.61-1

  • Accessing via Tailscale VPN for security

  • Two-way audio successfully configured and working on standard networks

  • Target: I need access when im in a different country through restrictive ISP

Problem:

  • WebRTC connection establishes initially (video works for 5-6 seconds)

  • Video stream dies with “Remote track muted” in console logs

  • Pattern: Connect → Video starts → Dies in 5-6 seconds → Falls back to MJPEG (also fails)

  • Mouse/keyboard control continues working (control channel OK, video channel fails)

  • Issue ONLY occurs on restrictive networks (works perfectly on standard home/office networks)

Critical Requirements:

  1. WebRTC must work (need 2-way audio functionality)

  2. Must work through restrictive networks that block UDP/P2P

  3. Must maintain security (no IP leaks to target machine)

What I’ve Tested:

  1. TURN Configuration in override.yaml:

    • Configured Metered.ca TURN servers with proper credentials

    • Added both UDP and TCP transport options

    • TURN servers are contacted (verified 28KB usage on dashboard)

    • However, TURN is only used for signaling, NOT for media relay

  2. Custom Janus Static Configuration:

    • Switched to kvmd-janus-static

    • Added TURN configuration to /etc/kvmd/janus/janus.jcfg

    • Result: Broke WebRTC entirely, had to revert

  3. Network Diagnostics:

    • Ping through VPN: ~50-60ms latency, 3% packet loss (acceptable)

    • chrome://webrtc-internals shows connection never progresses past “new” state

    • Verified TURN credentials are valid and servers reachable

Root Cause Analysis: Based on extensive testing, PiKVM v4 Plus’s Janus WebRTC implementation appears to:

  • Use TURN for initial signaling/connection setup only

  • NOT relay actual video stream through TURN servers

  • Attempt direct peer-to-peer for video even when it should use relay

  • This fails through VPN + restrictive networks combination

Question: Is there a way to force PiKVM v4 Plus to use TURN servers for actual media relay, not just signaling? The current implementation seems to ignore the need for relay even when direct connection is impossible.

I’ve documented this extensively and can provide logs, config files, or additional testing if needed. This is blocking our ability to provide remote support to international contractors on restrictive networks.

Thank you for your attention to this issue. PiKVM is an excellent product, and solving this TURN relay issue would make it perfect for our use case.

Best regards, A complete freaking beginner at this who’s using claude ai to help me set this up.

Additional Context: This is a well-documented WebRTC requirement - when both peers are behind symmetric NATs or restrictive firewalls, TURN relay is mandatory for establishing connections (not just for signaling, but for actual media relay). STUN alone cannot facilitate connections in these scenarios. Reference: Common WebRTC deployment patterns confirm TURN is required for ~15-20% of connections globally, particularly for users in countries with restrictive ISPs or on mobile networks.

If you are using Tailscale I would think most of the connectivity should be directly between the two hosts, but they have a similar limitation to STUN/TURN but theirs they call DERP, and basically to work around extremely aggressive firewall/filtering you need to control an endpoint that both ends can reach to handle bouncing traffic in a way that isn’t blocked.

Have you tried enabling Janus static per the documentation and testing that way?

Thanks for the insight about Tailscale’s DERP relay. You’re right that Tailscale has its own relay mechanism when direct connections fail.

Yes, I tried enabling Janus static per the documentation. Here’s what happened:

  1. Switched to kvmd-janus-static:

bash

systemctl disable --now kvmd-janus
systemctl enable --now kvmd-janus-static
  1. Added TURN configuration to /etc/kvmd/janus/janus.jcfg:
nat: {
  turn_server = "global.relay.metered.ca"
  turn_port = 443
  turn_type = "tcp"
  turn_user = "[credentials]"
  turn_pwd = "[credentials]"
  ice_tcp = true
  full_trickle = true
}
  1. Result: WebRTC broke completely - wouldn’t establish connection at all. Had to revert to stock Janus.

The issue appears to be that PiKVM’s Janus implementation (even in static mode) doesn’t properly handle TURN media relay. It contacts the TURN server (verified 28KB usage on dashboard) but only uses it for signaling, not actual video relay.

Regarding Tailscale + DERP: The connection path should be:

  • Remote client → Tailscale DERP (if needed) → PiKVM → WebRTC/Janus → Back through same path

But the WebRTC layer inside PiKVM is failing to use TURN for its portion, regardless of how the outer connection (Tailscale) is handled.

Have you successfully used Janus static with TURN relay on PiKVM v4? If so, I’d love to see your working config.

I haven’t had occasion to test Janus static with STUN/TURN. On the networks where I have needed to connect I can either things up enough on one end or the other to allow it to work as-is.

According to this note from the Google Groups where Janus was developed, you basically need to define both STUN and TURN for the Janus/client configuration.

I’m not sure if Metered.ca uses something like coturn for their services or something else, but you could test with it on a public cloud VM with a public IP to see if that allows you to tunnel between your PiKVM and an accessing host on a “challenging” network to see whether some anti-abuse measures Metered.ca is using might be affecting things as well.

Update: Extensive Testing Confirms TURN Media Relay Not Working

I’ve conducted comprehensive testing to isolate this issue. The WebRTC video stream consistently fails after 5-6 seconds on restrictive networks, despite proper TURN configuration. Here are my findings:

Test Environment

  • PiKVM v4 Plus: kvmd-platform-v4plus-hdmi-rpi4 4.61-1

  • Test Networks: Mobile hotspot (Verizon), residential ISP in India

  • Baseline: Works perfectly on standard home/office networks

  • Failure Pattern: Video establishes → works for 5-6 seconds → “Remote track muted” → connection dies

Test 1: Metered.ca TURN Servers

Configuration in /etc/kvmd/override.yaml:

yaml

kvmd:
    streamer:
        h264:
            stun:
                - stun:stun.relay.metered.ca:80
            turn:
                - username: "[redacted]"
                  credential: "[redacted]"
                  urls:
                    - turn:global.relay.metered.ca:80
                    - turn:global.relay.metered.ca:80?transport=tcp
                    - turn:global.relay.metered.ca:443

Result:

  • TURN server contacted (28KB usage on dashboard)

  • Only signaling traffic, no media relay

  • Video fails after 5-6 seconds

Test 2: Self-Hosted TURN Server

Setup:

  • Deployed coturn on DigitalOcean VPS (xxx.xxx.xxx.xxx)

  • Confirmed coturn working with test clients

  • Full configuration with verbose logging enabled

PiKVM Configuration:

yaml

kvmd:
    streamer:
        h264:
            stun:
                - stun:xxx.xxx.xxx.xxx:3478
            turn:
                - username: "pikvm"
                  credential: "[redacted]"
                  urls:
                    - turn:xxx.xxx.xxx.xxx:3478
                    - turn:xxx.xxx.xxx.xxx:3478?transport=tcp

Result:

  • Minimal activity in TURN server logs

  • No media relay traffic observed

  • Same failure pattern (5-6 seconds then disconnect)

Test 3: Custom Janus Static Configuration

Following official documentation:

bash

systemctl disable --now kvmd-janus
systemctl enable --now kvmd-janus-static

Added to /etc/kvmd/janus/janus.jcfg:

nat: {
  turn_server = "xxx.xxx.xxx.xxx"
  turn_port = 3478
  turn_type = "tcp"
  turn_user = "pikvm"
  turn_pwd = "[redacted]"
  ice_tcp = true
  full_trickle = true
}

Result: WebRTC connection fails entirely with custom Janus config

Test 4: Cloudflare Tunnel

Setup:

  • Configured cloudflared tunnel

  • Accessed PiKVM through Cloudflare CDN

  • URL: https://[redacted].trycloudflare.com

Result:

  • Same failure on restrictive networks

  • Video dies after 5-6 seconds

  • Proves issue is at WebRTC/Janus layer, not network routing

Browser Console Analysis

[02:24:26.547] LOG/INFO -- Stream [Janus]: Got uStreamer result message: started
[02:24:26.568] LOG/INFO -- Stream [Janus]: Got onremotetrack: 0 true created ▶ MediaStreamTrack
[02:24:26.591] LOG/INFO -- Stream [Janus]: Peer connection state changed to connecting
[02:24:26.714] LOG/INFO -- Stream [Janus]: ICE state changed to connected
[02:24:26.983] LOG/INFO -- Stream [Janus]: Peer connection state changed to connected
[02:24:26.987] LOG/INFO -- Stream [Janus]: Janus says our WebRTC PeerConnection is up now
[02:24:32.438] LOG/INFO -- Stream [Janus]: Got onremotetrack: 0 false mute
Remote track muted: ▶ Event
Failed to load resource: net::ERR_CONNECTION_RESET

chrome://webrtc-internals Analysis

  • ICE candidates generated include STUN reflexive candidates

  • No relay candidates are ever selected

  • candidateType never shows “relay”

  • Connection state progression: new → connecting → connected → failed

Root Cause Confirmed

The PiKVM v4 Plus Janus implementation:

  1. Successfully contacts TURN servers (verified via dashboard/logs)

  2. Uses TURN for signaling only (28KB traffic observed)

  3. Does NOT relay media streams through TURN

  4. Falls back to P2P for video even when it should use relay

  5. Fails in symmetric NAT scenarios where TURN relay is mandatory

Technical Context

Per WebRTC standards:

  • ~15-20% of connections globally require TURN relay

  • Symmetric NAT scenarios (mobile networks, restrictive ISPs) mandate TURN for media

  • STUN alone cannot facilitate connections when both peers are behind restrictive NATs

  • Reference: RFC 8445 Section 2.1

Impact

This prevents PiKVM v4 Plus from functioning in:

  • Countries with restrictive ISPs (confirmed: India)

  • Mobile network access (confirmed: Verizon, AT&T)

  • Corporate networks with symmetric NATs

  • Any scenario requiring TURN relay

Request for Resolution

This appears to be a fundamental issue with how PiKVM’s Janus integration handles ICE candidates and TURN relay. The TURN configuration syntax is correct (servers are contacted), but the media streams are not being relayed through TURN when P2P fails.

Could you please:

  1. Confirm if TURN media relay is actually implemented in the current firmware

  2. Provide guidance on forcing relay-only mode if available

  3. Consider this a bug report for the Janus WebRTC implementation

I’m happy to provide additional logs, packet captures, or test specific configurations. This issue is blocking our ability to provide remote support to international contractors.

So something VERY important about mobile networks is the MTU for packets needs SIGNIFICANTLY reduced because of the overhead of transiting their towers. With Wireguard for example (and other VPNs) you may experience a large number of retries and eventually disconnects if you don’t reduce the MTU to 1280 (this number works best for both IPv4 and IPv6).

I have a suspicion the issue might be the MTU more than the STUN/TURN configuration. I’m not sure how you might set the MTU for TURN/STUN, but I know you can configure it within a Wireguard client configuration so you should be able to set that via Tailscale and see whether that improves things at all.

You might be able to try forcing TURN-TLS to get through particularly restrictive firewalls.

@NoviceAtTech any luck getting this to work over TURN-TLS?