yum upgrades for production use, this is the repository for you.
Active subscription is required.
Technical Briefing: Brotli Compression for Varnish 6.0 LTS with vmod-brotli
The Problem
- Open-source Varnish only supports gzip. Brotli is a paid feature in Varnish Enterprise.
- Uplex’s open-source fetch processor, libvfp-brotli, only targets Varnish 6.2 and newer. That excludes the 6.0 LTS line, which Magento 2 and similar stacks standardize on.
- The new option: the processor has been backported to 6.0 LTS and packaged as vmod-brotli in the
getpagespeed-extras-varnish60repository channel. This is the same channel that carries vmod-pesi for parallel ESI.
The Practical Payoff
Test setup:
– File: jquery-3.7.1.js, 285,314 bytes uncompressed.
– Platform: Rocky Linux 10.
– Integrity: delivered bodies were decompressed and confirmed byte-identical to the original.
| Delivery | Bytes on wire | vs uncompressed | vs gzip |
|---|---|---|---|
Stock gzip (do_gzip) |
84,055 | 29.5% | baseline |
| vmod-brotli, default quality 11 | 69,545 | 24.4% | 17.3% smaller |
| vmod-brotli, quality 5 | 79,680 | 27.9% | 5.2% smaller |
Cold-miss compression cost was measured on a modest virtualized ARM machine, with a noise floor of about 2 ms:
| Method | Cost per miss |
|---|---|
| gzip | ~18 ms |
| brotli, quality 11 | ~333 ms |
| brotli, quality 5 | ~18 ms |
How to choose a quality level:
– Quality 11 for cacheable static assets. You pay about a third of a second once per object and save 17% bandwidth on every hit.
– Quality 5 for short-TTL or frequently-missing objects. It compresses at gzip speed and still beats gzip on size.
– Hits are served at full speed either way, because objects are stored compressed.
Installation
Supported platforms:
– EL 7–10: RHEL, Rocky, Alma, CentOS Stream, Oracle
– Amazon Linux 2 and 2023
– Fedora 43 and 44
– SLES 16
– Architectures: x86_64 and aarch64
Version pinning: the package is built against varnish-6.0.18 exactly and pins it. This prevents the module and daemon from drifting apart.
RHEL 8+ derivatives:
sudo dnf -y install https://extras.getpagespeed.com/release-latest.rpm dnf-plugins-core
sudo dnf config-manager --enable getpagespeed-extras-varnish60
sudo dnf -y install varnish vmod-brotli
EL7:
sudo yum -y install https://extras.getpagespeed.com/release-latest.rpm yum-utils
sudo yum-config-manager --enable getpagespeed-extras-varnish60
sudo yum -y install varnish vmod-brotli
Licensing caveat: production use of the repository requires a paid subscription. The subscription also covers 100+ NGINX modules.
VCL Negotiation: Critical Caveats
1. There is no decompress-on-delivery.
– vmod-brotli is a fetch processor, so objects are delivered exactly as stored.
– Serving brotli to every client would break curl, monitoring agents and older clients.
– You must therefore keep separate cache variants for brotli-capable and other clients.
2. Varnish rewrites Accept-Encoding before you can use it.
– Right after vcl_recv, and before cache lookup, Varnish normalizes Accept-Encoding to just gzip or removes it.
– As a result, br never reaches Vary matching or backend-side conditions.
3. The fix is a custom header. Record brotli capability in a custom header during vcl_recv, then hash on it:
vcl 4.0;
import brotli;
backend default { .host = "127.0.0.1"; .port = "8080"; }
sub vcl_recv {
unset req.http.X-Brotli;
if (req.http.Accept-Encoding ~ "\bbr\b") { set req.http.X-Brotli = "br"; }
}
sub vcl_hash {
if (req.http.X-Brotli) { hash_data(req.http.X-Brotli); }
}
sub vcl_backend_response {
if (beresp.http.Content-Type ~ "^(text/|application/(javascript|json|xml))") {
if (bereq.http.X-Brotli == "br") { brotli.compress(); }
else { set beresp.do_gzip = true; }
}
}
- Non-brotli clients keep the stock gzip path. This includes gunzip-on-delivery for clients with no compression support.
- This exact configuration is pinned by a regression test on every shipped distro and architecture.
Behaviors Inherited from Upstream (Re-verified on 6.0)
- Gzipped backend responses are converted. They are transparently decompressed and then brotli-compressed, so always-gzip dynamic backends work out of the box.
- Headers are adjusted. The module:
- sets
Content-Encoding: br - adds
Accept-EncodingtoVary - drops the stale
Content-Length - weakens any ETag
- sets
- Brotli compression cannot be combined with ESI.
brotli.compress()cannot be used withberesp.do_esi. The VCL fails loudly rather than corrupting responses. - The reverse direction does work with ESI.
brotli.decompress()on a brotli-sending backend works with ESI. For parallel ESI delivery, use vmod-pesi. - Partial responses are left alone. Backend 206 responses are ignored, the same as stock gzip handling.
Tuning and Observability
Defaults: brotli.compress() uses quality 11 and window 22.
Gzip-speed variant: create an encoder object with a lower quality.
sub vcl_init { new br_fast = brotli.encoder("br_fast", quality=5); }
sub vcl_backend_response { br_fast.activate(); }
Decompression: brotli.decompress() and brotli.decoder objects handle brotli-sending backends. Use them either to cache content uncompressed or to enable ESI processing.
Metrics: varnishstat exposes BROTLI.* counters for operations, input bytes and output bytes. Use them to watch the compression ratio directly in production:
varnishstat -f 'BROTLI.*'
About the Backport
Support:
– This build is not supported or endorsed by Uplex.
– Report issues to the packager, not upstream.
Provenance:
– Upstream is licensed BSD-2-Clause and publishes no release tags.
– The package uses the pristine 6.2-compatible branch under its own 0.1.0 version line.
Porting approach:
– Varnish 6.0 has no beresp.filters and no filter registry.
– The backport therefore activates the fetch processor directly at vcl_backend_response time.
Interaction with stock gzip:
– The backport relies on a 6.0 property verified in source.
– Stock gzip-family processors re-check Content-Encoding when the pipeline opens and disable themselves when they see br.
Testing:
– Two regression tests were added:
– One proves that stock behavior for other responses is untouched, covering gzip delivery, integrity checks and Range requests.
– One proves byte-correct gzip-to-brotli conversion by round-tripping through a second Varnish instance.
– The full upstream varnishtest suite passes on all 18 distro/architecture combinations with zero tests skipped. It was adapted only in activation syntax.
Read the full article: Brotli Compression for Varnish 6.0 LTS: vmod-brotli Now Packaged
