Brotli is a compression format built for the web. For text such as HTML, CSS and JavaScript it usually produces smaller files than gzip at a similar CPU cost, and every current browser supports it over HTTPS. Nginx does not include Brotli in its core, so you add it as a module. This guide installs the module packages, configures Brotli alongside gzip, and checks the result.
Before you start
- A Linux VPS running Ubuntu 24.04 or Debian 12 with Nginx from the distribution's own packages.
- Your site served over HTTPS. Browsers only ask for Brotli (
br) on secure connections. - gzip already set up as a fallback. See Enable gzip compression in Nginx.
- SSH access with sudo.
Note: Ubuntu 22.04 does not package the Brotli module, and neither does the AlmaLinux or Rocky Linux base repository. On those systems you need a third-party repository or a module built against your exact Nginx version. The Brotli on other systems section explains the options.
How the module works
The module comes in two parts:
- Filter module (
ngx_http_brotli_filter_module): compresses responses on the fly, likegzip on. - Static module (
ngx_http_brotli_static_module): serves files you have already compressed to.br, with no CPU cost per request.
Browsers send Accept-Encoding: gzip, deflate, br. When br is present, Nginx uses Brotli. Older clients and tools that only ask for gzip still get gzip, which is why you keep both on.
Install the module
On Ubuntu 24.04 the packages are in the universe repository, which standard Ubuntu installs have enabled. On Debian 12 they are in the main archive.
sudo apt update
sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-staticThe packages drop small loader files into /etc/nginx/modules-enabled/, so you do not need to add load_module lines yourself. Confirm they are there:
ls /etc/nginx/modules-enabled/ | grep -i brotliYou should see one file for the filter module and one for the static module.
Warning: The module package depends on the exact Nginx build. Install it from the same repository as Nginx itself. Mixing a distro module with Nginx from nginx.org or a PPA makes Nginx fail to start with a "module is not binary compatible" error.
Configure Brotli
Create a separate config file, loaded inside the http block:
sudo nano /etc/nginx/conf.d/brotli.confPaste:
brotli on;
brotli_comp_level 5;
brotli_static on;
brotli_min_length 256;
brotli_types
text/plain
text/css
text/xml
text/javascript
application/javascript
application/json
application/xml
application/rss+xml
application/atom+xml
application/ld+json
application/manifest+json
image/svg+xml
font/ttf
font/otf
application/vnd.ms-fontobject;What these do:
brotli oncompresses responses on the fly.brotli_comp_levelruns from 0 to 11. Levels 4 to 6 are a good balance for on-the-fly compression. Level 11 is very slow and only makes sense for pre-compressed files.brotli_static onservesfile.css.brwhen it exists next tofile.css.brotli_typeslists MIME types to compress.text/htmlis always included.
Leave your gzip settings in place. Nginx picks Brotli when the browser supports it and falls back to gzip otherwise.
Pre-compress static assets (optional)
For files that rarely change, compress them once at maximum level and let brotli_static serve them. Install the command-line tool:
sudo apt install brotliThen create .br copies of CSS and JS in your web root:
find /var/www/example.com/public -type f \( -name '*.css' -o -name '*.js' -o -name '*.svg' \) \
-exec brotli --best --keep --force {} \;Run it again whenever you deploy new assets, or add it to your build script. Stale .br files would be served instead of updated originals.
Apply the change
sudo nginx -t && sudo systemctl reload nginxIf the test says unknown directive "brotli", the module is not loaded. Check the files in modules-enabled and that nginx.conf still contains include /etc/nginx/modules-enabled/*.conf; near the top.
Check it works
Request a page while announcing Brotli support:
curl -sI -H "Accept-Encoding: br" https://example.com/ | grep -i content-encodingExpected:
content-encoding: brNow confirm the fallback:
curl -sI -H "Accept-Encoding: gzip" https://example.com/ | grep -i content-encodingThat should show content-encoding: gzip.
In a browser, open developer tools, go to the Network tab and reload. Click the HTML document and look under Response Headers for content-encoding: br.
Brotli on other systems
- Ubuntu 22.04: the simplest path is upgrading to 24.04, or installing Nginx and Brotli together from one third-party repository so their versions match.
- AlmaLinux and Rocky Linux: some third-party repositories ship Nginx and a matching Brotli module. Check the repository's documentation and keep Nginx from the same source.
- Building it yourself: you can compile the open source
ngx_brotlimodule as a dynamic module with--with-compatagainst the source of your exact Nginx version. You must rebuild it after every Nginx update. - Using a CDN: services such as Cloudflare can apply Brotli at the edge, so your origin only needs gzip.
Troubleshooting
- Still getting gzip in the browser: the site is on plain HTTP, or a CDN in front recompresses. Test the origin directly over HTTPS.
- Nginx fails after an upgrade with "not binary compatible": Nginx and the module came from different sources or versions. Reinstall the module from the same repository as Nginx.
unknown directive "brotli": the module is not loaded. Reinstall the package or checkmodules-enabled.- High CPU: lower
brotli_comp_levelto 4, and remove image types frombrotli_types. - Old CSS served after a deploy: a stale
.brfile exists. Regenerate or delete the.brcopies.
Next steps
- Cut repeat downloads entirely: Set browser caching headers in Nginx.
- Speed up the connection itself: Enable HTTP/2 and HTTP/3 in Nginx.
