diff --git a/deployment/proxy/nginx-cms.conf b/deployment/proxy/nginx-cms.conf index 1b5f6f2a..511ace60 100644 --- a/deployment/proxy/nginx-cms.conf +++ b/deployment/proxy/nginx-cms.conf @@ -192,7 +192,7 @@ server { keepalive_timeout 30s; send_timeout 10s; - # Abuse limits. Deliberately NOT set at server scope: a room load and a page +# Abuse limits. Deliberately NOT set at server scope: a room load and a page # load are not the same request profile, so each location picks its own zone. # /gamedata/* has no request limit at all — it is a disk cache, so limiting # it only cost players their icons. The page routes carry the budget. @@ -242,7 +242,7 @@ server { location = /gamedata { return 301 /gamedata/config/; } location = /gamedata/ { return 301 /gamedata/config/; } - # ─── Gamedata: drie cache-klassen, want niet alles onder /gamedata/ is + # ─── Gamedata: vier cache-klassen, want niet alles onder /gamedata/ is # even veranderlijk. # # Dit pad had één regel voor de hele boom: `max-age=604800` (7 dagen). De @@ -259,7 +259,13 @@ server { # dat de bestandsnaam verandert (schalen, repareren), dus # ook revalideren, maar minder vaak: ze worden veel vaker # opgehaald dan ze worden geschreven. - # 3. alles wat overblijft (c_images, album*, clothes, …) — content-addressed + # 3. icons/ — `{classname}_icon.png`. Wordt wél herschreven onder + # dezelfde naam (repair-icons.ts, herimport), dus ook + # klasse 4's "nooit herschreven" geldt hier niet. Wel + # minder vaak dan 2: per uur een must-revalidate is één + # 304 per icon per uur, en een gerepareerd icon is zo + # binnen een uur zichtbaar in plaats van dagenlang oud. + # 4. alles wat overblijft (c_images, album*, clothes, …) — content-addressed # of per item uniek, nooit herschreven onder dezelfde naam. Blijft lang. location ^~ /gamedata/config/ { alias /var/www/Gamedata/config/; @@ -267,10 +273,6 @@ server { access_log off; add_header Cache-Tag "cms-gamedata"; - # Geen limit_req: gamedata is schijf-cache, geen CMS-backend. Een - # kamerladen vuurt honderden bestanden in één burst af en elke limiet - # hier leidde alleen tot zichtbaar gemiste icons. - add_header Access-Control-Allow-Origin $http_origin always; add_header Access-Control-Allow-Methods "GET, OPTIONS" always; if ($cors_headers) { @@ -278,6 +280,7 @@ server { add_header Content-Type "text/plain; charset=utf-8"; return 204; } + error_page 404 = @gamedata_missing; } location ^~ /gamedata/bundled/ { @@ -286,6 +289,22 @@ server { access_log off; add_header Cache-Tag "cms-gamedata"; + add_header Access-Control-Allow-Origin $http_origin always; + add_header Access-Control-Allow-Methods "GET, OPTIONS" always; + if ($cors_headers) { + add_header Access-Control-Max-Age 1728000; + add_header Content-Type "text/plain; charset=utf-8"; + return 204; + } + error_page 404 = @gamedata_missing; + } + + location ^~ /gamedata/icons/ { + alias /var/www/Gamedata/icons/; + add_header Cache-Control "public, max-age=3600, must-revalidate"; + access_log off; + add_header Cache-Tag "cms-gamedata"; + # Geen limit_req: gamedata is schijf-cache, geen CMS-backend. Een # kamerladen vuurt honderden bestanden in één burst af en elke limiet # hier leidde alleen tot zichtbaar gemiste icons. @@ -297,6 +316,7 @@ server { add_header Content-Type "text/plain; charset=utf-8"; return 204; } + error_page 404 = @gamedata_missing; } location /gamedata/ { @@ -312,6 +332,32 @@ server { add_header Content-Type "text/plain; charset=utf-8"; return 204; } + error_page 404 = @gamedata_missing; + } + + # Een ONTBREKEND gamedata-bestand mag nooit gecacht worden, en daarom + # krijgt elke 404 hier een eigen handler. + # + # Zonder deze handler stuurde nginx op een 404 helemaal geen Cache-Control: + # `add_header` geldt zonder `always` alleen voor 2xx/3xx. Cloudflare vond + # dan geen expliciete cache-instructie en nam de zone-instelling over: + # "Browser Cache TTL = 1 jaar". Gevolg: de 404 kwam terug als + # `cache-control: max-age=31536000` met `cf-cache-status: HIT` — dus + # vastgezet in de browser van de bezoeker én op de edge. Een icon dat één + # keer te vroeg werd opgevraagd (import nog bezig) bleef daarom het hele + # jaar een 404, ook nadat het bestand er wél stond. Dat was de "sommige + # icons laden wel, sommige niet"-klacht. + # + # `no-store` (niet een korte TTL): het bestand kan elk moment verschijnen, + # dus er is geen enkel venster waarin we een 404 willen vasthouden. De + # Cache-Tag blijft meegegeven zodat een al gecachte 404 alsnog te purgen is + # via `scripts/cf-purge.sh cms-gamedata`. + location @gamedata_missing { + add_header Cache-Control "no-store" always; + add_header Cache-Tag "cms-gamedata" always; + add_header Access-Control-Allow-Origin $http_origin always; + add_header Access-Control-Allow-Methods "GET, OPTIONS" always; + return 404; } location /camera/ {