Last active
February 7, 2021 14:33
-
-
Save eksiscloud/935a1af43c4586f0868a00cabcf7df6f to your computer and use it in GitHub Desktop.
default.vcl for Varnish (Wordpress, Woocommerce, LearnDash)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Jakke Lehtonen | |
## by several sources | |
## Varnish default.vcl for Wordpress, Woocommerce, LearnDash, PMPro, bbPress etc. | |
## Just for one domain and one server, but can use for several servers AFAIK | |
# | |
# Lets's start caching | |
# | |
# Marker to tell the VCL compiler that this VCL has been adapted to the 4.0 format. | |
vcl 4.0; | |
# import directors; # Load the vmod_directors | |
import std; # Load the std, not STD for god sake | |
# Default backend definition. Set this to point to your content server. | |
backend default { # use your servers instead default if you have more than just one | |
.host = "127.0.0.1"; # IP or Hostname of backend | |
.port = "8080"; # Apache or whatever is listening | |
.max_connections = 800; # That's it enough | |
.first_byte_timeout = 300s; # How long to wait before we receive a first byte from our backend? | |
.connect_timeout = 300s; # How long to wait for a backend connection? | |
.between_bytes_timeout = 300s; # How long to wait between bytes received from our backend? | |
.probe = { # Is the backend healthy? | |
.url = "/index.html"; # Checking out root | |
.timeout = 2s; # How long should wait for respons; DO is slow, so I can't use 40ms | |
.interval = 5s; # How often shall we poll | |
.window = 4; # Out of this many tries... | |
.threshold = 3; # ...this many must be under timeout, otherwise giving gracetime | |
} | |
} | |
# Only allow purging from specific IPs | |
acl purge { | |
"localhost"; | |
"127.0.0.1"; | |
"1p-address"; # eth0 | |
} | |
#################### vcl_init ################## | |
# Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs. | |
# You have to define server at backend definition too. | |
# If using default, keep this commented | |
sub vcl_init { | |
#new cluster1 = directors.round_robin(); | |
#cluster1.add_backend(server1); | |
#cluster1.add_backend(server2); | |
} | |
##################### vcl_recv ################# | |
# vcl_recv function is used when a request is send by a HTTP client (Browser) | |
# Called at the beginning of a request, after the complete request has been received and parsed. | |
# Its purpose is to decide whether or not to serve the request, how to do it, and, if applicable, | |
# which backend to use. | |
# Also used to modify the request | |
sub vcl_recv { | |
# Your lifeline: Turn OFF cache | |
# For caching keep this commented | |
# return(pass); | |
# drops amp | |
if (req.url ~ "/amp/") { | |
return (pass); | |
} | |
# Fix Wordpress visual editor issues, must be the first one to work | |
if (req.url ~ "/wp-(login|admin|comments-post.php|cron)" || req.url ~ "preview=true" || req.url ~ "xmlrpc.php") { | |
return (pass); | |
} | |
# send all traffic to the vdir director | |
#set req.backend_hint = cluster1.backend(); | |
# 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]+", ""); | |
# Normalize hostname to avoid double caching | |
set req.http.host = regsub(req.http.host, | |
"^example\.com$", "www.example.com"); | |
# Remove the proxy header (see https://httpoxy.org/#mitigate-varnish) | |
unset req.http.proxy; | |
# Save Origin in a custom header | |
set req.http.X-Saved-Origin = req.http.Origin; | |
# Remove Origin from the request so that backend doesn’t add CORS headers. | |
unset req.http.Origin; | |
# Allow purging from ACL | |
if (req.method == "PURGE") { | |
# If not allowed then a error 405 is returned | |
if (!client.ip ~ purge) { | |
return(synth(405, "This IP is not allowed to send PURGE requests.")); | |
} | |
# If allowed, do a cache_lookup -> vlc_hit() or vlc_miss() | |
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. */ | |
# Why send the packet upstream, while the visitor is using a non-valid HTTP method? */ | |
return (synth(404, "Non-valid HTTP method!")); | |
} | |
# 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); | |
} | |
# Some generic URL manipulation, useful for all templates that follow | |
# First remove URL parameters used to track effectiveness of online marketing campaigns | |
if (req.url ~ "(\?|&)(utm_[a-z]+|gclid|cx|ie|cof|siteurl|fbclid)=") { | |
set req.url = regsuball(req.url, "(utm_[a-z]+|gclid|cx|ie|cof|siteurl|fbclid)=[-_A-z0-9+()%.]+&?", ""); | |
set req.url = regsub(req.url, "[?|&]+$", ""); | |
} | |
# Strip hash, server doesn't need it. | |
if (req.url ~ "\#") { | |
set req.url = regsub(req.url, "\#.*$", ""); | |
} | |
# Strip a trailing ? if it exists | |
if (req.url ~ "\?$") { | |
set req.url = regsub(req.url, "\?$", ""); | |
} | |
# Enable smart refreshing | |
# Remember your header Cache-Control must be set something else than no-cache | |
# Otherwise everythiong will miss | |
if (req.http.Cache-Control ~ "no-cache" && client.ip ~ purge) { | |
set req.hash_always_miss = true; | |
} | |
# If you are using SSL and it doesn't forward http to https when URL is given without protocol | |
if ( req.http.X-Forwarded-Proto !~ "(?i)https" ) { | |
set req.http.x-Redir-Url = "https://" + req.http.host + req.url; | |
return ( synth( 750 )); | |
} | |
# Setting http headers for backend | |
set req.http.X-Forwarded-For = client.ip; | |
set req.http.X-Forwarded-Proto = "https"; | |
# Unset headers that might cause us to cache duplicate infos | |
unset req.http.Accept-Language; | |
unset req.http.User-Agent; | |
### Do not Cache: special cases ### | |
# Do not cache AJAX requests. | |
if (req.http.X-Requested-With == "XMLHttpRequest") { | |
return(pass); | |
} | |
# Post requests will not be cached | |
if (req.http.Authorization || req.method == "POST") { | |
return (pass); | |
} | |
## Wordpress, Woocommerce, etc ## | |
# Don't cache post and edit pages | |
if (req.url ~ "/wp-(post.php|edit.php)") { | |
return(pass); | |
} | |
# Don't cache logged-in user and cart | |
if ( req.http.cookie ~ "wordpress_logged_in|resetpass" ) { | |
return( pass ); | |
} | |
#fixed non AJAX cart problem | |
if (req.http.cookie ~ "woocommerce_(cart|session)|wp_woocommerce_session") { | |
#return(lookup); # not worked for me, return can¨t be lookup. Trying pass instead | |
return(pass); | |
} | |
#Hit everything else, you propably don't have all this | |
if (!req.url ~ "/wp-(login|admin|cron)|logout|lost-password|wc-api|cart|my-account|checkout|addons|administrator|member|course|product|resetpass") { | |
unset req.http.cookie; | |
} | |
# This is for phpmyadmin | |
if (req.http.Host == "pmadomain.com") { | |
return (pass); | |
} | |
# Pass the Woocommerce related | |
if (req.url ~ "/(cart|my-account|checkout|wc-api|addons|logout|lost-password|administrator|\?wc-ajax=get_refreshed_fragments)") { | |
return (pass); | |
} | |
# Pass the Store related | |
if (req.url ~ "/(store|product)") { | |
return (pass); | |
} | |
# Page of contact form | |
if (req.url ~ "/(contact)") { | |
return (pass); | |
} | |
# Pass Let's Encrypt | |
if (req.url ~ "^/\.well-known/acme-challenge/") { | |
return (pass); | |
} | |
# Did not cache the RSS feed | |
if (req.url ~ "/feed") { | |
return (pass); | |
} | |
# Must Use plugins I reckon | |
if (req.url ~ "/mu-.*") { | |
return (pass); | |
} | |
# Paid memberships Pro | |
if ( req.url ~ "(membership-account|membership-account|membership-checkout|#login-panel)" ) { | |
return (pass); | |
} | |
# phpBB Logged in users and ACP | |
if ( req.url ~ "(/forumPM/adm/|ucp.php?mode=|\?mode=edit)" ) { | |
return (pass); | |
} | |
# Pass through the WooCommerce API | |
if (req.url ~ "\?wc-api=" ) { | |
return (pass); | |
} | |
# Pass through the WooCommerce add to cart | |
if (req.url ~ "\?add-to-cart=" ) { | |
return (pass); | |
} | |
if (req.url ~ "\?wc-ajax=" ) { | |
return (pass); | |
} | |
## Cookies | |
# Remove the "has_js" cookie | |
set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", ""); | |
# Remove any Google Analytics based cookies | |
set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "_gali=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "_gid=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", ""); | |
# Remove the Quant Capital cookies (added by some plugin, all __qca) | |
set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", ""); | |
# Remove the wp-settings-1 cookie | |
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-1=[^;]+(; )?", ""); | |
# Remove the wp-settings-time-1 cookie | |
set req.http.Cookie = regsuball(req.http.Cookie, "wp-settings-time-1=[^;]+(; )?", ""); | |
# Remove the wp test cookie | |
set req.http.Cookie = regsuball(req.http.Cookie, "wordpress_test_cookie=[^;]+(; )?", ""); | |
# Remove the phpBB cookie. This will help us cache bots and anonymous users. | |
#set req.http.Cookie = regsuball(req.http.Cookie, "style_cookie=[^;]+(; )?", ""); | |
#set req.http.Cookie = regsuball(req.http.Cookie, "phpbb3_psyfx_track=[^;]+(; )?", ""); | |
# Remove the PHPSESSID in members area cookie | |
set req.http.Cookie = regsuball(req.http.Cookie, "PHPSESSID=[^;]+(; )?", ""); | |
# Remove DoubleClick offensive cookies | |
set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", ""); | |
# Remove the AddThis cookies | |
set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", ""); | |
# Remove Woocommerce cookies, all three | |
set req.http.Cookie = regsuball(req.http.Cookie, "woocommerce_cart_hash=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "woocommerce_items_in_cart=[^;]+(; )?", ""); | |
set req.http.Cookie = regsuball(req.http.Cookie, "wp_woocommerce_session_=[^;]+(; )?", ""); | |
# Remove PMPro | |
set req.http.Cookie = regsuball(req.http.Cookie, "pmpro_visit=[^;]+(; )?", ""); | |
# Jetpack by Automattic, are this really needed? I don't think so | |
#set req.http.Cookie = regsuball(req.http.Cookie, "tk_or=[^;]+(; )?", ""); | |
#set req.http.Cookie = regsuball(req.http.Cookie, "tk_r3d=[^;]+(; )?", ""); | |
#set req.http.Cookie = regsuball(req.http.Cookie, "tk_lr=[^;]+(; )?", ""); | |
#set req.http.Cookie = regsuball(req.http.Cookie, "tk_ni=[^;]+(; )?", ""); | |
#set req.http.Cookie = regsuball(req.http.Cookie, "tk_ai=[^;]+(; )?", ""); | |
#set req.http.Cookie = regsuball(req.http.Cookie, "tk_qs=[^;]+(; )?", ""); | |
# Facebook Ads, same here, useless | |
#set req.http.Cookie = regsuball(req.http.Cookie, "_fbp=[^;]+(; )?", ""); | |
# _wp_session | |
set req.http.Cookie = regsuball(req.http.Cookie, "_wp_session=[^;]+(; )?", ""); | |
# Check the cookies for wordpress-comment items I reckon | |
if (req.http.Cookie ~ "comment_") { | |
return (pass); | |
} | |
# Do not pass other cookies | |
if (!req.http.cookie) { | |
unset req.http.cookie; | |
} | |
# Are there cookies left with only spaces or that are empty? | |
if (req.http.cookie ~ "^ *$") { | |
unset req.http.cookie; | |
} | |
## Back to more general things | |
# Normalize the query arguments. | |
# Note: Placing this above the "do not cache" section breaks some WP theme elements and admin functionality. | |
set req.url = std.querysort(req.url); | |
# 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 see do_stream in vcl_backend_response() to witness the glory. | |
if (req.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|wav|zip|bz2|xz|7z|avi|mov|ogm|mpe?g|mk[av])(\?.*)?$") { | |
unset req.http.Cookie; | |
return (hash); | |
} | |
# Cache all static files by Removing all cookies for static files | |
# Remember, do you really need to cache static files that don't cause load? Only if you have memory left. | |
# Here I decide to cache these static files. For me, most of them are handled by the CDN anyway. | |
if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|ico|jpeg|jpg|js|less|pdf|png|rtf|swf|txt|woff|xml)(\?.*)?$") { | |
unset req.http.Cookie; | |
return (hash); | |
} | |
# Normalize Accept-Encoding header and compression | |
# https://www.varnish-cache.org/docs/3.0/tutorial/vary.html | |
if (req.http.Accept-Encoding) { | |
# Do no compress compressed files... | |
if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") { | |
unset req.http.Accept-Encoding; | |
} elsif (req.http.Accept-Encoding ~ "gzip") { | |
set req.http.Accept-Encoding = "gzip"; | |
} elsif (req.http.Accept-Encoding ~ "deflate") { | |
set req.http.Accept-Encoding = "deflate"; | |
} else { | |
unset req.http.Accept-Encoding; | |
} | |
} | |
# Cache all static files by Removing all cookies for static files. | |
if (req.url ~ "^[^?]*\.(html|htm|gz)(\?.*)?$") { | |
unset req.http.Cookie; | |
return (hash); | |
} | |
# Do not cache HTTP authentication and HTTP Cookie | |
if (req.http.Authorization || req.http.Cookie) { | |
return (pass); | |
} | |
# Send Surrogate-Capability headers to announce ESI support to backend | |
set req.http.Surrogate-Capability = "key=ESI/1.0"; | |
# Cache all others requests if they reach this point | |
return (hash); | |
} | |
################### 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. | |
sub vcl_pipe { | |
# 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); | |
} | |
################### vcl_pass ####################### | |
# Called upon entering pass mode. In this mode, the request is passed on to the backend, and the | |
# backend's response is passed on to the client, but is not entered into the cache. Subsequent | |
# requests submitted over the same client connection are handled normally. | |
sub vcl_pass { | |
#return (pass); | |
} | |
################### vcl_hash ####################### | |
# The data on which the hashing will take place | |
# Called after vcl_recv to create a hash value for the request. This is used as a key | |
# to look up the object in Varnish. | |
sub vcl_hash { | |
hash_data(req.url); | |
if (req.http.host) { | |
hash_data(req.http.host); | |
} else { | |
hash_data(server.ip); | |
} | |
# hash cookies for requests that have them | |
if (req.http.Cookie) { | |
hash_data(req.http.Cookie); | |
} | |
# If the client supports compression, keep that in a different cache | |
if (req.http.Accept-Encoding) { | |
hash_data(req.http.Accept-Encoding); | |
} | |
return (lookup); | |
#this is to store cache based on PHPSESSID or woocommerce cookie so cart doesn't show 0 | |
if (req.http.cookie) { | |
hash_data(req.http.cookie); | |
} | |
#fix flexible ssl css | |
if (req.http.x-forwarded-proto) { | |
hash_data(req.http.x-forwarded-proto); | |
} | |
} | |
################### vcl_hit ################# | |
# Call if cached | |
# | |
sub vcl_hit { | |
if (obj.ttl >= 0s) { | |
# A pure unadultered hit, deliver it | |
return (deliver); | |
} | |
} | |
################# vcl_miss ##################### | |
# | |
# Called after a cache lookup if the requested document was not found in the cache | |
# | |
sub vcl_miss { | |
return (fetch); | |
} | |
#################### vcl_backend_response ################### | |
# Handle the HTTP request coming from our backend | |
# Called after the response headers has been successfully retrieved from the backend. | |
sub vcl_backend_response { | |
# 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; | |
} | |
# Sometimes, a 301 or 302 redirect formed via Apache's mod_rewrite can mess with the HTTP port that is being passed along. | |
# This often happens with simple rewrite rules in a scenario where Varnish runs on :80 and Apache on :8080 on the same box. | |
# A redirect can then often redirect the end-user to a URL on :8080, where it should be :80. | |
# This may need fine tuning on your setup. | |
# To prevent accidental replace, we only filter the 301/302 redirects for now. | |
if (beresp.status == 301 || beresp.status == 302) { | |
set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", ""); | |
} | |
# fix for empty cart issue | |
if (!(bereq.url ~ "wp-(login|admin)|^cart|^my-account|^checkout|wc-api|resetpass") && | |
!bereq.http.cookie ~ "wordpress_logged_in|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_|resetpass" && | |
!beresp.status == 302 ) { | |
unset beresp.http.set-cookie; | |
set beresp.ttl = 1w; | |
set beresp.grace = 1h; | |
} | |
## Overall TTL | |
## Note: The TTL is designed to be somewhat aggressive here, to keep things in cache. | |
# | |
# Lets get this party started. | |
#Varnish keep 1 year (or when purged), client 24 hour | |
if (beresp.ttl > 0s) { | |
#use this if you want use max-age | |
# Remove Expires from backend, it's not long enough | |
unset beresp.http.expires; | |
# Set the clients TTL on this object | |
set beresp.http.cache-control = "max-age=86400"; | |
# Set how long Varnish will keep it | |
set beresp.ttl = 1y; | |
# marker for vcl_deliver to reset Age | |
set beresp.http.magicmarker = "1"; | |
#or this one, if you want to use expires header | |
# We are using seconds | |
#set beresp.http.x-obj-ttl = beresp.ttl + "s"; | |
} | |
# Allow stale content, in case the backend goes down. | |
# make Varnish keep all objects for x hours beyond their TTL | |
set beresp.grace = 8h; | |
# Enable cache for all static files | |
# Monitor your cache size, if you get data nuked out of it, consider giving up the static file cache. | |
# More reading here: https://ma.ttias.be/stop-caching-static-files/ | |
if (bereq.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|zip)(\?.*)?$") { | |
set beresp.ttl = 365d; # set a TTL for these optional. | |
unset beresp.http.set-cookie; | |
} | |
# Cache all static files by Removing all cookies for static files - Note: These file extensions are generated by WordPress WP Super Cache. | |
if (bereq.url ~ "^[^?]*\.(html|htm|gz)(\?.*)?$") { | |
set beresp.ttl = 365d; # set a TTL for these optional. | |
unset beresp.http.set-cookie; | |
} | |
## Targeted TTL | |
# Members section is very dynamic and uses cookies (see cookie settings in vcl_recv). | |
if (bereq.url ~ "/members/") { | |
set beresp.ttl = 1d; | |
} | |
# My Shop section is fairly static when browsing the catalog, but woocommerce is passed in vcl_recv. | |
if (bereq.url ~ "/store/") { | |
set beresp.ttl = 1d; | |
} | |
# phBB Forum | |
# Note: Cookies are dropped for phpBB in vcl_recv which disables the forums cookies, however, logged in users still get a hash. | |
# I set the anonymous user as a bot in phpBB admin settings. As bots dont use cookies, this gives 99% hit rate. | |
#if (bereq.url ~ "/forumPM/") { | |
#set beresp.ttl = 1h; | |
#} | |
# Long ttl sites | |
#if (bereq.url ~ "(example.com|example2.com)") { | |
# set beresp.ttl = 1w; | |
#} | |
# 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. | |
# I do not stream large files from my server, I use a CDN or dropbox, so I have not tested this. | |
if (bereq.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|wav|zip|bz2|xz|7z|avi|mov|ogm|mpe?g|mk[av])(\?.*)?$") { | |
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 beresp.do_gzip = false; # Don't try to compress it for storage | |
} | |
# don't cache response to posted requests or those with basic auth | |
if ( bereq.method == "POST" || bereq.http.Authorization ) { | |
set beresp.uncacheable = true; | |
set beresp.ttl = 120s; | |
return (deliver); | |
} | |
# Don't cache search results | |
if ( bereq.url ~ "\?s=" ){ | |
set beresp.uncacheable = true; | |
set beresp.ttl = 120s; | |
return (deliver); | |
} | |
# Only cache status ok | |
if ( beresp.status != 200 ) { | |
set beresp.uncacheable = true; | |
set beresp.ttl = 120s; | |
return (deliver); | |
} | |
# Don't cache 50x responses | |
if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) { | |
return (abandon); | |
} | |
# Set 2min cache if unset for static files | |
# if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") { | |
# set beresp.ttl = 120s; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend | |
# set beresp.uncacheable = true; | |
# return (deliver); | |
# } | |
return (deliver); | |
} | |
####################### vcl_deliver ######################## | |
# The routine when we deliver the HTTP request to the user | |
# Last chance to modify headers that are sent to the client | |
# Called before a cached object is delivered to the client. | |
sub vcl_deliver { | |
if (req.http.X-Saved-Origin == "https://www.example.com" | |
|| req.http.X-Saved-Origin == "https://cdn.example.com" | |
|| req.http.X-Saved-Origin == "https://cdn2.example.com") { | |
set resp.http.Access-Control-Allow-Origin = | |
req.http.X-Saved-Origin; | |
} | |
if (resp.http.Vary) { | |
set resp.http.Vary = resp.http.Vary + ",Origin"; | |
} else { | |
set resp.http.Vary = "Origin"; | |
} | |
# HIT & MISS | |
if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed | |
set resp.http.X-Mood = "HIT!"; | |
} else { | |
set resp.http.X-Mood = "MISS..."; | |
} | |
# Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per object | |
set resp.http.X-Cache-Wham = (obj.hits); | |
# If we are on max-age: | |
# Earlier we set 1 year for Varnish and 24 hour for client. Now it will finished | |
if (resp.http.magicmarker) { | |
# Remove the magic marker | |
unset resp.http.magicmarker; | |
# By definition we have a fresh object | |
set resp.http.age = "0"; | |
} | |
# Or if you wanted to use headers instead: | |
# Dynamically set the Expires header on every request from the web. | |
#if (resp.http.x-obj-ttl) { | |
# 1. Calculate and reset the Expires header. (3600s is just a fallback value) | |
#set resp.http.Expires = "" + (now + std.duration(resp.http.x-obj-ttl, 604800s)); | |
# 2. Delete the temporary header from the response. | |
#unset resp.http.x-obj-ttl; | |
#} | |
# Remove some headers: | |
unset resp.http.Server; | |
unset resp.http.X-Powered-By; | |
unset resp.http.X-Drupal-Cache; | |
unset resp.http.X-Varnish; | |
unset resp.http.Age; | |
unset resp.http.Via; | |
unset resp.http.Link; | |
unset resp.http.X-Generator; | |
unset resp.http.X-Mod-Pagespeed; | |
## You know you can set headers here? | |
set resp.http.Server = "WhiteHat v0.1"; | |
set resp.http.X-Powered-by = "Talisker and one drop water"; | |
set resp.http-X-Mood = "some good old blues"; | |
return (deliver); | |
} | |
#################### vcl_purge ################# | |
# | |
# | |
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); | |
} | |
} | |
##################### vcl_synth ##################### | |
# | |
# | |
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); | |
# because of force to https - or something | |
if (resp.status == 750) { | |
set resp.status = 301; | |
set resp.http.Location = req.http.x-Redir-Url; | |
return(deliver); | |
} | |
} | |
####################### vcl_fini ####################### | |
# | |
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