Websites & apps

Enable Brotli compression in Nginx

Add Brotli compression to Nginx with the packaged dynamic modules on Ubuntu 24.04 and Debian 12, keep gzip as a fallback, and confirm browsers receive br encoding.

IntermediateLinux server5 min read

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, like gzip 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.

Bash
sudo apt update
sudo apt install libnginx-mod-http-brotli-filter libnginx-mod-http-brotli-static

The 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:

Bash
ls /etc/nginx/modules-enabled/ | grep -i brotli

You 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:

Bash
sudo nano /etc/nginx/conf.d/brotli.conf

Paste:

Nginx
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 on compresses responses on the fly.
  • brotli_comp_level runs 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 on serves file.css.br when it exists next to file.css.
  • brotli_types lists MIME types to compress. text/html is 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:

Bash
sudo apt install brotli

Then create .br copies of CSS and JS in your web root:

Bash
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

Bash
sudo nginx -t && sudo systemctl reload nginx

If 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:

Bash
curl -sI -H "Accept-Encoding: br" https://example.com/ | grep -i content-encoding

Expected:

content-encoding: br

Now confirm the fallback:

Bash
curl -sI -H "Accept-Encoding: gzip" https://example.com/ | grep -i content-encoding

That 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_brotli module as a dynamic module with --with-compat against 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 check modules-enabled.
  • High CPU: lower brotli_comp_level to 4, and remove image types from brotli_types.
  • Old CSS served after a deploy: a stale .br file exists. Regenerate or delete the .br copies.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.