Docs / Web Servers / Compile Nginx with Brotli Compression from Source

Compile Nginx with Brotli Compression from Source

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 232 views · 4 min read

Brotli compression offers 15-25% better compression ratios than gzip for text-based assets like HTML, CSS, and JavaScript. While Nginx doesn't include Brotli by default, you can add it as a dynamic module. This guide covers building and configuring Nginx with Brotli support.

Build Nginx with Brotli Module

# Install dependencies
sudo apt install -y build-essential git libpcre3-dev zlib1g-dev libssl-dev

# Get current Nginx version
NGINX_VER=$(nginx -v 2>&1 | grep -oP '\d+\.\d+\.\d+')
echo "Current Nginx: $NGINX_VER"

# Download Nginx source
cd /opt
wget https://nginx.org/download/nginx-${NGINX_VER}.tar.gz
tar xzf nginx-${NGINX_VER}.tar.gz

# Clone Brotli module
git clone --recurse-submodules https://github.com/google/ngx_brotli.git

# Build Brotli dependencies
cd ngx_brotli/deps/brotli
mkdir out && cd out
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF ..
cmake --build . --config Release

# Build Nginx with Brotli as dynamic module
cd /opt/nginx-${NGINX_VER}
./configure --with-compat --add-dynamic-module=/opt/ngx_brotli
make modules

# Install modules
sudo cp objs/ngx_http_brotli_filter_module.so /etc/nginx/modules/
sudo cp objs/ngx_http_brotli_static_module.so /etc/nginx/modules/

Configure Brotli

# /etc/nginx/nginx.conf — load modules at top
load_module modules/ngx_http_brotli_filter_module.so;
load_module modules/ngx_http_brotli_static_module.so;

http {
    # Brotli on-the-fly compression
    brotli on;
    brotli_comp_level 6;    # 0-11, higher = better compression, slower
    brotli_static on;        # Serve pre-compressed .br files if available
    brotli_min_length 256;   # Don't compress tiny files

    brotli_types
        text/plain
        text/css
        text/javascript
        text/xml
        text/x-component
        application/javascript
        application/json
        application/xml
        application/rss+xml
        application/atom+xml
        application/vnd.ms-fontobject
        application/x-font-ttf
        application/x-font-opentype
        application/x-web-app-manifest+json
        font/opentype
        image/svg+xml
        image/x-icon;

    # Keep gzip as fallback for clients that don't support Brotli
    gzip on;
    gzip_comp_level 5;
    gzip_min_length 256;
    gzip_types text/plain text/css application/javascript application/json
        application/xml text/xml image/svg+xml;
}

# Test and reload
sudo nginx -t
sudo systemctl reload nginx

Pre-Compress Static Assets

# Pre-compress files for brotli_static
# This avoids CPU overhead of on-the-fly compression

# Install brotli CLI
sudo apt install brotli

# Compress all static assets
find /var/www/html -type f \( -name "*.css" -o -name "*.js" -o -name "*.html" -o -name "*.svg" -o -name "*.json" -o -name "*.xml" \) -exec brotli -f -k {} \;

# Build script for your deployment pipeline
#!/bin/bash
# pre-compress.sh
WEBROOT="/var/www/html"
find "$WEBROOT" -type f \( \
    -name "*.css" -o -name "*.js" -o -name "*.html" \
    -o -name "*.svg" -o -name "*.json" -o -name "*.xml" \
    -o -name "*.txt" -o -name "*.woff2" \
\) | while read file; do
    brotli -f -k --quality=11 "$file"  # Max compression for static
    gzip -f -k -9 "$file"              # Also create .gz for fallback
done
echo "Pre-compressed $(find $WEBROOT -name '*.br' | wc -l) files"

Verify Brotli is Working

# Test with curl
curl -sI -H 'Accept-Encoding: br' https://example.com | grep -i content-encoding
# Should show: content-encoding: br

# Compare compression ratios
# Original size
curl -so /dev/null -w '%{size_download}' https://example.com/style.css
# Gzip compressed
curl -so /dev/null -w '%{size_download}' -H 'Accept-Encoding: gzip' https://example.com/style.css
# Brotli compressed
curl -so /dev/null -w '%{size_download}' -H 'Accept-Encoding: br' https://example.com/style.css

Performance Tuning

# Compression level trade-offs:
# Level 1-4:  Fast, ~10% better than gzip
# Level 5-6:  Good balance (recommended for dynamic content)
# Level 7-9:  Slower, diminishing returns
# Level 10-11: Very slow, best for pre-compression only

# For dynamic content (on-the-fly):
brotli_comp_level 4;    # Fast enough for real-time

# For pre-compressed static files:
brotli --quality=11     # Maximum compression, done once

Best Practices

  • Use level 4-6 for dynamic content — higher levels are too slow for real-time compression
  • Pre-compress static assets at level 11 — maximum compression, done once during build
  • Enable brotli_static to serve pre-compressed .br files automatically
  • Keep gzip as fallback: Some clients and proxies don't support Brotli
  • Only compress text-based content: Images and videos are already compressed
  • Set brotli_min_length to avoid compressing tiny responses (overhead > savings)

Was this article helpful?