Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #vcl 4.0;
- #Based on: #https://github.com/mattiasgeniar/varnish-4.0-configuration-#templates/blob/master/default.vcl
- import std;
- import directors;
- #BACKEND_SERVERS**
- #Called when VCL is loaded, before any requests pass through it.
- #Typically used to initialize VMODs.
- #BACKEND_DIRECTORS**
- #Called when VCL is loaded, before any requests pass through it.
- #Typically used to initialize VMODs.
- sub vcl_init {
- }
- sub vcl_pass {
- return (pass);
- }
- #SET THE ALLOWED IP OF PURGE REQUESTS
- ###########################################################
- acl purge {
- "localhost";
- "127.0.0.1";
- "Web.Server.IP";
- }
- #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
- #Normalize the header, remove the port (in case you're testing this on various TCP ports)
- sub vcl_recv {
- set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
- #remove HTTPOXY CGI vulnerability
- unset req.http.proxy;
- #Some generic cookie manipulation, useful for all templates that follow
- #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, "_gat=[^;]+(; )?", "");
- 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 DoubleClick offensive cookies
- set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", "");
- #Remove the Quant Capital cookies (added by some plugin, all __qca)
- set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", "");
- #Remove the AddThis cookies
- set req.http.Cookie = regsuball(req.http.Cookie, "__atuv.=[^;]+(; )?", "");
- #Remove a ";" prefix in the cookie if present
- set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
- #Are there cookies left with only spaces or that are empty?
- if (req.http.cookie ~ "^\s*$") {
- unset req.http.cookie;
- }
- #Remove all cookies for static files
- #A valid discussion could be held on this line: do you really need to cache static files that don't #cause load? Only if you have memory left.
- #Sure, there's disk I/O, but chances are your OS will already have these files in their buffers ##(thus memory).
- #Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
- if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
- unset req.http.Cookie;
- return (hash);
- }
- #remove extraneous host ports
- set req.http.host = regsub(req.http.Host, ":[0-9]+", "");
- #set realIP by trimming CloudFlare IP which will be used for various checks
- set req.http.X-Actual-IP = regsub(req.http.X-Forwarded-For, "[, ].*$", "");
- #Enable smart refreshing
- if (req.http.Cache-Control ~ "no-cache" && client.ip ~ purge) {
- set req.hash_always_miss = true;
- }
- #Unset cloudflare cookies
- #Remove has_js and CloudFlare/Google Analytics __* cookies.
- set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
- #Remove a ";" prefix, if present.
- set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
- #For Testing: If you want to test with Varnish passing (not caching) uncomment
- #return( pass );
- #FORWARD THE IP OF THE REQUEST
- if (req.restarts == 0) {
- if (req.http.x-forwarded-for) {
- set req.http.X-Forwarded-For =
- req.http.X-Forwarded-For + ", " + client.ip;
- } else {
- set req.http.X-Forwarded-For = client.ip;
- }
- }
- set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
- #Remove the proxy header (see https://httpoxy.org/#mitigate-varnish)
- unset req.http.proxy;
- #Normalize the query arguments
- set req.url = std.querysort(req.url);
- #Non-RFC2616 or CONNECT which is weird.
- #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") {
- 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);
- }
- #Not cacheable by default
- if (req.http.Authorization) {
- return (pass);
- }
- #For static file access, strip all querystring parameters.
- if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpe?g|js|less|mp[34]|otf|pdf|png|rar|rtf|swf|tar|tgz|ttf|txt|wav|webm|woff|xml|zip)(\?.*)?$") {
- unset req.http.Cookie;
- set req.url = querystring.remove(req.url);
- return (hash);
- }
- #Whitelist query string parameters for WordPress.
- set req.url = querystring.filter_except(req.url,
- "sort" + querystring.filtersep() +
- "q" + querystring.filtersep() +
- "dom" + querystring.filtersep() +
- "dedupe_hl" + querystring.filtersep() +
- "filter" + querystring.filtersep() +
- "attachment" + querystring.filtersep() +
- "attachment_id" + querystring.filtersep() +
- "author" + querystring.filtersep() +
- "author_name" + querystring.filtersep() +
- "cat" + querystring.filtersep() +
- "calendar" + querystring.filtersep() +
- "category_name" + querystring.filtersep() +
- "comments_popup" + querystring.filtersep() +
- "cpage" + querystring.filtersep() +
- "day" + querystring.filtersep() +
- "dedupe_hl" + querystring.filtersep() +
- "dom" + querystring.filtersep() +
- "error" + querystring.filtersep() +
- "exact" + querystring.filtersep() +
- "exclude" + querystring.filtersep() +
- "feed" + querystring.filtersep() +
- "hour" + querystring.filtersep() +
- "m" + querystring.filtersep() +
- "minute" + querystring.filtersep() +
- "monthnum" + querystring.filtersep() +
- "more" + querystring.filtersep() +
- "name" + querystring.filtersep() +
- "order" + querystring.filtersep() +
- "orderby" + querystring.filtersep() +
- "p" + querystring.filtersep() +
- "page_id" + querystring.filtersep() +
- "page" + querystring.filtersep() +
- "paged" + querystring.filtersep() +
- "pagename" + querystring.filtersep() +
- "pb" + querystring.filtersep() +
- "post_type" + querystring.filtersep() +
- "posts" + querystring.filtersep() +
- "preview" + querystring.filtersep() +
- "q" + querystring.filtersep() +
- "robots" + querystring.filtersep() +
- "s" + querystring.filtersep() +
- "search" + querystring.filtersep() +
- "second" + querystring.filtersep() +
- "sentence" + querystring.filtersep() +
- "sort" + querystring.filtersep() +
- "static" + querystring.filtersep() +
- "subpost" + querystring.filtersep() +
- "subpost_id" + querystring.filtersep() +
- "taxonomy" + querystring.filtersep() +
- "tag" + querystring.filtersep() +
- "tb" + querystring.filtersep() +
- "tag_id" + querystring.filtersep() +
- "term" + querystring.filtersep() +
- "tb" + querystring.filtersep() +
- "url" + querystring.filtersep() +
- "w" + querystring.filtersep() +
- "withcomments" + querystring.filtersep() +
- "withoutcomments" + querystring.filtersep() +
- "year");
- #Sort the querystring parameters, so different orders of the same produce a single cache #object.
- if (req.url ~ "\?") {
- set req.url = querystring.sort(req.url);
- }
- #Keep WordPress cookies for preview
- #drop all cookies.
- if (req.http.cookie) {
- if (req.url ~ "preview") {
- return (pass);
- } else {
- unset req.http.cookie;
- }
- return (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 {
- if (req.http.cookie) {
- hash_data(req.http.cookie);
- }
- return(lookup);
- }
- #fix flexible ssl css
- if (req.http.x-forwarded-proto) {
- hash_data(req.http.x-forwarded-proto);
- }
- if (req.http.host) {
- hash_data(req.http.host);
- } else {
- hash_data(server.ip);
- set req.http.ccsuri = regsub(req.url, "\?(.*)", "");
- hash_data(req.http.ccsuri);
- }
- return (hash);
- }
- #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.
- #The data on which the hashing will take place
- #Called when a cache lookup is successful.
- #A pure unadultered hit, deliver it
- sub vcl_hit {
- if (obj.ttl >= 0s) {
- return (deliver);
- }
- if (req.request == "PURGE") {
- purge;
- error 200 "Purged.";
- }
- return (deliver);
- #https://www.varnish-cache.org/docs/trunk/users-guide/vcl-grace.html
- #When several clients are requesting the same page Varnish will send one request to the #backend and #place the others on hold while fetching one copy from the backend. In some #products this is called #request coalescing and Varnish does this automatically.
- #If you are serving thousands of hits per second the queue of waiting requests can get huge. #There #are two potential problems - one is a thundering herd problem - suddenly releasing a #thousand #threads to serve content might send the load sky high. Secondly - nobody likes to #wait. To deal #with this we can instruct Varnish to keep the objects in cache beyond their TTL #and to serve the #waiting requests somewhat stale content.
- #Object is in grace, deliver it
- #Automatically triggers a background fetch
- if (obj.ttl + obj.grace > 0s) {
- return (deliver);
- }
- #fetch & deliver once we get the result
- return (fetch);
- }
- if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
- return (deliver);
- } else {
- return (miss);
- }
- #We have no fresh fish. Lets look at the stale ones.
- #Backend is healthy. Limit age to 10s.
- set req.http.grace = "normal(limited)";
- #No candidate for grace. Fetch a fresh object.
- #backend is sick - use full grace
- #no graced object.
- if (std.healthy(req.backend_hint)) {
- if (obj.ttl + 10s > 0s) {
- return (deliver);
- } else {
- return (fetch);
- }
- } else {
- if (obj.ttl + obj.grace > 0s) {
- set req.http.grace = "full";
- return (deliver);
- } else {
- return (fetch);
- }
- }
- #fetch & deliver once we get the result
- #Dead code, keep as a safeguard
- return (fetch);
- }
- #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.
- sub vcl_miss {
- return (fetch);
- }
- #Handle the HTTP request coming from our backend
- #Called after the response headers has been successfully retrieved from the backend.
- #Pause ESI request and remove Surrogate-Control header
- sub vcl_backend_response {
- if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
- unset beresp.http.Surrogate-Control;
- set beresp.do_esi = true;
- }
- if (!(bereq.url ~ "wp-(login|admin)|cart|my-account|wc-api|resetpass") &&
- !bereq.http.cookie ~ "wordpress_logged_in|woocommerce_items_in_cart|resetpass" && !beresp.status == 302) {
- unset beresp.http.set-cookie;
- set beresp.ttl = 1w;
- set beresp.grace = 1d;
- }
- #Enable cache for all static files
- #The same argument as the static caches from above: monitor your cache size, if you get data nuked #out of it, consider giving up the static file cache.
- #Before you blindly enable this, have a read here: https://ma.ttias.be/stop-caching-static-files/
- if (bereq.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|otf|ogg|ogm|opus|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
- unset beresp.http.set-cookie;
- }
- #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;
- return (hash);
- }
- #Don't cache 50x responses
- if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
- return (abandon);
- }
- #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 finetuning 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]+", "");
- }
- #Set 2min cache if unset for static files
- if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
- set beresp.ttl = 120s;
- set beresp.uncacheable = true;
- return (deliver);
- }
- #Allow stale content, in case the backend goes down.
- #make Varnish keep all objects for 6 hours beyond their TTL
- set beresp.grace = 6h;
- return (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.
- #Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
- sub vcl_deliver {
- if (obj.hits > 0) {
- set resp.http.X-Cache = "HIT";
- } else {
- set resp.http.X-Cache = "MISS";
- return (deliver);
- }
- #Please note that obj.hits behaviour changed in 4.0, now it counts per objecthead, not per #object
- #and obj.hits may not be reset in some cases where bans are in use. See bug 1492 for #details.
- #So take hits with a grain of salt
- set resp.http.X-Cache-Hits = obj.hits;
- if (req.http.sticky) {
- if(!resp.http.Set-Cookie) {
- set resp.http.Set-Cookie = "";
- }
- set resp.http.Set-Cookie = "ccsvs=ccs" + req.http.sticky + "; Expires=" + (now + 10d) + ";" + resp.http.Set-Cookie;
- }
- #Remove some headers: PHP version
- unset resp.http.X-Powered-By;
- #Remove some headers: Apache version & OS
- 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;
- return (deliver);
- }
- #Only handle actual PURGE HTTP methods, everything else is discarded
- #restart request
- sub vcl_purge {
- if (req.method != "PURGE") {
- set req.http.X-Purge = "Yes";
- return(restart);
- }
- }
- #You may need to add other locations like membership sites here, 302 is necessary if you use #redirect to cart
- ###########################################################
- if (!(req.url ~ "wp-(login|admin)|wc-api|resetpass|cart|checkout|my-account|\?wc-ajax=get_refreshed_fragments") && !req.http.cookie ~ "wordpress_logged_in|resetpass" && !beresp.status == 302) {
- unset beresp.http.set-cookie;
- set beresp.ttl = 1w;
- set beresp.grace =3d;
- }
- if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
- set beresp.ttl = 120 s;
- return (hit_for_pass);
- }
- return (deliver);
- }
- #We use this special error status 8201 for clear cache messages
- #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"));
- #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"));
- sub vcl_synth {
- if (resp.status == 720) {
- set resp.http.Location = resp.reason;
- set resp.status = 301;
- return (deliver);
- } elseif (resp.status == 721) {
- set resp.http.Location = resp.reason;
- set resp.status = 302;
- return (deliver);
- }
- #Called when VCL is discarded only after all requests have exited the VCL.
- #Typically used to clean up VMODs.
- sub vcl_fini {
- return (ok);
- }
- #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:
- #here. It is not set by default as it might break some broken web
- #applications, like IIS with NTLM authentication.
- #Implementing websocket support #(https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-#websockets.html)
- sub vcl_pipe {
- set bereq.http.Connection = "Close";
- set bereq.http.connection = "close";
- if (req.http.upgrade) {
- set bereq.http.upgrade = req.http.upgrade;
- }
- return (pipe);
- }
Advertisement
Add Comment
Please, Sign In to add comment