Compression
Overview
Response compression is applied per backend via HAProxy filters. Different backends can use different algorithms, allowing you to optimize compression for each upstream service’s content type.
Algorithms
| Algorithm | Source | Description |
|---|---|---|
| gzip | HAProxy native | Widely supported, good ratio for text |
| deflate | HAProxy native | Standard deflate encoding |
| raw-deflate | HAProxy native | Raw deflate without zlib header |
| brotli | Rust Lua module | Better ratio than gzip for text, supported by modern browsers |
| zstd | Rust Lua module | Fast compression with good ratio, growing browser support |
Brotli and zstd are provided by a Rust Lua module and require the compression_enabled global toggle to be on. Gzip and deflate are HAProxy native and always available.
Per-Backend Configuration
| Setting | Description |
|---|---|
compression_algorithm | none, gzip, deflate, raw-deflate, brotli, or zstd |
compression_quality | Brotli quality (0-11, higher = better ratio, slower) |
compression_level | Zstd level (1-22, higher = better ratio, slower) |
compression_window | Brotli window size (10-24) |
compression_content_types | Comma-separated MIME prefixes to compress |
compression_offload | Strip Accept-Encoding from the backend request |
Filter Behavior
The compression filter only activates when all of the following are true:
- Request method is GET or POST
- Client sends a supported
Accept-Encodingheader - Response status is 200
- Response has no existing
Content-Encodingheader - Response has no
Cache-Control: no-transformheader - Response
Content-Typematches the configuredcompression_content_types
When compression is applied:
- Strong ETags are converted to weak ETags (the body has changed)
Transfer-Encodingswitches tochunkedContent-Lengthis removed (the length is now unknown)
Global Toggle
To enable brotli and zstd:
- Navigate to Settings > Global Options
- Enable
compression_enabled - Save and Apply
High compression levels (brotli quality 11, zstd level 22) are CPU-intensive. Start with moderate settings (brotli quality 4, zstd level 3) and increase only if you have CPU headroom and need better ratios.
FCGI Limitation
Brotli and zstd (the Lua filter) are skipped for FastCGI backends due to an HAProxy 3.4 bug. Native gzip and deflate are unaffected and work normally with FastCGI backends.
Step-by-Step: Enable Compression
- Navigate to Settings > Global Options
- Enable
compression_enabled - Save
Step-by-Step: Configure Per-Backend Compression
- Navigate to Core > Backends and open the backend
- Scroll to Compression Configuration
- Set
compression_algorithmtobrotli - Set
compression_qualityto4(good balance of ratio and speed) - Set
compression_content_typestotext/,application/javascript,application/json,image/svg - Enable
compression_offload(so the backend doesn’t also try to compress) - Save and Apply
Verification
-
Test with brotli support:
curl -k -H "Accept-Encoding: br" -sI https://localhost/ | grep -i content-encodingExpect
content-encoding: br. -
Test with gzip fallback:
curl -k -H "Accept-Encoding: gzip" -sI https://localhost/ | grep -i content-encodingExpect
content-encoding: gzip(brotli not supported by the client, falls back to gzip if configured). -
Test with no encoding:
curl -k -H "Accept-Encoding: identity" -sI https://localhost/ | grep -i content-encodingExpect no
content-encodingheader. -
Check compression ratio:
curl -k -H "Accept-Encoding: br" -s https://localhost/ | wc -c curl -k -H "Accept-Encoding: identity" -s https://localhost/ | wc -cCompare the sizes to verify compression is working.
Next Steps
- Caching — Cache compressed responses
- Response Transforms — Modify response bodies before compression
- Image Conversion — Convert images to WebP