TCP BBR on a VPS: Enabling Congestion Control and Verifying It Actually Helps

If your VPS transfers large files slowly, or throughput collapses whenever the network drops a packet, the default congestion control algorithm is a likely culprit. Most distributions still ship CUBIC, which treats every packet loss as a congestion signal and halves the send rate. On modern high-bandwidth links, BBR — Google’s Bottleneck Bandwidth and Round-trip propagation time algorithm — models the actual bottleneck instead. This article covers how to enable BBR, verify it is active, and measure whether it actually improved your throughput rather than assuming it did.

What BBR changes under the hood

CUBIC probes for bandwidth by increasing the send rate until packets drop, then backs off — loss-based control. BBR continuously measures bottleneck bandwidth and minimum RTT, then paces the sender to match. The practical effect is that BBR keeps the pipe full without treating loss as congestion, which produces large gains on bufferbloated links, long-distance routes, and shared uplinks where other tenants cause occasional drops. The trade-off: more retransmissions in genuinely loss-heavy paths, and no benefit at all if your bottleneck is local CPU or disk rather than the network.

Check your kernel and module first

BBR requires kernel 4.9 or newer; fq or fq_codel queueing discipline for pacing. Confirm availability before changing anything:

uname -r
sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control
modprobe tcp_bbr 2>/dev/null; echo $?

If bbr does not appear in the available list, load it with modprobe tcp_bbr and add it to /etc/modules-load.d/bbr.conf so it survives reboots.

Enable BBR and the fq qdisc

cat >/etc/sysctl.d/99-bbr.conf <<'EOF'
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF
sysctl --system
sysctl net.ipv4.tcp_congestion_control   # should print: bbr

Note the order: the qdisc must be fq for BBR’s pacing to work well. fq_codel also works on newer kernels, but plain pfifo_fast cripples BBR. If you are provisioning a new instance for a transfer-heavy role, our VPS comparison page shows which plans pair BBR-friendly kernels with high-bandwidth uplinks.

Verify per-connection with tcp_info

The setting is global, but results are per-flow. Check the live algorithm and delivery rate on an established connection rather than trusting the sysctl:

ss -tin state established | grep -A1 bbr
# look for: bbr, and fields bw/rtt in the tcp_info line

Goodput (the bw field in ss -ti output) is the number that matters — not the interface counter. If delivery rate stays near the link rate while retransmits (retrans in ss -ti) climb, the path is lossy and BBR is over-pacing; test bbr against cubic with a controlled transfer.

BBR v2 and the sysctl knobs that matter

Recent kernels (5.18+) may expose BBRv2, which adds ECN and loss-recovery improvements for mix networks. Check what you actually have — bbr and bbr2 are distinct modules — and do not assume a distro backport is version-faithful. Beyond the algorithm, three knobs control whether pacing works: net.core.default_qdisc must be fq (or fq_codel); net.ipv4.tcp_notsent_lowat limits how much unsent data blocks a socket, which helps latency on interactive workloads; and net.core.wmem_max caps the send buffer so a single fast flow cannot starve others. Setting BBR without fq is the single most common configuration error — the kernel falls back to loss-based pacing and you see none of the benefit.

When BBR is the wrong answer

BBR helps when the bottleneck is the wide-area network. It does nothing when your own CPU is saturated encrypting TLS, when a disk read is the limiter, or when the receiver’s window is the constraint. It can also be counterproductive in a datacenter-to-datacenter link where CUBIC already saturates the path and BBR’s probing adds retransmits. Before enabling it fleet-wide, classify what is actually slow: run iperf3 between hosts to isolate the network, then check CPU and disk on the sender. If a plain iperf3 from the VPS reaches the link rate with CUBIC, BBR has nothing to fix. Measure the counterfactual — a control run with CUBIC — rather than assuming modern equals faster.

Interaction with TLS and request/response workloads

BBR’s benefit is proportional to the size of the transfer and the distance to the peer. A single short TLS handshake dominated by the round-trip does not improve; a large file or a video segment does. For web servers this means the wins cluster in static asset delivery, streamed responses, and large API payloads, while small JSON responses see almost nothing. If your traffic is overwhelmingly small requests, the effort is better spent on TLS session resumption, HTTP/2 or HTTP/3 multiplexing, and reducing round-trips than on congestion control. BBR and connection-reuse optimizations are complementary, not competing — but be honest about which one your workload actually rewards before you invest in either.

Measure before you celebrate

Run the same transfer before and after the change. A repeatable test beats a single speedtest run:

# baseline
sysctl -w net.ipv4.tcp_congestion_control=cubic
iperf3 -c <peer> -t 30 -P 4 --json > cubic.json
# candidate
sysctl -w net.ipv4.tcp_congestion_control=bbr
iperf3 -c <peer> -t 30 -P 4 --json > bbr.json

Compare retransmits and goodput, not just throughput. If your workload is a web front-end, the real test is TTFB and p95 response time under load; BBR helps most when the bottleneck is the WAN, and disappears when CPU in the guest is the limit. Picking a plan with dedicated cores removes the CPU ceiling so BBR can do its job — see our performance VPS plans for configurations with guaranteed vCPU allocation. Finally, remember BBR is not a substitute for correct buffers: pair it with tcp_rmem/tcp_wmem sized to the bandwidth-delay product or you will leave throughput on the table.

Leave a Reply