Prefer brotli, stop compressing what is already compressed

OtherKlusterServices
Shipped
August 20, 2026 at 10:46 PM UTC
Author
Kamo
Commit
3f36bd0

The shared `compress` middleware was `compress: {}`, which is three separate defaults and none of them is the one we want. Traefik picks gzip whenever the client offers it at all, regardless of the order the client asked in. Measured against api.kamocrm.com, which is Spring Boot and does not compress at its own origin: Accept-Encoding: gzip, deflate, br, zstd -> gzip 119 bytes Accept-Encoding: br, gzip -> gzip 119 bytes Accept-Encoding: br -> br 87 bytes The second line is the finding: asking for brotli first still returned gzip. Every browser sends gzip, so nothing behind this chain has ever received brotli — about 25% of every JSON response from every Java service, given up to an ordering default. It also compressed things that are already compressed. /favicon/favicon-96x96.png is 12,763 bytes and came back as 12,793 — larger, plus compressor CPU here and decompressor CPU in the browser, on every image request on every site in the chain. The theme host already solved this with an allow-list (`theme-compress`); the same PNG served from there passes through untouched. This brings the shared chain into line. And it compressed bodies too small to benefit: api.kamocrm.com's 404 body is 99 bytes as identity and 119 bytes gzipped. minResponseBodyBytes is now set rather than assumed. The allow-list is an allow-list rather than a list of exclusions specifically because of text/event-stream. Compressing SSE buffers it, which is the one thing a stream must not do; an allow-list excludes it by construction. text/x-component is on the list on purpose — Next 16 prefetches every <Link> in the viewport as RSC, 60-100 KB apiece, and leaving it off would silently un-fix that for every Next app that does not compress at its origin. CRDs regenerated from v3.3 in the same commit, because `encodings` requires Traefik >= 3.2 and the committed CRDs were generated for a pre-3.2 release while the running binary is v3.3. The field would have been SILENTLY PRUNED by the API server, not rejected — every apply in deploy-services.yml passes --validate=false — so this would have looked applied and changed nothing. Schema diff verified purely additive: 88 fields added, 0 removed, same 10 CRDs, same versions, and `kubectl apply --dry-run=server` accepts all ten.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing