93 lines
2.7 KiB
Plaintext
93 lines
2.7 KiB
Plaintext
vcl 4.1;
|
||
|
||
import vsthrottle;
|
||
import std;
|
||
|
||
backend app {
|
||
.host = "app";
|
||
.port = "${APP_PORT}";
|
||
}
|
||
|
||
/* unikamy duplikatu; dodajemy IPv6 */
|
||
acl purge { "127.0.0.1"; "::1"; }
|
||
|
||
sub vcl_recv {
|
||
# RATE LIMIT: 100 żądań / 10s, blokada 60s
|
||
if (vsthrottle.is_denied(client.identity, 100, 10s, 60s)) {
|
||
return (synth(429, "Too Many Requests"));
|
||
}
|
||
|
||
# PURGE tylko lokalnie
|
||
if (req.method == "PURGE") {
|
||
if (!client.ip ~ purge) { return (synth(405, "Not allowed")); }
|
||
return (purge);
|
||
}
|
||
|
||
# omijamy cache dla healthchecków / wewn. nagłówka
|
||
if (req.url == "/healthcheck" || req.http.X-Internal-Check) { return (pass); }
|
||
|
||
# metody inne niż GET/HEAD bez cache
|
||
if (req.method != "GET" && req.method != "HEAD") { return (pass); }
|
||
|
||
# statyczne – agresywny cache
|
||
if (req.url ~ "^/static/" || req.url ~ "\.(css|js|png|jpg|svg|ico|woff2?)$") {
|
||
return (hash);
|
||
}
|
||
|
||
return (hash);
|
||
}
|
||
|
||
sub vcl_backend_response {
|
||
# Treści prywatne / zakazane do cache
|
||
if (beresp.http.Cache-Control ~ "(?i)no-store|private") {
|
||
set beresp.uncacheable = true;
|
||
set beresp.ttl = 0s;
|
||
return (deliver);
|
||
}
|
||
|
||
# Preferuj s-maxage, potem max-age
|
||
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);
|
||
} 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);
|
||
} else if (beresp.http.Expires) {
|
||
# fallback na Expires
|
||
set beresp.ttl = std.time(beresp.http.Expires, now, 0s) - now;
|
||
} else {
|
||
# ostateczny fallback
|
||
set beresp.ttl = 60s;
|
||
}
|
||
|
||
# Jeśli immutable – zwiększ grace/keep
|
||
if (beresp.http.Cache-Control ~ "(?i)immutable") {
|
||
set beresp.grace = 1h;
|
||
set beresp.keep = 24h;
|
||
}
|
||
|
||
# statykom daj minimalne TTL, gdy backend NIE ustawił CC
|
||
if ((bereq.url ~ "^/static/" || bereq.url ~ "\.(css|js|png|jpg|svg|ico|woff2?)$")
|
||
&& !(beresp.http.Cache-Control ~ "(?i)(s-maxage|max-age)")) {
|
||
set beresp.ttl = 24h;
|
||
}
|
||
}
|
||
|
||
sub vcl_deliver {
|
||
if (obj.hits > 0) {
|
||
set resp.http.X-Cache = "HIT";
|
||
# ukryj niepotrzebny nagłówek z MISS
|
||
#} else {
|
||
# set resp.http.X-Cache = "MISS";
|
||
}
|
||
|
||
# Nagłówki rate limit – MUSZĄ używać tej samej czwórki parametrów co is_denied()
|
||
#set resp.http.X-RateLimit-Limit = "100";
|
||
#set resp.http.X-RateLimit-Window = "10s";
|
||
#set resp.http.X-RateLimit-Remaining = vsthrottle.remaining(client.identity, 100, 10s, 60s);
|
||
#set resp.http.Retry-After = vsthrottle.blocked(client.identity, 100, 10s, 60s);
|
||
|
||
unset resp.http.Via;
|
||
unset resp.http.X-Varnish;
|
||
#unset resp.http.Age;
|
||
unset resp.http.Server;
|
||
}
|