fix: nginx cache ignores Set-Cookie + adds explicit valid 60s
Deploy to VPS / deploy (push) Has been cancelled

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
This commit is contained in:
2026-05-05 13:48:43 -05:00
parent 1a4abfc7f2
commit aebcabd767
+16 -5
View File
@@ -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;