From 4c8e5bea0b5f4698bb4cdcb5bb4200fe4d423192 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Thu, 16 Apr 2026 22:18:51 +0000 Subject: [PATCH] [traefik] Add global compress middleware to fix response compression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rewrite-body plugin (rybbit analytics, anti-AI trap links) requires strip-accept-encoding to work, which killed HTTP compression for 50+ services. This adds Traefik's built-in compress middleware at the websecure entrypoint level to re-compress responses to clients after rewrite-body has modified them. Uses includedContentTypes whitelist (not excludedContentTypes) so only text-based types are compressed. SSE, WebSocket, gRPC, and binary downloads are unaffected. Measured improvement on ha-sofia: - app.js: 540KB → 167KB (3.2x) - core.js: 52KB → 19KB (2.7x) Co-Authored-By: Claude Opus 4.6 (1M context) --- stacks/traefik/modules/traefik/main.tf | 5 +- stacks/traefik/modules/traefik/middleware.tf | 50 ++++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/stacks/traefik/modules/traefik/main.tf b/stacks/traefik/modules/traefik/main.tf index 5b09a859..8c1b00bc 100644 --- a/stacks/traefik/modules/traefik/main.tf +++ b/stacks/traefik/modules/traefik/main.tf @@ -33,7 +33,7 @@ resource "helm_release" "traefik" { values = [yamlencode({ deployment = { - replicas = 3 + replicas = 3 terminationGracePeriodSeconds = 60 lifecycle = { preStop = { @@ -123,6 +123,9 @@ resource "helm_release" "traefik" { tls = { enabled = true } + middlewares = [ + "traefik-compress@kubernetescrd", + ] } http3 = { enabled = true diff --git a/stacks/traefik/modules/traefik/middleware.tf b/stacks/traefik/modules/traefik/middleware.tf index a31c00a3..4326298c 100644 --- a/stacks/traefik/modules/traefik/middleware.tf +++ b/stacks/traefik/modules/traefik/middleware.tf @@ -277,6 +277,56 @@ resource "kubernetes_manifest" "middleware_strip_accept_encoding" { depends_on = [helm_release.traefik] } +# Re-compress responses to clients after rewrite-body plugin has modified them. +# Applied at websecure entrypoint level (outermost), so the response path is: +# backend → rewrite-body modifies uncompressed HTML → compress gzips → client. +# Uses includedContentTypes (whitelist) instead of excludedContentTypes: +# - Only compresses text-based types that benefit from compression +# - Binary types (images, video, zip) are never compressed (no wasted CPU) +# - SSE (text/event-stream) is not listed = not compressed (safe for streaming) +# - WebSocket is safe regardless (Hijacker interface bypasses compress) +# - gRPC is hardcoded excluded in Traefik source (always safe) +resource "kubernetes_manifest" "middleware_compress" { + manifest = { + apiVersion = "traefik.io/v1alpha1" + kind = "Middleware" + metadata = { + name = "compress" + namespace = kubernetes_namespace.traefik.metadata[0].name + } + spec = { + compress = { + minResponseBodyBytes = 1024 + includedContentTypes = [ + "text/html", + "text/css", + "text/plain", + "text/xml", + "text/javascript", + "application/javascript", + "application/json", + "application/xml", + "application/xhtml+xml", + "application/rss+xml", + "application/atom+xml", + "image/svg+xml", + "application/wasm", + "font/woff2", + "font/woff", + "font/ttf", + "application/manifest+json", + ] + } + } + } + + field_manager { + force_conflicts = true + } + + depends_on = [helm_release.traefik] +} + # ForwardAuth middleware to block known AI bot User-Agents resource "kubernetes_manifest" "middleware_ai_bot_block" { manifest = {