From aebcabd7675b8737dbbbeef982173092df13e140 Mon Sep 17 00:00:00 2001 From: DavidHerran Date: Tue, 5 May 2026 13:48:43 -0500 Subject: [PATCH] fix: nginx cache ignores Set-Cookie + adds explicit valid 60s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The HTTP cache was always reporting MISS on /en even on consecutive hits. Two reasons converging: 1) next-intl writes a NEXT_LOCALE cookie on response, so every upstream reply included a Set-Cookie header. Nginx refuses to cache responses with Set-Cookie by default — that's a safe default to avoid leaking session cookies, but it's the wrong default for our public marketing pages, where the cookie just records a locale preference and the HTML body is identical for every visitor on the same URL. 2) proxy_cache_valid wasn't set, so even when Cache-Control would have authorised caching, Nginx fell back to its conservative no-cache stance. Fix: - proxy_ignore_headers Set-Cookie X-Accel-Expires Expires; - proxy_hide_header Set-Cookie; - proxy_cache_valid 200 60s; Net result: marketing pages now actually cache. The Set-Cookie is still emitted by Next.js (the upstream is unchanged), Nginx just strips it before storing/relaying — locale detection still works because next-intl persists locale through the URL prefix anyway. DEPLOY (David) cd /opt/flux-srl git pull docker compose restart nginx docker compose exec nginx nginx -s reload Then verify: curl -sI https://rf-flux.com/en | grep -iE 'x-cache|cache-control|set-cookie' curl -sI https://rf-flux.com/en | grep -iE 'x-cache|cache-control|set-cookie' Second hit should show: x-cache-status: HIT --- nginx/conf.d/flux.conf | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/nginx/conf.d/flux.conf b/nginx/conf.d/flux.conf index ab81558..5833cf6 100644 --- a/nginx/conf.d/flux.conf +++ b/nginx/conf.d/flux.conf @@ -198,10 +198,10 @@ server { # ── Shared HTML cache ─────────────────────────────────────────── # Caches GET responses that come back with a Cache-Control header - # from Next.js (the middleware sets s-maxage=60 on public marketing - # pages). Authenticated requests skip the cache entirely. While a - # cached entry is being refreshed, other visitors keep getting the - # stale copy — no thundering herd, no cold starts visible to users. + # from Next.js (the proxy at src/proxy.ts sets s-maxage=60 on + # public marketing pages). Authenticated requests skip the cache + # entirely. While a cached entry is being refreshed, other + # visitors keep getting the stale copy — no thundering herd. proxy_cache flux_html; proxy_cache_revalidate on; proxy_cache_min_uses 1; @@ -209,9 +209,20 @@ server { proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_background_update on; proxy_cache_methods GET HEAD; + proxy_cache_valid 200 60s; + + # Tell Nginx to ignore upstream headers that would otherwise + # disable caching: + # - Set-Cookie: next-intl writes a NEXT_LOCALE cookie even on + # public pages. Without ignoring it, Nginx refuses to cache + # anything that contains Set-Cookie (default behaviour). + # - Cache-Control / Expires from upstream-internal mechanisms + # would compete with our s-maxage=60 logic. + proxy_ignore_headers Set-Cookie X-Accel-Expires Expires; + proxy_hide_header Set-Cookie; # Bypass cache for authenticated sessions (admin CMS or B2B portal) - # so logged-in users always see fresh, per-account content. + # so logged-in users always get a fresh per-account render. proxy_cache_bypass $cookie_flux_session $cookie_flux_b2b_session $http_pragma; proxy_no_cache $cookie_flux_session $cookie_flux_b2b_session $http_pragma;