Enable Brotli Compression on VPS with Nginx: Smaller Files, Faster Load Times
Brotli is Google’s compression algorithm that produces files 20–30% smaller than gzip at equivalent CPU cost — supported by all modern browsers. Enabling Brotli for HTML, CSS, JavaScript, and JSON responses reduces bandwidth consumption and speeds up page load times without any application code changes. This guide adds Brotli support to Nginx on Ubuntu.
Brotli vs gzip: Real-World Size Comparison
| File type | Uncompressed | gzip (level 6) | Brotli (level 6) | Saving vs gzip |
|---|---|---|---|---|
| JavaScript bundle | 250 KB | 82 KB | 68 KB | −17% |
| CSS stylesheet | 80 KB | 22 KB | 18 KB | −18% |
| HTML page | 45 KB | 12 KB | 9 KB | −25% |
| JSON API response | 100 KB | 28 KB | 21 KB | −25% |
Option A: Install Pre-Built Nginx with Brotli (Easiest)
<code"># Ubuntu 22.04/24.04: libnginx-mod-brotli is available sudo apt install -y libnginx-mod-brotli # Verify module is loaded nginx -V 2>&1 | grep brotli # The module config file is auto-installed at: # /etc/nginx/modules-enabled/50-mod-brotli.conf
Option B: Compile Nginx with ngx_brotli (If package unavailable)
<code"># Install build dependencies
sudo apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev \
libssl-dev libgd-dev libxml2-dev git
# Get current Nginx version
nginx -v # e.g., nginx/1.24.0
# Download Nginx source and ngx_brotli module
cd /tmp
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar xzf nginx-1.24.0.tar.gz
git clone --recurse-submodules https://github.com/google/ngx_brotli
cd ngx_brotli && git submodule update --init && cd /tmp
# Get current Nginx compile flags
nginx -V 2>&1 | grep "configure arguments" | sed 's/configure arguments: //'
# Compile with Brotli added (copy your existing flags, append --add-dynamic-module)
cd nginx-1.24.0
./configure YOUR_EXISTING_FLAGS --add-dynamic-module=/tmp/ngx_brotli
make modules
# Copy compiled module
sudo cp objs/ngx_http_brotli_filter_module.so /usr/share/nginx/modules/
sudo cp objs/ngx_http_brotli_static_module.so /usr/share/nginx/modules/
Step 2: Enable Brotli in Nginx Configuration
<code">sudo nano /etc/nginx/nginx.conf
Add at the top of the file (before events {}):
<code"># Load Brotli modules (only needed if not auto-loaded) # load_module /usr/share/nginx/modules/ngx_http_brotli_filter_module.so; # load_module /usr/share/nginx/modules/ngx_http_brotli_static_module.so;
Add inside the http { } block:
<code">http {
# ── Brotli dynamic compression ──────────────────────────
brotli on;
brotli_comp_level 6; # 0-11, 6 is good balance of compression/CPU
brotli_min_length 1000; # Don't compress tiny responses
brotli_types
text/plain
text/css
text/javascript
text/xml
text/x-component
application/javascript
application/x-javascript
application/json
application/xml
application/xml+rss
application/atom+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-font-opentype
application/x-font-woff
application/rss+xml
font/opentype
image/svg+xml
image/x-icon;
# ── Brotli static file serving ──────────────────────────
# Serves .br files from disk when they exist (pre-compressed)
brotli_static on;
# ── Keep gzip as fallback for older browsers ─────────────
gzip on;
gzip_comp_level 5;
gzip_min_length 1000;
gzip_vary on;
gzip_proxied any;
gzip_types
text/plain
text/css
text/javascript
application/javascript
application/json
application/xml
image/svg+xml;
}
<code">sudo nginx -t && sudo systemctl reload nginx
Step 3: Pre-Compress Static Assets (Optimal Performance)
For static files (CSS, JS, images) served by Nginx, pre-compress them at build time so Nginx serves the .br file directly — zero CPU overhead per request:
<code"># Install brotli command-line tool
sudo apt install -y brotli
# Pre-compress all CSS and JS in your web root
find /var/www/yourdomain.com -type f \( -name "*.js" -o -name "*.css" -o -name "*.html" \) \
-exec brotli --best --keep {} \;
# This creates .br files alongside originals:
# main.js → main.js.br
# styles.css → styles.css.br
# Nginx with brotli_static on; serves main.js.br when browser supports Brotli
Automate pre-compression in your deployment pipeline:
<code"># In GitHub Actions / Woodpecker CI / deployment script:
find dist/ -type f \( -name "*.js" -o -name "*.css" \) -exec brotli --best --keep {} \;
rsync -avz dist/ deploy@YOUR_VPS:/var/www/yourdomain.com/
Step 4: Verify Brotli is Working
<code"># Check response headers — browser must send Accept-Encoding: br curl -H "Accept-Encoding: br" -I https://yourdomain.com/ | grep -i "content-encoding" # Expected: content-encoding: br # If no brotli header, check: curl -H "Accept-Encoding: gzip,br" -I https://yourdomain.com/ | grep -i "content-encoding" # Verify the actual compressed response curl -H "Accept-Encoding: br" -s https://yourdomain.com/ | file - # Should show "data" (binary Brotli-encoded content) # Online test: https://tools.keycdn.com/brotli-test
Step 5: Measure the Improvement
<code"># Compare transfer sizes with and without compression
curl -so /dev/null -w "%{size_download} bytes\n" \
https://yourdomain.com/static/js/main.js
curl -H "Accept-Encoding: br" -so /dev/null -w "%{size_download} bytes\n" \
https://yourdomain.com/static/js/main.js
Brotli Compression Levels
- Level 1–3: Fast, similar to gzip — good for high-traffic dynamic content where CPU matters
- Level 4–6: Good balance — recommended for most cases (default in config above)
- Level 7–9: Better compression, more CPU — suitable for static files or low-traffic servers
- Level 10–11: Best compression, 10–100× slower — only for pre-compression, never for dynamic
Getting Started
Brotli compression works on any Ubuntu VPS at VPS.DO running Nginx. The libnginx-mod-brotli package makes installation a single apt install command. For sites with large JavaScript bundles (React, Vue, Angular apps), Brotli compression typically reduces the initial page load transfer size by 15–25% compared to gzip alone — measurable as faster First Contentful Paint on slow connections.
Conclusion
Brotli compression is a free performance win — smaller response sizes, faster load times, reduced bandwidth costs, and no application changes required. Enable dynamic Brotli compression in Nginx for real-time requests, pre-compress static assets at deployment for zero per-request CPU cost, and keep gzip as a fallback for the 2–3% of traffic from browsers that don’t support Brotli. The 20–30% size reduction over gzip is meaningful on slow mobile connections and for users in bandwidth-limited regions.