# Nginx Brotli Compression Not Working

Brotli compression should make responses smaller than gzip, but responses aren't compressed at all, or they're compressed with gzip instead. The Content-Encoding: br header doesn't appear, even though Brotli is configured. Brotli offers better compression ratios than gzip, but the module and configuration must be correct.

Introduction

This article covers troubleshooting steps and solutions for How to Fix Nginx Brotli Compression Not Working. The error typically occurs in production environments and can cause service disruptions if not addressed promptly.

Symptoms

Common error messages include:

bash
curl -H "Accept-Encoding: br, gzip" -I http://example.com | grep -i "content-encoding"

```bash # Check for module in compile options nginx -V 2>&1 | grep brotli

# Check for dynamic module ls /etc/nginx/modules/ | grep brotli ls /usr/lib/nginx/modules/ | grep brotli

# Check if module is loaded in config grep -r "load_module" /etc/nginx/ | grep brotli ```

```bash # Ubuntu/Debian (from nginx-extras or custom repo) sudo apt install libnginx-mod-http-brotli

# Or add module repository sudo add-apt-repository ppa:ondrej/nginx sudo apt update sudo apt install nginx-module-brotli

# CentOS/RHEL sudo yum install nginx-module-brotli ```

Common Causes

  • Configuration misconfiguration
  • Missing or incorrect credentials
  • Network connectivity issues
  • Version compatibility problems
  • Resource exhaustion or limits
  • Permission or access denied

Step-by-Step Fix

  1. 1.Check logs for specific error messages
  2. 2.Verify configuration settings
  3. 3.Test network connectivity
  4. 4.Review recent changes
  5. 5.Apply corrective action
  6. 6.Verify the fix

Understanding Brotli in Nginx

  1. 1.Brotli requires:
  2. 2.Brotli module (ngx_http_brotli_module)
  3. 3.Client support (Accept-Encoding: br)
  4. 4.Correct MIME types configured
  5. 5.Sufficient quality level

Check compression status: ``bash curl -H "Accept-Encoding: br, gzip" -I http://example.com | grep -i "content-encoding"

Expect: Content-Encoding: br or Content-Encoding: gzip

Common Cause 1: Brotli Module Not Installed

The module isn't compiled into Nginx or loaded as dynamic module.

Diagnosis: ```bash # Check for module in compile options nginx -V 2>&1 | grep brotli

# Check for dynamic module ls /etc/nginx/modules/ | grep brotli ls /usr/lib/nginx/modules/ | grep brotli

# Check if module is loaded in config grep -r "load_module" /etc/nginx/ | grep brotli ```

Solution: Install Brotli module: ```bash # Ubuntu/Debian (from nginx-extras or custom repo) sudo apt install libnginx-mod-http-brotli

# Or add module repository sudo add-apt-repository ppa:ondrej/nginx sudo apt update sudo apt install nginx-module-brotli

# CentOS/RHEL sudo yum install nginx-module-brotli ```

Load dynamic module: ``nginx # In nginx.conf main context (before http block) load_module modules/ngx_http_brotli_filter_module.so; load_module modules/ngx_http_brotli_static_module.so;

Verify module loaded: ``bash sudo nginx -t # Should not error about unknown directive "brotli"

Common Cause 2: Brotli Not Enabled in Configuration

Module loaded but compression not enabled.

