{"id":983,"date":"2026-11-02T03:00:00","date_gmt":"2026-11-02T03:00:00","guid":{"rendered":"https:\/\/vpslake.com\/blog\/?p=983"},"modified":"2026-11-02T03:00:00","modified_gmt":"2026-11-02T03:00:00","slug":"enable-bbr-ubuntu-26-04","status":"publish","type":"post","link":"https:\/\/vpslake.com\/blog\/2026\/11\/02\/enable-bbr-ubuntu-26-04\/","title":{"rendered":"How to Enable BBR on Ubuntu 26.04 (Step-by-Step)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Enable BBR on Ubuntu 26.04 to make new TCP connections use a modern congestion-control algorithm and the <code>fq<\/code> packet scheduler. You can apply the change immediately and make it survive reboots in about five minutes without opening a new firewall port.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Ubuntu Server 26.04 LTS (Resolute Raccoon), using the normal generic kernel or another kernel newer than 4.9.<\/li>\n\n\n<li>SSH access as <code>root<\/code>, or a normal user with working <code>sudo<\/code> privileges.<\/li>\n\n\n<li>Permission to load kernel modules and write files below <code>\/etc<\/code>; an unprivileged container may not provide those capabilities.<\/li>\n\n\n<li>No domain, web server, extra RAM, or extra disk is required because BBR is a kernel-level TCP setting.<\/li>\n\n\n<li>If you need the server first, start with a <a href=\"https:\/\/vpslake.com\/buy-vps\">Linux VPS from VPSLake<\/a> and install Ubuntu 26.04.<\/li>\n\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">BBR changes TCP pacing and capacity estimation; it does not increase the bandwidth limit attached to your VPS. The result depends on the route, the remote peer, and the application using TCP.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Confirm Ubuntu 26.04 and inspect TCP<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Check the release and running kernel before changing sysctl values so you do not tune a different image or a provider-supplied kernel unexpectedly.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>. \/etc\/os-release &amp;&amp; printf '%s\\n' \"$PRETTY_NAME\"\nuname -r\nsysctl net.ipv4.tcp_available_congestion_control\nsysctl net.ipv4.tcp_congestion_control<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first line should identify Ubuntu 26.04, and the release ships with a 7.0-series kernel in the standard stack. A fresh installation commonly uses <code>cubic<\/code>; BBR may already be listed if the kernel has registered it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Ubuntu 26.04 LTS\n7.0.0-...-generic\nnet.ipv4.tcp_available_congestion_control = reno cubic\nnet.ipv4.tcp_congestion_control = cubic<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Kernel patch numbers and the available algorithm list vary. Do not replace a working provider kernel just to reproduce the sample output.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Make BBR available to the running kernel<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The kernel must register BBR before a sysctl can select it, so load the module only when the current algorithm list does not already contain it.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if ! sysctl -n net.ipv4.tcp_available_congestion_control | grep -qw bbr; then\n  sudo modprobe tcp_bbr\nfi\nsysctl net.ipv4.tcp_available_congestion_control<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The final line should contain <code>bbr<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>net.ipv4.tcp_available_congestion_control = reno cubic bbr<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If BBR was already listed, the conditional skips <code>modprobe<\/code>. The order of the algorithms is not important; the check proves that the running kernel can use BBR.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Save BBR and <code>fq<\/code> for future boots<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Keep the module request and sysctl values in separate drop-in files so Ubuntu can restore both pieces at boot without changing unrelated kernel tuning.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tee \/etc\/modules-load.d\/tcp-bbr.conf &gt;\/dev\/null &lt;&lt;'EOF'\ntcp_bbr\nEOF\nsudo tee \/etc\/sysctl.d\/99-bbr.conf &gt;\/dev\/null &lt;&lt;'EOF'\nnet.core.default_qdisc = fq\nnet.ipv4.tcp_congestion_control = bbr\nEOF\nsudo sysctl -p \/etc\/sysctl.d\/99-bbr.conf<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first file asks <code>systemd-modules-load<\/code> to prepare BBR during later boots. The second selects BBR for new TCP connections and sets fair queueing as the default scheduler; the final command applies those values now.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Successful output looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>net.core.default_qdisc = fq\nnet.ipv4.tcp_congestion_control = bbr<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Ubuntu supports persistent kernel parameters through <code>\/etc\/sysctl.d\/<\/code>, and <code>modules-load.d<\/code> is the standard systemd location for a static list of modules to load at boot. The <a href=\"https:\/\/documentation.ubuntu.com\/security\/security-features\/network\/syn-cookies\/\" target=\"_blank\" rel=\"noopener\">Ubuntu sysctl guidance<\/a> and <a href=\"https:\/\/manpages.ubuntu.com\/manpages\/jammy\/man5\/modules-load.d.5.html\" target=\"_blank\" rel=\"noopener\">modules-load.d reference<\/a> describe these configuration locations.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Check the queue on the active network interface<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>net.core.default_qdisc<\/code> controls the default for interfaces created later, but the interface already carrying your SSH session can still have another root queue.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MAIN_IFACE=$(ip -o route show default | awk '{print $5; exit}')\nprintf '%s\\n' \"$MAIN_IFACE\"\ntc qdisc show dev \"$MAIN_IFACE\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first line should print the device used by the default route, often <code>ens3<\/code> or <code>eth0<\/code>. If the final command does not show <code>qdisc fq<\/code>, replace the live root queue for the current boot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo tc qdisc replace dev \"$MAIN_IFACE\" root fq\ntc qdisc show dev \"$MAIN_IFACE\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Look for a result similar to this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ens3\nqdisc fq 0: root refcnt 2 limit 10000p buckets 1024<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Your interface name and queue details will differ. The <code>tc<\/code> replacement changes the active interface without opening a port, but it is runtime state; the saved <code>default_qdisc<\/code> value handles interface initialization on a later boot. Do not bring a NetworkManager or netplan connection down over SSH unless you have the VPS control panel console available.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verify BBR on Ubuntu 26.04<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run the complete check below to prove that the active algorithm, persistent files, module availability, and live qdisc all agree.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MAIN_IFACE=$(ip -o route show default | awk '{print $5; exit}')\nsysctl net.ipv4.tcp_congestion_control net.core.default_qdisc\nsysctl net.ipv4.tcp_available_congestion_control\ngrep -Ev '^[[:space:]]*(#|$)' \/etc\/sysctl.d\/99-bbr.conf\ngrep -Fx 'tcp_bbr' \/etc\/modules-load.d\/tcp-bbr.conf\ntc qdisc show dev \"$MAIN_IFACE\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You want <code>tcp_congestion_control = bbr<\/code>, <code>default_qdisc = fq<\/code>, <code>bbr<\/code> in the available list, both assignments from <code>99-bbr.conf<\/code>, the line <code>tcp_bbr<\/code>, and <code>qdisc fq<\/code> for the active interface. These settings apply to new TCP connections, so reconnect SSH clients or restart a long-lived service before comparing network behavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The <a href=\"https:\/\/docs.kernel.org\/networking\/ip-sysctl.html\" target=\"_blank\" rel=\"noopener\">Linux kernel IP sysctl reference<\/a> confirms that <code>tcp_congestion_control<\/code> selects the algorithm for new connections. BBR cannot guarantee faster traffic on every route, so compare the application and remote peers that matter to you.<\/p>\n\n\n\n<aside class=\"vl-element vl-cta-banner\" aria-label=\"Tune Ubuntu TCP networking\">\n\t<div class=\"vl-cta-banner__content\">\n\t\t<p class=\"vl-cta-banner__eyebrow\">Linux VPS<\/p>\n\t\t<h3 class=\"vl-cta-banner__title\">Tune Ubuntu TCP networking<\/h3>\n\t\t<p class=\"vl-cta-banner__text\">Run Ubuntu 26.04 workloads on a VPS ready for persistent BBR settings.<\/p>\n\t<\/div>\n\t<a class=\"vl-cta-banner__button\" href=\"\/buy-vps\" aria-label=\"View Linux VPS plans\">View Linux VPS plans<\/a>\n<\/aside>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><code>modprobe: FATAL: Module tcp_bbr not found<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The running kernel does not expose the BBR module, or the matching module package is missing. On a standard Ubuntu generic kernel, install the extra modules package for the kernel you are running, then try Step 2 again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt install -y linux-modules-extra-$(uname -r)\nsudo modprobe tcp_bbr<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If APT cannot find that exact package, the VPS may be using a provider-managed custom kernel. Ask the provider for a supported Ubuntu 26.04 generic kernel instead of installing a package built for a different kernel.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>sysctl: cannot set net.ipv4.tcp_congestion_control<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">BBR was not available when the configuration was applied. Run Step 2, confirm that <code>bbr<\/code> appears in <code>net.ipv4.tcp_available_congestion_control<\/code>, and reload the saved file:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo sysctl -p \/etc\/sysctl.d\/99-bbr.conf<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the error returns after a reboot, verify that <code>\/etc\/modules-load.d\/tcp-bbr.conf<\/code> contains exactly <code>tcp_bbr<\/code> and that the VPS is booting the same kernel family you checked with <code>uname -r<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>tc: command not found<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The minimal image is missing <code>iproute2<\/code>, which provides both <code>ip<\/code> and <code>tc<\/code>. Install it, then repeat Step 4:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt update\nsudo apt install -y iproute2<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><code>RTNETLINK answers: Operation not permitted<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The VPS is likely an unprivileged container without the capability needed to replace a qdisc. The TCP sysctl may still work, but the live <code>fq<\/code> queue cannot be changed inside that container; ask the provider for a full VPS or the required traffic-control permission.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Does Ubuntu 26.04 need a special BBR patch?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. The standard Ubuntu 26.04 kernel is new enough for BBR; the important checks are whether <code>bbr<\/code> appears in the available algorithm list and whether the live sysctl selects it. A custom provider kernel can still omit the module.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why pair BBR with <code>fq<\/code>?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">BBR estimates the path and paces TCP traffic, while <code>fq<\/code> provides fair per-flow queueing for that paced traffic. Setting the default qdisc is useful, but checking the existing interface matters because changing a default does not always replace a queue that is already attached.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does BBR tune UDP traffic?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. <code>net.ipv4.tcp_congestion_control<\/code> applies to TCP only. UDP applications need their own rate and congestion-control behavior, so enabling BBR does not change them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do I switch back to CUBIC?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Change <code>net.ipv4.tcp_congestion_control = bbr<\/code> to <code>cubic<\/code> in <code>\/etc\/sysctl.d\/99-bbr.conf<\/code>, then run <code>sudo sysctl -p \/etc\/sysctl.d\/99-bbr.conf<\/code>. You can leave the module-load file in place because loading <code>tcp_bbr<\/code> does not select it as the active algorithm.<\/p>\n\n\n\n<script type=\"application\/ld+json\">{\"@context\": \"https:\/\/schema.org\", \"@type\": \"FAQPage\", \"mainEntity\": [{\"@type\": \"Question\", \"name\": \"Does Ubuntu 26.04 need a special BBR patch?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. The standard Ubuntu 26.04 kernel is new enough for BBR; the important checks are whether `bbr` appears in the available algorithm list and whether the live sysctl selects it. A custom provider kernel can still omit the module.\"}}, {\"@type\": \"Question\", \"name\": \"Why pair BBR with `fq`?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"BBR estimates the path and paces TCP traffic, while `fq` provides fair per-flow queueing for that paced traffic. Setting the default qdisc is useful, but checking the existing interface matters because changing a default does not always replace a queue that is already attached.\"}}, {\"@type\": \"Question\", \"name\": \"Does BBR tune UDP traffic?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. `net.ipv4.tcp_congestion_control` applies to TCP only. UDP applications need their own rate and congestion-control behavior, so enabling BBR does not change them.\"}}, {\"@type\": \"Question\", \"name\": \"How do I switch back to CUBIC?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Change `net.ipv4.tcp_congestion_control = bbr` to `cubic` in `\/etc\/sysctl.d\/99-bbr.conf`, then run `sudo sysctl -p \/etc\/sysctl.d\/99-bbr.conf`. You can leave the module-load file in place because loading `tcp_bbr` does not select it as the active algorithm.\"}}]}<\/script>\n\n","protected":false},"excerpt":{"rendered":"Learn how to enable bbr on ubuntu 26.04 with persistent kernel settings, fq queueing, live verification, and fixes for common VPS errors safely.","protected":false},"author":1,"featured_media":984,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_singular_sidebar":"","csco_page_header_type":"","csco_page_load_nextpost":"","footnotes":""},"categories":[5,9],"tags":[113,114,104,115],"class_list":["post-983","post","type-post","status-publish","format-standard","has-post-thumbnail","category-guides","category-vps-hosting","tag-bbr","tag-linux-networking","tag-ubuntu-26-04","tag-vps-tuning","cs-entry"],"_links":{"self":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/983","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/comments?post=983"}],"version-history":[{"count":1,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/983\/revisions"}],"predecessor-version":[{"id":3846,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/983\/revisions\/3846"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media\/984"}],"wp:attachment":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media?parent=983"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/categories?post=983"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/tags?post=983"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}