From 8a6d92afd84668edc01c2b8579739b0d567df3ad Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 1 Oct 2026 18:00:48 +0200 Subject: [PATCH] fix(cloudflare): cache the gamedata tree at the edge with respect_origin Icons are plain .png, a cacheable extension by default, so the zone's "Browser Cache TTL = 1 year" pinned them to max-age=31536000 regardless of the 300/3600/604800 that nginx sends per class. Extend the edge rule to /gamedata/ and keep respect_origin, so the nginx header wins and a 404 (notably no-store from the gamedata 404 handler) is never pinned. --- scripts/cf-setup-cache.sh | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/cf-setup-cache.sh b/scripts/cf-setup-cache.sh index f35f056a..edd8f8b2 100755 --- a/scripts/cf-setup-cache.sh +++ b/scripts/cf-setup-cache.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash # Create/update the Cloudflare Cache Rule that stores the CMS public API -# allowlist at the edge (the routes nginx tags with `Cache-Tag: cms-public`). +# allowlist plus the client-facing gamedata tree at the edge (the routes nginx +# tags with `Cache-Tag: cms-public` respectievelijk `cms-gamedata`). # # Why a rule is required: Cloudflare only caches a handful of file extensions # by default; `/api/*` responses are served `cf-cache-status: DYNAMIC` even @@ -8,12 +9,19 @@ # with "Cache Everything" turns those the other way. # # What the rule does: -# - edge_ttl bypass_by_default : edge cachet volgens de s-maxage van nginx; -# zonder (publieke) header (bv. errorresponses) juist NIET cachen. +# - edge_ttl bypass_by_default : edge cachet volgens de max-age/s-maxage van +# nginx; zonder (publieke) header (bv. errorresponses) juist NIET cachen. # - browser_ttl respect_origin : de zone heeft "Browser Cache TTL = 1 jaar" en # overschrijft daarmee het max-age dat nginx per klasse stuurt. Deze rule -# herstelt dat voor de publieke API's: browsers krijgen de korte -# max-age van nginx terug (10/60/300s) i.p.v. een jaar stale data. +# herstelt dat voor de publieke API's én /gamedata/: browsers krijgen de +# per-klasse max-age van nginx terug i.p.v. een jaar stale data. +# +# Het /gamedata/-deel is toegevoegd omdat de zone-TTL anders ook de iconen +# (`.png`, een standaard cachebare extensie) op een jaar zette: nginx stuurde +# 300/3600/604800, maar de browser kreeg `max-age=31536000` en een 404 werd als +# `max-age=31536000` + `cf-cache-status: HIT` vastgezet. Een ontbrekend icon dat +# later werd geïmporteerd bleef daardoor een jaar 404. Met `respect_origin` geldt +# de nginx-header, en die stuurt op een 404 juist `no-store`. # # Idempotent: vergelijkt de bestaande rule (op description + inhoud) en zet # alleen bij als die verschilt. Re-running is veilig. @@ -27,12 +35,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ENV_FILE="$SCRIPT_DIR/../.env" BASE="https://api.cloudflare.com/client/v4" PHASE="http_request_cache_settings" -DESCRIPTION="EpicNabbo CMS public API edge cache (cms-public)" +DESCRIPTION="EpicNabbo CMS public API + gamedata edge cache (cms-public, cms-gamedata)" # Cache de allowlist exact zoals nginx hem tagt (deployment/proxy/nginx-cms.conf). # Geen regex: `matches` vereist Business; vrije operators zijn `in` en # `starts_with()`. -EXPRESSION='(http.request.method eq "GET") and (http.request.uri.path in { "/api/staff" "/api/teams" "/api/guilds" "/api/photos" "/api/leaderboard" "/api/online" "/api/online/count" "/api/shop" "/api/shop/categories" "/api/values" "/api/values/categories" "/api/radio/current-dj" "/api/radio/points/leaderboard" } or starts_with(http.request.uri.path, "/api/values/"))' +EXPRESSION='(http.request.method eq "GET") and (http.request.uri.path in { "/api/staff" "/api/teams" "/api/guilds" "/api/photos" "/api/leaderboard" "/api/online" "/api/online/count" "/api/shop" "/api/shop/categories" "/api/values" "/api/values/categories" "/api/radio/current-dj" "/api/radio/points/leaderboard" } or starts_with(http.request.uri.path, "/api/values/") or starts_with(http.request.uri.path, "/gamedata/"))' load_env() { local name="$1"