diff --git a/deploy/varnish/default.vcl.template b/deploy/varnish/default.vcl.template index bdbb357..3d69823 100644 --- a/deploy/varnish/default.vcl.template +++ b/deploy/varnish/default.vcl.template @@ -28,28 +28,19 @@ sub vcl_recv { return (purge); } - # Specjalna obsługa WebSocket i socket.io – BARDZO WCZEŚNIE + # omijamy cache dla healthchecków / wewnętrznych nagłówków + if (req.url == "/healthcheck" || req.http.X-Internal-Check) { return (pass); } + + # Specjalna obsługa WebSocket i socket.io if (req.http.Upgrade ~ "(?i)websocket" || req.url ~ "^/socket.io/") { return (pipe); } - # omijamy cache dla healthchecków / wewnętrznych nagłówków - if (req.url == "/healthcheck" || req.http.X-Internal-Check) { - set req.http.X-Pass-Reason = "internal"; - return (pass); - } - # metody inne niż GET/HEAD bez cache - if (req.method != "GET" && req.method != "HEAD") { - set req.http.X-Pass-Reason = "method"; - return (pass); - } + if (req.method != "GET" && req.method != "HEAD") { return (pass); } # Żądania z Authorization nie są buforowane - if (req.http.Authorization) { - set req.http.X-Pass-Reason = "auth"; - return (pass); - } + if (req.http.Authorization) { return (pass); } # ---- Normalizacja Accept-Encoding (kolejność: zstd > br > gzip) ---- if (req.http.Accept-Encoding) { @@ -64,9 +55,17 @@ sub vcl_recv { } } + # ---- (Opcjonalnie) Normalizacja Accept dla obrazów generowanych wariantowo ---- + # if (req.url ~ "\.(png|jpe?g|gif|bmp)$") { + # if (req.http.Accept ~ "image/webp") { + # set req.http.X-Accept-Image = "modern"; # webp + # } else { + # set req.http.X-Accept-Image = "legacy"; # jpg/png + # } + # } + # ---- STATYCZNE – agresywny cache + ignorujemy sesję ---- - # Użyj double escape jak w działającej wersji! - if (req.url ~ "^/static/" || req.url ~ "\\.(css|js|png|jpe?g|webp|svg|ico|woff2?)$") { + if (req.url ~ "^/static/" || req.url ~ "\.(css|js|png|jpe?g|webp|svg|ico|woff2?)$") { unset req.http.Cookie; unset req.http.Authorization; return (hash); @@ -76,19 +75,36 @@ sub vcl_recv { set req.http.X-Forwarded-Proto = "https"; } - # BRAK DUPLIKATÓW – koniec wyjątków, reszta do hash + if (req.url == "/healthcheck" || req.http.X-Internal-Check) { + set req.http.X-Pass-Reason = "internal"; + return (pass); + } + + if (req.method != "GET" && req.method != "HEAD") { + set req.http.X-Pass-Reason = "method"; + return (pass); + } + + if (req.http.Authorization) { + set req.http.X-Pass-Reason = "auth"; + return (pass); + } + + # jeśli chcesz PASS przy cookie: + # if (req.http.Cookie) { + # set req.http.X-Pass-Reason = "cookie"; + # return (pass); + # } + return (hash); } -# ===== PIPE (WebSocket passthrough) – poprawione ===== +# ===== PIPE (WebSocket passthrough) ===== sub vcl_pipe { - # Kopiuj WS headers z klienta do backendu if (req.http.Upgrade) { set bereq.http.Upgrade = req.http.Upgrade; set bereq.http.Connection = req.http.Connection; } - # WAŻNE: backend nie może reuse połączenia po WS - set bereq.http.connection = "close"; } # ===== HASH ===== @@ -124,9 +140,9 @@ sub vcl_backend_response { return (deliver); } - # Nie cache'uj statyków, jeśli status ≠ 200 – double escape + # Nie cache'uj statyków, jeśli status ≠ 200 if (bereq.url ~ "^/static/" || - bereq.url ~ "\\.(css|js|png|jpe?g|webp|svg|ico|woff2?)($|\\?)") { + bereq.url ~ "\.(css|js|png|jpe?g|webp|svg|ico|woff2?)($|\?)") { if (beresp.status != 200) { set beresp.uncacheable = true; set beresp.ttl = 0s; @@ -135,31 +151,31 @@ sub vcl_backend_response { } # Jeśli pod .js przychodzi text/html — też nie cache'uj (to zwykle redirect/login) - if (bereq.url ~ "\\.js(\\?.*)?$" && beresp.http.Content-Type ~ "(?i)text/html") { + if (bereq.url ~ "\.js(\?.*)?$" && beresp.http.Content-Type ~ "(?i)text/html") { set beresp.uncacheable = true; set beresp.ttl = 0s; return (deliver); } # Wymuś poprawny Content-Type dla .js/.css, gdy backend zwróci HTML - if (bereq.url ~ "\\.js(\\?.*)?$") { + if (bereq.url ~ "\.js(\?.*)?$") { if (!beresp.http.Content-Type || beresp.http.Content-Type ~ "(?i)text/html") { set beresp.http.Content-Type = "application/javascript; charset=utf-8"; } } - if (bereq.url ~ "\\.css(\\?.*)?$") { + if (bereq.url ~ "\.css(\?.*)?$") { if (!beresp.http.Content-Type || beresp.http.Content-Type ~ "(?i)text/html") { set beresp.http.Content-Type = "text/css; charset=utf-8"; } } # ---- STATYCZNE: zdejmij Set-Cookie i Vary: Cookie, zapewnij TTL ---- - if (bereq.url ~ "^/static/" || bereq.url ~ "\\.(css|js|png|jpe?g|webp|svg|ico|woff2?)$") { + if (bereq.url ~ "^/static/" || bereq.url ~ "\.(css|js|png|jpe?g|webp|svg|ico|woff2?)$") { unset beresp.http.Set-Cookie; # Jeśli backend dodał Vary: Cookie, usuńmy ten element (nie wpływa na statyki) if (beresp.http.Vary) { - set beresp.http.Vary = regsuball(beresp.http.Vary, "(?i)(^|,)[[:space:]]*Cookie[[:space:]]*(,|$)", "\\1"); + set beresp.http.Vary = regsuball(beresp.http.Vary, "(?i)(^|,)[[:space:]]*Cookie[[:space:]]*(,|$)", "\1"); set beresp.http.Vary = regsuball(beresp.http.Vary, ",[[:space:]]*,", ","); set beresp.http.Vary = regsub(beresp.http.Vary, "^[[:space:]]*,[[:space:]]*", ""); set beresp.http.Vary = regsub(beresp.http.Vary, "[[:space:]]*,[[:space:]]*$", ""); @@ -178,9 +194,9 @@ sub vcl_backend_response { # ---- Ogólne TTL z nagłówków ---- if (beresp.http.Cache-Control ~ "(?i)s-maxage=([0-9]+)") { - set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, "(?i).*s-maxage=([0-9]+).*", "\\1") + "s", 0s); + set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, "(?i).*s-maxage=([0-9]+).*", "\1") + "s", 0s); } else if (beresp.http.Cache-Control ~ "(?i)max-age=([0-9]+)") { - set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, "(?i).*max-age=([0-9]+).*", "\\1") + "s", 0s); + set beresp.ttl = std.duration(regsub(beresp.http.Cache-Control, "(?i).*max-age=([0-9]+).*", "\1") + "s", 0s); } else if (beresp.http.Expires) { set beresp.ttl = std.time(beresp.http.Expires, now) - now; if (beresp.ttl < 0s) { set beresp.ttl = 0s; } @@ -195,7 +211,9 @@ sub vcl_backend_response { } # Kompresja po stronie Varnisha wyłącznie dla klientów akceptujących gzip + # i tylko jeśli backend nie dostarczył już Content-Encoding. if (!beresp.http.Content-Encoding && bereq.http.Accept-Encoding ~ "gzip") { + # Kompresujemy tylko „tekstowe” typy; wykluczamy WASM if (beresp.http.Content-Type ~ "(?i)text/|application/(javascript|json|xml)") { set beresp.do_gzip = true; } @@ -207,6 +225,7 @@ sub vcl_backend_response { } } +# (Opcjonalnie) Serwuj „stale” przy błędach backendu, jeśli jest obiekt w grace sub vcl_backend_error { return (deliver); } @@ -216,7 +235,7 @@ sub vcl_deliver { if (obj.uncacheable) { if (req.http.X-Pass-Reason) { set resp.http.X-Cache = "PASS:" + req.http.X-Pass-Reason; - } else if (resp.http.X-Pass-Reason) { + } else if (resp.http.X-Pass-Reason) { # z backendu set resp.http.X-Cache = "PASS:" + resp.http.X-Pass-Reason; } else { set resp.http.X-Cache = "PASS"; @@ -235,32 +254,11 @@ sub vcl_deliver { unset resp.http.Server; } -# ===== SYNTH ===== sub vcl_synth { - unset resp.http.X-Varnish; - - if (resp.status == 429) { - set resp.http.Content-Type = "text/html; charset=utf-8"; - synthetic({"429 - To many requests

429

To many requests!

Limit: 200 req / 10 s

"}); - return (deliver); - } - - if (resp.status == 405) { - set resp.http.Content-Type = "text/plain; charset=utf-8"; - synthetic("Metoda PURGE dozwolona tylko z localhost"); - return (deliver); - } - - if (resp.status == 200 && req.method == "PURGE") { - set resp.http.Content-Type = "text/plain; charset=utf-8"; - synthetic("Purged"); - return (deliver); - } - set resp.http.X-Cache = "SYNTH"; } # ===== PURGE HANDLER ===== sub vcl_purge { return (synth(200, "Purged")); -} +} \ No newline at end of file