Problematic config: ``nginx http { # Module loaded but no brotli directives gzip on; }

Solution: Enable Brotli: ```nginx http { brotli on; brotli_comp_level 6; brotli_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;

# Minimum length to compress (default 256) brotli_min_length 256;

# Also keep gzip for older clients gzip on; gzip_comp_level 6; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; } ```

Common Cause 3: MIME Types Not Configured

Only certain MIME types are compressed by default.

Default Brotli types: Only text/html

Problem: ``nginx brotli on; # Only HTML compressed, not CSS/JS/JSON

Solution: Add all compressible types: ``nginx brotli on; brotli_types text/plain text/css text/xml application/json application/javascript application/xml application/xml+rss application/atom+xml image/svg+xml text/javascript text/x-component text/x-cross-domain-policy;

Check current response type: ```bash curl -I http://example.com/style.css | grep Content-Type # Content-Type: text/css

# If response shows Content-Type, verify it's in brotli_types ```

Common Cause 4: Client Doesn't Support Brotli

Brotli only used if client requests it.

Diagnosis: ```bash # Request with Brotli support curl -H "Accept-Encoding: br, gzip, deflate" -I http://example.com

# Request without Brotli support curl -H "Accept-Encoding: gzip, deflate" -I http://example.com ```

Browser support: - Chrome 50+, Firefox 44+, Edge 15+, Safari 11+ - Older browsers fall back to gzip

Test with different Accept-Encoding: ```bash # Brotli only curl -H "Accept-Encoding: br" -I http://example.com/style.css

# Should see: Content-Encoding: br ```

Common Cause 5: Compression Level Too Low

Quality level affects compression ratio and CPU usage.

Problem: Level 1 gives minimal compression: ``nginx brotli on; brotli_comp_level 1; # Minimal compression

Solution: Use balanced level: ```nginx brotli on; brotli_comp_level 6; # Good balance (default is 4)

# Level 4: Fast, moderate compression # Level 6: Good compression, reasonable CPU # Level 11: Maximum compression, high CPU ```

Compare compression ratios: ```bash # Test uncompressed curl -s http://example.com/style.css > uncompressed.css wc -c uncompressed.css

# Test brotli level 4 curl -s -H "Accept-Encoding: br" http://example.com/style.css > compressed.br wc -c compressed.br

# Test brotli level 11 (if configured) curl -s -H "Accept-Encoding: br" http://example.com/style.css > compressed-11.br wc -c compressed-11.br ```

Common Cause 6: Response Too Small

Small responses aren't compressed (below brotli_min_length).

Default: 256 bytes

Problem: ``nginx brotli on; brotli_min_length 256; # 100-byte responses not compressed

Solution: Lower minimum if needed: ``nginx brotli on; brotli_min_length 100;

Or check response size: ``bash curl -s http://example.com/small.json | wc -c # If < 256, won't be compressed

Common Cause 7: Pre-compressed Static Files Conflict

Static module conflicts with dynamic compression.

Brotli static module: Serves pre-compressed .br files Brotli filter module: Compresses on-the-fly

Using static pre-compression: ``nginx brotli_static on; # Looks for file.css.br and serves it if exists

Problem: .br file exists but wrong content.

Solution: Verify pre-compressed files: ```bash # Check if .br file exists ls -la /var/www/html/style.css.br

# Test pre-compressed file curl -s -H "Accept-Encoding: br" -I http://example.com/style.css

# Should see Content-Encoding: br and correct size ```

Generate pre-compressed files: ```bash # Compress all static assets find /var/www/html -name '*.css' -exec brotli {} \; find /var/www/html -name '*.js' -exec brotli {} \;

# Or parallel find /var/www/html -name '*.css' -print0 | xargs -0 -P4 brotli ```

Common Cause 8: Vary Header Issues

Vary: Accept-Encoding must be set for proper caching.

Problem: ``nginx brotli on; # Missing Vary header, cache might serve compressed to non-brotli client

Solution: Ensure Vary header: ```nginx brotli on; brotli_types text/plain text/css application/json;

# Nginx adds Vary automatically, but verify add_header Vary Accept-Encoding always; ```

Check Vary header: ``bash curl -I http://example.com/style.css | grep Vary # Vary: Accept-Encoding

Common Cause 9: Double Compression

Response already compressed upstream.

Problem: ``nginx location /api { brotli on; proxy_pass http://backend; # Backend returns gzip-compressed response # Nginx tries to brotli compress gzip -> garbage }

Solution: Decompress upstream or disable compression: ```nginx # Option 1: Tell upstream not to compress location /api { brotli on; proxy_pass http://backend; proxy_set_header Accept-Encoding ""; # Backend returns uncompressed }

# Option 2: Don't compress proxied responses location /api { proxy_pass http://backend; # Let backend handle compression } ```

Verification

  1. 1.Check module loaded:
  2. 2.```bash
  3. 3.sudo nginx -t 2>&1 | grep -i brotli
  4. 4.`
  5. 5.Check Brotli is on:
  6. 6.```nginx
  7. 7.location /brotli-test {
  8. 8.brotli on;
  9. 9.return 200 "test content here with enough bytes for compression minimum length requirement satisfied";
  10. 10.}
  11. 11.`
bash
curl -H "Accept-Encoding: br" -I http://localhost/brotli-test
# Should show: Content-Encoding: br
  1. 1.Compare sizes:
  2. 2.```bash
  3. 3.# Uncompressed
  4. 4.curl -s http://example.com/style.css | wc -c

# Brotli compressed curl -s -H "Accept-Encoding: br" http://example.com/style.css | wc -c ```

  1. 1.Check MIME types:
  2. 2.```bash
  3. 3.sudo nginx -T | grep brotli_types
  4. 4.`

Complete Working Configuration

```nginx load_module modules/ngx_http_brotli_filter_module.so; load_module modules/ngx_http_brotli_static_module.so;

http { brotli on; brotli_comp_level 6; brotli_min_length 256; brotli_buffers 16 8k;

brotli_types text/plain text/css text/xml application/json application/javascript application/xml application/xml+rss application/atom+xml image/svg+xml text/javascript application/x-javascript text/x-component text/x-cross-domain-policy application/font-ttf application/font-otf;

gzip on; gzip_comp_level 6; gzip_min_length 256; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

gzip_vary on;

server { listen 80; server_name example.com;

root /var/www/html;

# Static files - use pre-compressed if available location ~* \.(css|js)$ { brotli_static on; expires 1y; add_header Cache-Control "public, immutable"; add_header Vary Accept-Encoding; }

# Dynamic content - compress on-the-fly location / { brotli on; try_files $uri $uri/ =404; } } } ```

Verification

SymptomCauseFix
No br headerModule not loadedInstall/load module
No br headerbrotli not onAdd brotli on;
CSS/JS not compressedMissing MIME typesAdd to brotli_types
Small files not compressedBelow min_lengthLower brotli_min_length
Old clients get garbageNo gzip fallbackKeep gzip enabled
Cached wrong versionMissing Vary headerAdd Vary: Accept-Encoding
Pre-compressed not servedStatic module missingLoad static module

Brotli compression requires the module, correct MIME types, and proper client negotiation. Verify module loading first, then check MIME type configuration and compression settings.

  • [Nginx troubleshooting: Fix Lambda Permission Denied - Complete ](fix-lambda-permission-denied)
  • [Nginx web server troubleshooting: Fix Client Max Body Size Large Upload Nginx Issue ](client-max-body-size-large-upload-nginx)
  • [Fix Apache 502 Proxy Error](fix-apache-502-proxy-error)
  • [Fix Apache LogLevel Core Debug Configuration](fix-apache-loglevel-core-debug)
  • [Fix Cloudflare 502 Bad Gateway Error](fix-cloudflare-502-bad-gateway)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "How to Fix Nginx Brotli Compression Not Working", "description": "Troubleshoot Nginx Brotli compression failures. Fix module loading, MIME type configuration, and compression quality settings.", "url": "https://www.fixwikihub.com/fix-nginx-brotli-not-working", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-11-28T03:19:19.651Z", "dateModified": "2025-11-28T03:19:19.651Z" } </script>