Skip to content

Instantly share code, notes, and snippets.

@thyarles
Forked from danielpotthast/default.vcl
Created May 17, 2023 20:15
Show Gist options
  • Save thyarles/628941792df273f13b4725bf944325e5 to your computer and use it in GitHub Desktop.
Save thyarles/628941792df273f13b4725bf944325e5 to your computer and use it in GitHub Desktop.
Varnish Konfiguration
vcl 4.0;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
.connect_timeout = 600s;
.first_byte_timeout = 600s;
.between_bytes_timeout = 600s;
}
# Only allow purging from specific IPs
acl purge {
"localhost";
"127.0.0.1";
}
sub vcl_recv {
# Normalize the header, remove the port (in case you're testing this on various TCP ports)
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
unset req.http.proxy;
# Allow purging
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "This IP is not allowed to send PURGE requests."));
}
ban("req.http.host == " + req.http.host + " && req.url ~ " + req.url);
return (purge);
}
# Only deal with "normal" types
if (req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "PATCH" &&
req.method != "DELETE") {
/* Non-RFC2616 or CONNECT which is weird. */
return (pipe);
}
# Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
if (req.http.Upgrade ~ "(?i)websocket") {
return (pipe);
}
# Only cache GET or HEAD requests. This makes sure the POST requests are always passed.
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Handle compression correctly. Different browsers send different
# "Accept-Encoding" headers, even though they mostly support the same
# compression mechanisms. By consolidating compression headers into
# a consistent format, we reduce the cache size and get more hits.
# @see: http:// varnish.projects.linpro.no/wiki/FAQ/Compression
if (req.http.Accept-Encoding) {
if (req.http.Accept-Encoding ~ "gzip") {
# If the browser supports it, we'll use gzip.
set req.http.Accept-Encoding = "gzip";
}
else if (req.http.Accept-Encoding ~ "deflate") {
# Next, try deflate if it is supported.
set req.http.Accept-Encoding = "deflate";
}
else {
# Unknown algorithm. Remove it and send unencoded.
unset req.http.Accept-Encoding;
}
}
# Admin users always miss the cache
if (req.url ~ "^/wp-(login|admin)" ||
req.url ~ "preview=true" ||
req.http.Cookie ~ "wordpress_logged_in_") {
return (pass);
}
# Remove cookies set by Google Analytics, Universial Analytics or Tag-Manager
if (req.http.Cookie) {
# Google Analytics (__utmA)
set req.http.Cookie = regsuball(req.http.Cookie,
"(^|; ) *__utm.=[^;]+;? *", "\1");
# Universial Analytics (_ga or _gat_UA-*)
set req.http.Cookie = regsuball(req.http.Cookie,
"(^|; ) *_ga[^=]*=[^;]+;? *", "\1");
# Double Click (_dc_gtm)
set req.http.Cookie = regsuball(req.http.Cookie,
"(^|; ) *_dc_[^=]+=[^;]+;? *", "\1");
if (req.http.Cookie == "") {
unset req.http.Cookie;
}
}
# Send Surrogate-Capability headers to announce ESI support to backend
set req.http.Surrogate-Capability = "key=ESI/1.0";
# always pass through POST requests and those with basic auth
if (req.http.Authorization || req.method == "POST") {
return (pass);
}
# Do not cache these paths
if (req.url ~ "^/wp-cron\.php$" ||
req.url ~ "^/xmlrpc\.php$" ||
req.url ~ "^/wp-admin/.*$" ||
req.url ~ "^/wp-includes/.*$" ||
req.url ~ "\?s=") {
return (pass);
}
if (req.http.Cache-Control ~ "(?i)no-cache") {
if (client.ip ~ purge) {
# Ignore requests via proxy caches and badly behaved crawlers
# like msnbot that send no-cache with every request.
if (! (req.http.Via || req.http.User-Agent ~ "(?i)bot" || req.http.X-Purge)) {
#set req.hash_always_miss = true; # Doesn't seems to refresh the object in the cache
return(purge); # Couple this with restart in vcl_purge and X-Purge header to avoid loops
}
}
}
# Large static files are delivered directly to the end-user without
# waiting for Varnish to fully read the file first.
# Varnish 4 fully supports Streaming, so set do_stream in vcl_backend_response()
if (req.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
unset req.http.Cookie;
return (hash);
}
# By ignoring any other cookies, it is now ok to get a page
unset req.http.Cookie;
return (hash);
}
sub vcl_pipe {
# Called upon entering pipe mode.
# In this mode, the request is passed on to the backend, and any further data from both the client
# and backend is passed on unaltered until either end closes the connection. Basically, Varnish will
# degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode,
# no other VCL subroutine will ever get called after vcl_pipe.
# Note that only the first request to the backend will have
# X-Forwarded-For set. If you use X-Forwarded-For and want to
# have it set for all requests, make sure to have:
# set bereq.http.connection = "close";
# here. It is not set by default as it might break some broken web
# applications, like IIS with NTLM authentication.
# set bereq.http.Connection = "Close";
# Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
if (req.http.upgrade) {
set bereq.http.upgrade = req.http.upgrade;
}
return (pipe);
}
sub vcl_hash {
if(req.http.X-brotli == "true") {
hash_data("brotli");
}
if (req.http.X-Forwarded-Proto) {
hash_data(req.http.X-Forwarded-Proto);
}
}
sub vcl_hit {
# Called when a cache lookup is successful.
if (obj.ttl + 10s > 0s) {
// A pure unadulterated hit, deliver it
return (deliver);
}
if (obj.ttl + obj.grace > 0s) {
// Object is in grace, deliver it
// Automatically triggers a background fetch
return (deliver);
}
// fetch & deliver once we get the result
return (miss);
}
sub vcl_miss {
# Called after a cache lookup if the requested document was not found in the cache. Its purpose
# is to decide whether or not to attempt to retrieve the document from the backend, and which
# backend to use.
return (fetch);
}
sub vcl_backend_response {
# remove some headers we never want to see
unset beresp.http.Server;
unset beresp.http.X-Powered-By;
# Pause ESI request and remove Surrogate-Control header
if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
unset beresp.http.Surrogate-Control;
set beresp.do_esi = true;
}
if (bereq.http.X-brotli == "true") {
set bereq.http.Accept-Encoding = "br";
unset bereq.http.X-brotli;
}
# Large static files are delivered directly to the end-user without
# waiting for Varnish to fully read the file first.
# Varnish 4 fully supports Streaming, so use streaming here to avoid locking.
if (bereq.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
unset beresp.http.set-cookie;
set beresp.do_stream = true; # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects
}
// Set grace time
set beresp.grace = 3m;
# don't cache if nocache header is set
if (beresp.http.cache-control ~ "no-cache") {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# only cache status ok, 301 or 302
if ( beresp.status != 200 && beresp.status != 301 && beresp.status != 302 ) {
set beresp.uncacheable = true;
set beresp.ttl = 120s;
return (deliver);
}
# If our backend returns 5xx status this will reset the grace time
# set in vcl_recv so that cached content will be served and
# the unhealthy backend will not be hammered by requests
if (beresp.status == 500 || beresp.status == 503) {
set beresp.grace = 60s;
return (retry);
}
# GZip the cached content if possible
if (beresp.http.content-type ~ "text") {
set beresp.do_gzip = true;
}
# if nothing above matched it is now ok to cache the response
set beresp.ttl = 24h;
return (deliver);
}
sub vcl_deliver {
# remove some headers added by varnish
unset resp.http.X-Powered-By;
unset resp.http.Server;
unset resp.http.X-Drupal-Cache;
unset resp.http.X-Varnish;
unset resp.http.Via;
unset resp.http.Link;
unset resp.http.X-Generator;
if (obj.hits > 0 ) {
set resp.http.X-Cache = "HIT:";
set resp.http.X-Cache = regsub( resp.http.X-Cache, "$", obj.hits );
} else {
set resp.http.X-Cache = "MISS";
}
return (deliver);
}
sub vcl_purge {
# Only handle actual PURGE HTTP methods, everything else is discarded
if (req.method != "PURGE") {
# restart request
set req.http.X-Purge = "Yes";
return(restart);
}
}
sub vcl_synth {
if (resp.status == 720) {
# We use this special error status 720 to force redirects with 301 (permanent) redirects
# To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
set resp.http.Location = resp.reason;
set resp.status = 301;
return (deliver);
} elseif (resp.status == 721) {
# And we use error status 721 to force redirects with a 302 (temporary) redirect
# To use this, call the following from anywhere in vcl_recv: return (synth(720, "http://host/new.html"));
set resp.http.Location = resp.reason;
set resp.status = 302;
return (deliver);
}
return (deliver);
}
sub vcl_fini {
# Called when VCL is discarded only after all requests have exited the VCL.
# Typically used to clean up VMODs.
return (ok);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment