vcl 4.1; import std; # # backend definitions # # no default backend backend default none; backend subdomain { .host = "[service ip]"; .port = "[service port]"; # .connect_timeout = 6s; .first_byte_timeout = 6s; .between_bytes_timeout = 2s; .max_connections = 128; } # # configurations # # call for every start request sub vcl_recv { if(req.http.host ~ "subdomain.domain.com") { set req.backend_hint = subdomain; } # set initial grace period usage status set req.http.grace = "none"; if (req.restarts == 0) { if (req.http.X-Forwarded-For && !req.http.X-Real-IP) { set req.http.X-Real-IP = regsub(req.http.X-Forwarded-For, ".*\b(?!10|127|172)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*", "\1"); }else{ set req.http.X-Forwarded-For = req.http.X-Real-IP; } } if (req.restarts > 0) { set req.hash_always_miss = true; } if (req.http.upgrade ~ "(?i)websocket") { return (pipe); } # non-RFC2616 or CONNECT which is weird. if (req.method != "GET" && req.method != "HEAD" && req.method != "PUT" && req.method != "POST" && req.method != "TRACE" && req.method != "OPTIONS" && req.method != "DELETE") { return (pipe); } # we only deal with GET and HEAD by default if (req.method != "GET" && req.method != "HEAD") { return (pass); } if (req.url ~ "^/api($|/.*)" || req.url ~ "^/admin($|/.*)") { return (pass); } return (hash); } sub vcl_backend_response { set beresp.grace = 60m; set beresp.ttl = 5s; if (bereq.url ~ "^/static/") { set beresp.ttl = 1d; } # keep the response in cache for 4 hours if the response has # validating headers. if (beresp.http.ETag || beresp.http.Last-Modified) { set beresp.keep = 4h; } if (bereq.url ~ "\.js$" || beresp.http.content-type ~ "text") { set beresp.do_gzip = true; } # cache only successfully responses and 404s if (beresp.status != 200 && beresp.status != 404) { set beresp.ttl = 0s; set beresp.uncacheable = true; return (deliver); } elsif (beresp.http.Cache-Control ~ "private") { set beresp.uncacheable = true; set beresp.ttl = 86400s; return (deliver); } # validate if we need to cache it and prevent from setting cookie if (beresp.ttl > 0s && (bereq.method == "GET" || bereq.method == "HEAD")) { unset beresp.http.set-cookie; } # if page is not cacheable then bypass varnish for 2 minutes as Hit-For-Pass if (beresp.ttl <= 0s || beresp.http.Surrogate-control ~ "no-store" || (!beresp.http.Surrogate-Control && beresp.http.Cache-Control ~ "no-cache|no-store") || beresp.http.Vary == "*") { # Mark as Hit-For-Pass for the next 2 minutes set beresp.ttl = 120s; set beresp.uncacheable = true; } return (deliver); } # called is page's hash found (= page already cached) sub vcl_hit { if (obj.ttl >= 0s) { return (deliver); } if (std.healthy(req.backend_hint)) { if (obj.ttl + 300s > 0s) { # hit after TTL expiration, but within grace period set req.http.grace = "normal (healthy server)"; return (deliver); } else { # hit after TTL and grace expiration return (restart); } } else { # server is not healthy, retrieve from cache set req.http.grace = "unlimited (unhealthy server)"; return (deliver); } return (restart); } # called at every response end (cached or not) sub vcl_deliver { if (obj.hits > 0) { set resp.http.V-Cache = "HIT"; } else { set resp.http.V-Cache = "MISS"; } set resp.http.V-Cache-Hits = obj.hits; return (deliver); } sub vcl_pipe { if (req.http.upgrade) { set bereq.http.upgrade = req.http.upgrade; set bereq.http.connection = req.http.connection; } }