From 086ff859114b3ca6716b40a894deb0c56e1b579a Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Sun, 14 Jun 2026 13:01:14 +0000 Subject: [PATCH] health: dedicated 100/1000 rate limit for the redesigned SPA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Viktor hit 429s browsing the redesigned health app. The default shared limiter is 10 req/s / burst 50, but each page load is the shell (JS chunks + two self-hosted Geist woff2) plus a 5-8 call API burst, so fast tab-to-tab navigation from one client IP overruns burst 50 — Traefik 429s the tail and the affected cards/pages render empty. Give health its own limiter (average 100, burst 1000) and skip the default, exactly as tripit/immich/actualbudget/ha-sofia already do for the same parallel-burst pattern. Attached via the ingress_factory escape hatch (skip_default_rate_limit + extra_middlewares). Co-Authored-By: Claude Opus 4.8 --- stacks/health/main.tf | 5 ++++ stacks/traefik/modules/traefik/middleware.tf | 25 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/stacks/health/main.tf b/stacks/health/main.tf index 5b9ae090..df3a68fe 100644 --- a/stacks/health/main.tf +++ b/stacks/health/main.tf @@ -206,6 +206,11 @@ module "ingress" { name = "health" tls_secret_name = var.tls_secret_name max_body_size = "100m" + # The redesigned SPA bursts well past the default 10/50 limiter on each page + # load (shell + fonts + a 5-8 call API burst). Swap the shared limiter for a + # health-specific one (100/1000), mirroring tripit/immich/actualbudget. + skip_default_rate_limit = true + extra_middlewares = ["health-rate-limit@kubernetescrd"] extra_annotations = { "gethomepage.dev/enabled" = "true" "gethomepage.dev/name" = "Health" diff --git a/stacks/traefik/modules/traefik/middleware.tf b/stacks/traefik/modules/traefik/middleware.tf index d2749ce0..3d26ecd2 100644 --- a/stacks/traefik/modules/traefik/middleware.tf +++ b/stacks/traefik/modules/traefik/middleware.tf @@ -344,6 +344,31 @@ resource "kubernetes_manifest" "middleware_tripit_rate_limit" { depends_on = [helm_release.traefik] } +# Health-specific rate limit. The redesigned, data-dense SPA loads the shell +# (JS chunks + two self-hosted Geist woff2) plus a 5-8 call API burst per page, +# and fast tab-to-tab navigation from one client IP blows past the default +# 10/50 limiter — 429ing the tail so cards/pages render empty (fifth instance +# of the burst pattern, after ha-sofia, ActualBudget, noVNC and tripit). Burst +# absorbs a couple of full page loads back-to-back. +resource "kubernetes_manifest" "middleware_health_rate_limit" { + manifest = { + apiVersion = "traefik.io/v1alpha1" + kind = "Middleware" + metadata = { + name = "health-rate-limit" + namespace = kubernetes_namespace.traefik.metadata[0].name + } + spec = { + rateLimit = { + average = 100 + burst = 1000 + } + } + } + + depends_on = [helm_release.traefik] +} + # Compress responses to clients at the entrypoint level (outermost). # Applied at websecure entrypoint so all responses get compressed. # Uses includedContentTypes (whitelist) instead of excludedContentTypes: