{"id":971,"date":"2026-10-31T13:00:00","date_gmt":"2026-10-31T13:00:00","guid":{"rendered":"https:\/\/vpslake.com\/blog\/?p=971"},"modified":"2026-10-31T13:00:00","modified_gmt":"2026-10-31T13:00:00","slug":"enable-bbr-debian-13","status":"publish","type":"post","link":"https:\/\/vpslake.com\/blog\/2026\/10\/31\/enable-bbr-debian-13\/","title":{"rendered":"How to Enable BBR on Debian 13 (Step-by-Step)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Enable BBR on Debian 13 to make new TCP connections use BBR with the <code>fq<\/code> packet scheduler. You can apply the change immediately and make it persistent across reboots in about five minutes, without opening a new firewall port.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">BBR does not increase your VPS plan\u2019s bandwidth limit. It changes how Linux estimates available capacity and paces TCP traffic, so the result depends on the route, remote peer, and application.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>A fresh Debian 13 (Trixie) VPS with a kernel newer than 4.9; the standard Debian 13 kernel is in the 6.12 series.<\/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 space is required because BBR is a kernel-level TCP setting.<\/li>\n\n\n<li>If you need the server first, choose a <a href=\"https:\/\/vpslake.com\/buy-vps\">Linux VPS from VPSLake<\/a> and install Debian 13.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Confirm Debian 13 and inspect the current TCP settings<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Check the release, running kernel, and current congestion-control algorithm before changing anything. This catches a mismatched image or a provider-supplied kernel that may not expose BBR.<\/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\">A normal Debian 13 installation reports Trixie and a 6.12-series kernel. <code>cubic<\/code> is commonly active before tuning, while the available list may not contain BBR yet.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Debian GNU\/Linux 13 (trixie)\n6.12.0-...-amd64\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\">The kernel revision and algorithm order vary with updates. Do not replace a working kernel merely to match the example output.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Load BBR into 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 for the current boot and check the available algorithms immediately.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo modprobe tcp_bbr\nsysctl net.ipv4.tcp_available_congestion_control<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The second command should now include <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, <code>modprobe<\/code> simply confirms that the running kernel can use it. The order of the names is not important, and the module size or <code>lsmod<\/code> output is not a reliable success test on every kernel build.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Save the module and sysctl settings<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Keep the boot-time module request separate from the TCP parameters so each part is easy to inspect or remove later.<\/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-debian13.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-debian13.conf<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The first file tells Debian\u2019s boot services to make BBR available after a reboot. The second selects BBR for new TCP connections and sets fair queueing as the default scheduler; <code>sysctl -p<\/code> applies those values now.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Expected output:<\/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\">Debian reads local kernel-parameter files from <code>\/etc\/sysctl.d\/<\/code>; the <a href=\"https:\/\/www.debian.org\/doc\/manuals\/debian-reference\/ch05.en.html\" target=\"_blank\" rel=\"noopener\">Debian Reference<\/a> documents this configuration model.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Apply <code>fq<\/code> to the active network interface<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The default qdisc setting is used when an interface is initialized, but an interface that is already up can retain its previous queue, often <code>fq_codel<\/code>. Inspect the device carrying the default route and replace its live root qdisc when necessary.<\/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 a device such as <code>ens3<\/code> or <code>eth0<\/code>. If the final command does not show <code>qdisc fq<\/code>, apply <code>fq<\/code> for the current boot:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>MAIN_IFACE=$(ip -o route show default | awk '{print $5; exit}')\nsudo 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\">The result should contain <code>qdisc fq<\/code>:<\/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\">Interface names, counters, and queue limits differ between VPS images. The <code>tc<\/code> replacement changes the live device; the saved <code>net.core.default_qdisc<\/code> value handles future interface initialization and the next boot. Keep the VPS control panel console available if your provider recreates the network device during maintenance.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Verify BBR on Debian 13<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run this complete check to prove that BBR is available, selected, saved for the next boot, and paired with <code>fq<\/code> on the interface carrying normal traffic.<\/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-debian13.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\">A successful check includes <code>tcp_congestion_control = bbr<\/code>, <code>default_qdisc = fq<\/code>, <code>bbr<\/code> in the available list, both assignments from <code>99-bbr-debian13.conf<\/code>, the line <code>tcp_bbr<\/code>, and <code>qdisc fq<\/code> for the active device. These settings affect connections created after the change, so reconnect SSH or restart a long-lived service before comparing traffic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the meaning of the TCP controls, see the <a href=\"https:\/\/docs.kernel.org\/networking\/ip-sysctl.html\" target=\"_blank\" rel=\"noopener\">Linux kernel IP sysctl reference<\/a>. BBR is enabled when the live values are correct; a speed increase is not guaranteed for every route or workload.<\/p>\n\n\n\n<aside class=\"vl-element vl-cta-banner\" aria-label=\"Tune Debian 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 Debian TCP networking<\/h3>\n\t\t<p class=\"vl-cta-banner__text\">Run Debian 13 workloads on a VPS ready for persistent BBR configuration.<\/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 provide the BBR module, or its matching module files are missing. Install Debian\u2019s standard kernel meta-package and reboot into the newly installed kernel:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt-get update\nsudo apt-get install -y linux-image-amd64\nsudo reboot<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">After reconnecting, repeat Step 2. If the VPS still boots a provider-managed custom kernel, ask the provider for a Debian 13 kernel with BBR support rather than trying to copy a module from another 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\">The sysctl file was applied before BBR became available. Load the module, confirm that <code>bbr<\/code> appears in the available list, and apply the Debian 13 file again:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo modprobe tcp_bbr\nsysctl net.ipv4.tcp_available_congestion_control\nsudo sysctl -p \/etc\/sysctl.d\/99-bbr-debian13.conf<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the error returns after every reboot, verify that <code>\/etc\/modules-load.d\/tcp-bbr.conf<\/code> contains exactly <code>tcp_bbr<\/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 supplies 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-get update\nsudo apt-get 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\">This normally indicates an unprivileged container without the capability required to change a qdisc. The TCP setting may still be usable, but the live queue cannot be changed inside that container; enable BBR on the host or move the workload to a full VPS.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Why does <code>lsmod<\/code> not always show <code>tcp_bbr<\/code>?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some kernels build BBR into the kernel or expose it without the same module-list behavior. Use <code>sysctl net.ipv4.tcp_available_congestion_control<\/code> as the authoritative check that the running kernel offers <code>bbr<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does BBR require a firewall rule?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. BBR changes TCP behavior inside the kernel and does not start a daemon or listen on a port. Leave your existing SSH and application firewall rules unchanged.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Will my current SSH session switch to BBR?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Do not assume that an already-open connection changes algorithm state. Reconnect SSH, or restart the service you are evaluating, after the verification commands report BBR.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do I restore 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-debian13.conf<\/code>, then run <code>sudo sysctl -p \/etc\/sysctl.d\/99-bbr-debian13.conf<\/code>. You can keep the module-load file because loading BBR 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\": \"Why does `lsmod` not always show `tcp_bbr`?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Some kernels build BBR into the kernel or expose it without the same module-list behavior. Use `sysctl net.ipv4.tcp_available_congestion_control` as the authoritative check that the running kernel offers `bbr`.\"}}, {\"@type\": \"Question\", \"name\": \"Does BBR require a firewall rule?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. BBR changes TCP behavior inside the kernel and does not start a daemon or listen on a port. Leave your existing SSH and application firewall rules unchanged.\"}}, {\"@type\": \"Question\", \"name\": \"Will my current SSH session switch to BBR?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Do not assume that an already-open connection changes algorithm state. Reconnect SSH, or restart the service you are evaluating, after the verification commands report BBR.\"}}, {\"@type\": \"Question\", \"name\": \"How do I restore CUBIC?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Change `net.ipv4.tcp_congestion_control = bbr` to `cubic` in `\/etc\/sysctl.d\/99-bbr-debian13.conf`, then run `sudo sysctl -p \/etc\/sysctl.d\/99-bbr-debian13.conf`. You can keep the module-load file because loading BBR does not select it as the active algorithm.\"}}]}<\/script>\n\n","protected":false},"excerpt":{"rendered":"Learn how to enable bbr on debian 13 with persistent kernel settings, live fq verification, and practical fixes for modules, qdisc errors, and reboots.","protected":false},"author":1,"featured_media":972,"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,98,114,115],"class_list":["post-971","post","type-post","status-publish","format-standard","has-post-thumbnail","category-guides","category-vps-hosting","tag-bbr","tag-debian-13","tag-linux-networking","tag-vps-tuning","cs-entry"],"_links":{"self":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/971","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=971"}],"version-history":[{"count":1,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/971\/revisions"}],"predecessor-version":[{"id":3819,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/971\/revisions\/3819"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media\/972"}],"wp:attachment":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media?parent=971"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/categories?post=971"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/tags?post=971"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}