Why a Direct, 500 Mbit Tailscale Link Only Gave Me 10 Mbit for One Stream

Piterniel1 pts0 comments

Why a Direct, 500 Mbit Tailscale Link Only Gave Me 10 Mbit for One Stream | LTe - Today I Learned

Table of Contents

The Problem#

My self-hosted Jellyfin was slow whenever I connected to it from abroad over Tailscale. My ISP upload is about 500 Mbit/s, but streams stuttered and iperf3 over the tunnel only managed ~10 Mbit/s:

$ iperf3 -c jellyfin-host<br>[ 5] 0.00-10.00 sec 11.9 MBytes 10.0 Mbit/s<br>It wasn&rsquo;t a relay or routing issue — tailscale status showed a direct connection (not a DERP relay):

$ tailscale status<br>100.xx.xx.xx jellyfin-host linux active; direct xx.xx.xx.xx:41641<br>So: direct, low-latency, half a gigabit of upload available — and still only 10 Mbit/s for a single stream.

The Cause: Lossy UDP + CUBIC#

Mesh VPNs (Tailscale/WireGuard) wrap all traffic — including TCP — inside UDP . When a lossy mobile/WiFi link drops a UDP packet, the inner TCP sees a gap and the default CUBIC congestion control assumes congestion, halving its window. But the loss is usually random radio loss, not congestion. CUBIC throttles anyway.

A fraction of a percent of loss is enough to wreck it (throughput ∝ 1 / (RTT·√loss), where RTT is the round-trip time). A multi-stream speed test hides this; a single video stream doesn&rsquo;t. Hence &ldquo;direct, low-latency, lots of bandwidth, still slow.&rdquo;

The Fix: BBR#

BBR models bandwidth and RTT directly instead of treating loss as congestion — exactly right for a tunneled, lossy link. Set it on whatever box sends video to the client (Jellyfin server or reverse proxy):

echo "tcp_bbr" | sudo tee /etc/modules-load.d/bbr.conf<br>echo "net.core.default_qdisc=fq" | sudo tee /etc/sysctl.d/99-bbr.conf<br>echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.d/99-bbr.conf<br>sudo sysctl --system

Interleaved A/B over cellular (alternating back-to-back on the same path):

cubic: 80 87 80 Mbit/s<br>bbr: 269 248 253 Mbit/s<br>~3x, repeatable. On a clean LAN path BBR shows no gain — there&rsquo;s no loss to be resilient against, which is why a single before/after on a variable network fooled me at first.

Lessons#

&ldquo;Direct&rdquo; ≠ &ldquo;fast&rdquo; — link loss still rules.

VPN = TCP-in-UDP ; a little UDP loss kills a single inner stream under CUBIC. BBR is the cure.

mbit loss direct tailscale stream link

Related Articles