Bypass cache for 4xx & 5xx errors

Bypass cache for 4xx & 5xx errors

# Default backend definition.  Set this to point to your content server.
# all paths relative to varnish option vcl_dir

include "custom.backend.vcl";
include "custom.acl.vcl";

# Handle the HTTP request received by the client
sub vcl_recv {
    # varnish serves stale (but cacheable) objects while retriving object from backend
    if (req.backend.healthy) {
        set req.grace = 30s;
    } else {
        set req.grace = 1h;
    }

    # shortcut for DFind requests
    if (req.url ~ "^/w00tw00t") {
        error 404 "Not Found";
    }

    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;
        }
    }

    # 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]+", "");

    # Allow purging
    if (req.request == "PURGE") {
        if (!client.ip ~ purge) {
            # Not from an allowed IP? Then die with an error.
            error 405 "This IP is not allowed to send PURGE requests.";
        }

        # If you got this stage (and didn't error out above), do a cache-lookup
        # That will force entry into vcl_hit() or vcl_miss() below and purge the actual cache
        return (lookup);
    }

    # Only deal with "normal" types
    if (req.request != "GET" &&
            req.request != "HEAD" &&
            req.request != "PUT" &&
            req.request != "POST" &&
            req.request != "TRACE" &&
            req.request != "OPTIONS" &&
            req.request != "PATCH" &&
            req.request != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }

    if (req.request != "GET" && req.request != "HEAD") {
        # We only deal with GET and HEAD by default
        return (pass);
    }

    # Some generic URL manipulation, useful for all templates that follow
    # First remove the Google Analytics added parameters, useless for our backend
    if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
        set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
        set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
        set req.url = regsub(req.url, "\?&", "?");
        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, "\?$", "");
    }

    # This is an example to redirect with a 301/302 HTTP status code from within Varnish
    # if (req.http.Host ~ "secure.mysite.tld") {
    #   # We may want to force our users from the secure site to the HTTPs version?
    #   error 720 "https://secure.mysite.tld";
    #   # If you want to keep the URLs intact, this also works:
    #   error 720 "https://" + req.http.Host + req.url;
    # }
    #
    # Or to force a 302 temporary redirect, use error 721
    # if (req.http.Host ~ "temp.mysite.tld") {
    #   # Temporary redirect
    #   error 721 "http://mysite.tld/temp";
    # }
    #

    # 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 Satallite cookies
    set req.http.Cookie = regsuball(req.http.Cookie, "__gaid=[^;]+(; )?", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "_sdsat_[^=]+=[^;]+(; )?", "");

    # 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, "utmctr=[^;]+(; )?", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");

    # Remove any Cloudflare cookies
    set req.http.Cookie = regsuball(req.http.Cookie, "__cfduid=[^;]+(; )?", "");

    # 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, "__atuvc=[^;]+(; )?", "");

    # 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;
    }

    # Normalize Accept-Encoding header
    # straight from the manual: https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
            # No point in compressing these
            remove 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 {
            # unkown algorithm
            remove req.http.Accept-Encoding;
        }
    }

    # 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: http://mattiasgeniar.be/2012/11/28/stop-caching-static-files/
    if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|zip)(\?.*)?$") {
        unset req.http.Cookie;
        return (lookup);
    }

    # Send Surrogate-Capability headers to announce ESI support to backend
    set req.http.Surrogate-Capability = "key=ESI/1.0";

    # Include custom vcl_recv logic
    include "conf.d/receive/wordpress.vcl";

    if (req.http.Authorization || req.http.Cookie) {
        # Not cacheable by default
        return (pass);
    }

    return (lookup);
}

sub 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";
    return (pipe);
}

sub vcl_pass {
    return (pass);
}

# The data on which the hashing will take place
sub vcl_hash {
    hash_data(req.url);

    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # hash cookies for object with auth
    if (req.http.Cookie) {
        hash_data(req.http.Cookie);
    }
    if (req.http.Authorization) {
        hash_data(req.http.Authorization);
    }

    return (hash);
}

sub vcl_hit {
    # Allow purges
    if (req.request == "PURGE") {
        purge;
        error 200 "purged";
    }

    return (deliver);
}

sub vcl_miss {
    # Allow purges
    if (req.request == "PURGE") {
        purge;
        error 200 "purged";
    }

    return (fetch);
}

# Handle the HTTP request coming from our backend
sub vcl_fetch {
    set beresp.grace = 1h;

    # Include custom vcl_fetch logic
    include "conf.d/fetch/wordpress.vcl";

    # Parse 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 the request to the backend returns a code is 5xx, restart the loop
    # If the number of restarts reaches the value of the parameter max_restarts,
    # the request will be error'ed.  max_restarts defaults to 4.  This prevents
    # an eternal loop in the event that, e.g., the object does not exist at all.
    if (beresp.status >= 500 && beresp.status <= 599){
        return(restart);
    }

    # 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: http://mattiasgeniar.be/2012/11/28/stop-caching-static-files/
    if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|zip)(\?.*)?$") {
        unset beresp.http.set-cookie;
    }

    # 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]+", "");
    }

    # Don't cache user & server errors
    if (beresp.status >= 400) {
        return (hit_for_pass);
    }

    # Non private responses without cookies and with a ttl of 0 should be artificially extended to 5min
    if (beresp.ttl <= 0s && beresp.http.Cache-Control !~ "private" && (!beresp.http.Set-Cookie)) {
        set beresp.ttl = 1h;
        set beresp.http.X-Cache-Extended = "1";
    }

    # Set 2min cache if unset for static files
    if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
        set beresp.ttl = 120s;
        return (hit_for_pass);
    }

    return (deliver);
}

# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "cached";
    } else {
        set resp.http.x-Cache = "uncached";
    }

    # 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;

    return (deliver);
}

sub vcl_error {
    if (obj.status >= 500 && obj.status <= 599 && req.restarts < 4) {
        # 4 retry for 5xx error
        return(restart);
    } elsif (obj.status >= 400 && obj.status <= 499 ) {
        # use 404 error page for 4xx error
        include "conf.d/error-404.vcl";
    } elsif (obj.status <= 200 && obj.status >= 299 ) {
        # for other errors (not 5xx, not 4xx and not 2xx)
        include "conf.d/error.vcl";
    } elseif (obj.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: error 720 "http://host/new.html"
        set obj.status = 301;
        set obj.http.Location = obj.response;
        return (deliver);
    } elseif (obj.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: error 720 "http://host/new.html"
        set obj.status = 302;
        set obj.http.Location = obj.response;
        return (deliver);
    } else {
        include "conf.d/error.vcl";
    }

    return (deliver);
}

sub vcl_init {
    return (ok);
}

sub vcl_fini {
    return (ok);
}

# Default backend definition.  Set this to point to your content server.
# all paths relative to varnish option vcl_dir

include "custom.backend.vcl";
include "custom.acl.vcl";

# Handle the HTTP request received by the client
sub vcl_recv {
    # varnish serves stale (but cacheable) objects while retriving object from backend
    if (req.backend.healthy) {
        set req.grace = 30s;
    } else {
        set req.grace = 1h;
    }

    # shortcut for DFind requests
    if (req.url ~ "^/w00tw00t") {
        error 404 "Not Found";
    }

    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;
        }
    }

    # 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]+", "");

    # Allow purging
    if (req.request == "PURGE") {
        if (!client.ip ~ purge) {
            # Not from an allowed IP? Then die with an error.
            error 405 "This IP is not allowed to send PURGE requests.";
        }

        # If you got this stage (and didn't error out above), do a cache-lookup
        # That will force entry into vcl_hit() or vcl_miss() below and purge the actual cache
        return (lookup);
    }

    # Only deal with "normal" types
    if (req.request != "GET" &&
            req.request != "HEAD" &&
            req.request != "PUT" &&
            req.request != "POST" &&
            req.request != "TRACE" &&
            req.request != "OPTIONS" &&
            req.request != "PATCH" &&
            req.request != "DELETE") {
        /* Non-RFC2616 or CONNECT which is weird. */
        return (pipe);
    }

    if (req.request != "GET" && req.request != "HEAD") {
        # We only deal with GET and HEAD by default
        return (pass);
    }

    # Some generic URL manipulation, useful for all templates that follow
    # First remove the Google Analytics added parameters, useless for our backend
    if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") {
        set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
        set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
        set req.url = regsub(req.url, "\?&", "?");
        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, "\?$", "");
    }

    # This is an example to redirect with a 301/302 HTTP status code from within Varnish
    # if (req.http.Host ~ "secure.mysite.tld") {
    #   # We may want to force our users from the secure site to the HTTPs version?
    #   error 720 "https://secure.mysite.tld";
    #   # If you want to keep the URLs intact, this also works:
    #   error 720 "https://" + req.http.Host + req.url;
    # }
    #
    # Or to force a 302 temporary redirect, use error 721
    # if (req.http.Host ~ "temp.mysite.tld") {
    #   # Temporary redirect
    #   error 721 "http://mysite.tld/temp";
    # }
    #

    # 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 Satallite cookies
    set req.http.Cookie = regsuball(req.http.Cookie, "__gaid=[^;]+(; )?", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "_sdsat_[^=]+=[^;]+(; )?", "");

    # 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, "utmctr=[^;]+(; )?", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", "");
    set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", "");

    # Remove any Cloudflare cookies
    set req.http.Cookie = regsuball(req.http.Cookie, "__cfduid=[^;]+(; )?", "");

    # 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, "__atuvc=[^;]+(; )?", "");

    # 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;
    }

    # Normalize Accept-Encoding header
    # straight from the manual: https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
            # No point in compressing these
            remove 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 {
            # unkown algorithm
            remove req.http.Accept-Encoding;
        }
    }

    # 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: http://mattiasgeniar.be/2012/11/28/stop-caching-static-files/
    if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|zip)(\?.*)?$") {
        unset req.http.Cookie;
        return (lookup);
    }

    # Send Surrogate-Capability headers to announce ESI support to backend
    set req.http.Surrogate-Capability = "key=ESI/1.0";

    # Include custom vcl_recv logic
    include "conf.d/receive/wordpress.vcl";

    if (req.http.Authorization || req.http.Cookie) {
        # Not cacheable by default
        return (pass);
    }

    return (lookup);
}

sub 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";
    return (pipe);
}

sub vcl_pass {
    return (pass);
}

# The data on which the hashing will take place
sub vcl_hash {
    hash_data(req.url);

    if (req.http.host) {
        hash_data(req.http.host);
    } else {
        hash_data(server.ip);
    }

    # hash cookies for object with auth
    if (req.http.Cookie) {
        hash_data(req.http.Cookie);
    }
    if (req.http.Authorization) {
        hash_data(req.http.Authorization);
    }

    return (hash);
}

sub vcl_hit {
    # Allow purges
    if (req.request == "PURGE") {
        purge;
        error 200 "purged";
    }

    return (deliver);
}

sub vcl_miss {
    # Allow purges
    if (req.request == "PURGE") {
        purge;
        error 200 "purged";
    }

    return (fetch);
}

# Handle the HTTP request coming from our backend
sub vcl_fetch {
    set beresp.grace = 1h;

    # Include custom vcl_fetch logic
    include "conf.d/fetch/wordpress.vcl";

    # Parse 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 the request to the backend returns a code is 5xx, restart the loop
    # If the number of restarts reaches the value of the parameter max_restarts,
    # the request will be error'ed.  max_restarts defaults to 4.  This prevents
    # an eternal loop in the event that, e.g., the object does not exist at all.
    if (beresp.status >= 500 && beresp.status <= 599){
        return(restart);
    }

    # 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: http://mattiasgeniar.be/2012/11/28/stop-caching-static-files/
    if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|zip)(\?.*)?$") {
        unset beresp.http.set-cookie;
    }

    # 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]+", "");
    }

    # Non private responses without cookies and with a ttl of 0 should be artificially extended to 5min
    if (beresp.ttl <= 0s && beresp.http.Cache-Control !~ "private" && (!beresp.http.Set-Cookie)) {
        set beresp.ttl = 1h;
        set beresp.http.X-Cache-Extended = "1";
    }

    # Set 2min cache if unset for static files
    if (beresp.ttl <= 0s || beresp.http.Set-Cookie || beresp.http.Vary == "*") {
        set beresp.ttl = 120s;
        return (hit_for_pass);
    }

    return (deliver);
}

# The routine when we deliver the HTTP request to the user
# Last chance to modify headers that are sent to the client
sub vcl_deliver {
    if (obj.hits > 0) {
        set resp.http.X-Cache = "cached";
    } else {
        set resp.http.x-Cache = "uncached";
    }

    # 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;

    return (deliver);
}

sub vcl_error {
    if (obj.status >= 500 && obj.status <= 599 && req.restarts < 4) {
        # 4 retry for 5xx error
        return(restart);
    } elsif (obj.status >= 400 && obj.status <= 499 ) {
        # use 404 error page for 4xx error
        include "conf.d/error-404.vcl";
    } elsif (obj.status <= 200 && obj.status >= 299 ) {
        # for other errors (not 5xx, not 4xx and not 2xx)
        include "conf.d/error.vcl";
    } elseif (obj.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: error 720 "http://host/new.html"
        set obj.status = 301;
        set obj.http.Location = obj.response;
        return (deliver);
    } elseif (obj.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: error 720 "http://host/new.html"
        set obj.status = 302;
        set obj.http.Location = obj.response;
        return (deliver);
    } else {
        include "conf.d/error.vcl";
    }

    return (deliver);
}

sub vcl_init {
    return (ok);
}

sub vcl_fini {
    return (ok);
}


Strip last-modified headers from wms requests for data overlays and otherwise don't cache (so logged in and logged out user doesn't see the same data)

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
backend cy {
    .host = "cy.blah";
    .port = "8001";
}

backend en {
    .host = "en.blah";
    .port = "8002";
}

#
# Below is a commented-out copy of the default VCL logic.  If you
# redefine any of these subroutines, the built-in logic will be
# appended to your code.
sub vcl_recv {
	if (req.http.host ~ "(?i)^(www.)?cy.blah") {
		set req.http.host = "cy.blah";
		set req.backend = cy;
	}
	elsif (req.http.host ~ "(?i)^(www.)?en.blah") {
		set req.http.host = "en.blah";
		set req.backend = en;
	}

	if ( req.url ~ "^/wms\?map=fishmap" ) {
		return (pass);
	}

	if ( req.url ~ "^/static/" ) {
		return (lookup);
	}
	if ( req.url ~ "^/wms" ) {
		return (lookup);
	}
#     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;
# 	}
#     }
#     if (req.request != "GET" &&
#       req.request != "HEAD" &&
#       req.request != "PUT" &&
#       req.request != "POST" &&
#       req.request != "TRACE" &&
#       req.request != "OPTIONS" &&
#       req.request != "DELETE") {
#         /* Non-RFC2616 or CONNECT which is weird. */
#         return (pipe);
#     }
     if (req.request != "GET" && req.request != "HEAD") {
         /* We only deal with GET and HEAD by default */
         return (pass);
     }
     if (req.http.Authorization || req.http.Cookie) {
         /* Not cacheable by default */
         return (pass);
     }
     return (lookup);
}
#
# sub 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.
#     return (pipe);
# }
#
# sub vcl_pass {
#     return (pass);
# }
#
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (hash);
# }
#
# sub vcl_hit {
#     return (deliver);
# }
#
# sub vcl_miss {
#     return (fetch);
# }
#
sub vcl_fetch {
#     if (beresp.ttl <= 0s ||
#         beresp.http.Set-Cookie ||
#         beresp.http.Vary == "*") {
# 		/*
# 		 * Mark as "Hit-For-Pass" for the next 2 minutes
# 		 */
# 		set beresp.ttl = 120 s;
# 		return (hit_for_pass);
#     }
	if ( req.url ~ "^/wms\?map=fishmap" ) {
		unset beresp.http.last-modified;
		return (hit_for_pass);
	}
	if ( req.url ~ "^/wms" ) {
     		unset beresp.http.set-cookie;
		unset beresp.http.expires;
     		set beresp.ttl = 1w;
	        set beresp.http.Cache-Control = "max-age=1900";
	}
     return (deliver);
}
#
# sub vcl_deliver {
#     return (deliver);
# }
#
# sub vcl_error {
#     set obj.http.Content-Type = "text/html; charset=utf-8";
#     set obj.http.Retry-After = "5";
#     synthetic {"
# <?xml version="1.0" encoding="utf-8"?>
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
#  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
#
#
#     <title>"} + obj.status + " " + obj.response + {"</title>
#
#
#
Error "} + obj.status + " " + obj.response + {"

#
"} + obj.response + {"

#
Guru Meditation:

#
XID: "} + req.xid + {"

#

#
Varnish cache server

#
#
# "};
#     return (deliver);
# }
#
# sub vcl_init {
# 	return (ok);
# }
#
# sub vcl_fini {
# 	return (ok);
# }

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition.  Set this to point to your content
# server.
#
backend cy {
    .host = "cy.blah";
    .port = "8001";
}

backend en {
    .host = "en.blah";
    .port = "8002";
}

#
# Below is a commented-out copy of the default VCL logic.  If you
# redefine any of these subroutines, the built-in logic will be
# appended to your code.
sub vcl_recv {
	if (req.http.host ~ "(?i)^(www.)?cy.blah") {
		set req.http.host = "cy.blah";
		set req.backend = cy;
	}
	elsif (req.http.host ~ "(?i)^(www.)?en.blah") {
		set req.http.host = "en.blah";
		set req.backend = en;
	}

	if ( req.url ~ "^/wms\?map=fishmap" ) {
		return (pass);
	}

	if ( req.url ~ "^/static/" ) {
		return (lookup);
	}
	if ( req.url ~ "^/wms" ) {
		return (lookup);
	}
#     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;
# 	}
#     }
#     if (req.request != "GET" &&
#       req.request != "HEAD" &&
#       req.request != "PUT" &&
#       req.request != "POST" &&
#       req.request != "TRACE" &&
#       req.request != "OPTIONS" &&
#       req.request != "DELETE") {
#         /* Non-RFC2616 or CONNECT which is weird. */
#         return (pipe);
#     }
     if (req.request != "GET" && req.request != "HEAD") {
         /* We only deal with GET and HEAD by default */
         return (pass);
     }
     if (req.http.Authorization || req.http.Cookie) {
         /* Not cacheable by default */
         return (pass);
     }
     return (lookup);
}
#
# sub 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.
#     return (pipe);
# }
#
# sub vcl_pass {
#     return (pass);
# }
#
# sub vcl_hash {
#     hash_data(req.url);
#     if (req.http.host) {
#         hash_data(req.http.host);
#     } else {
#         hash_data(server.ip);
#     }
#     return (hash);
# }
#
# sub vcl_hit {
#     return (deliver);
# }
#
# sub vcl_miss {
#     return (fetch);
# }
#
sub vcl_fetch {
#     if (beresp.ttl <= 0s ||
#         beresp.http.Set-Cookie ||
#         beresp.http.Vary == "*") {
# 		/*
# 		 * Mark as "Hit-For-Pass" for the next 2 minutes
# 		 */
# 		set beresp.ttl = 120 s;
# 		return (hit_for_pass);
#     }
	if ( req.url ~ "^/wms" ) {
     		unset beresp.http.set-cookie;
		unset beresp.http.expires;
     		set beresp.ttl = 1w;
	        set beresp.http.Cache-Control = "max-age=1900";
	}
     return (deliver);
}
#
# sub vcl_deliver {
#     return (deliver);
# }
#
# sub vcl_error {
#     set obj.http.Content-Type = "text/html; charset=utf-8";
#     set obj.http.Retry-After = "5";
#     synthetic {"
# <?xml version="1.0" encoding="utf-8"?>
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
#  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
#
#
#     <title>"} + obj.status + " " + obj.response + {"</title>
#
#
#
Error "} + obj.status + " " + obj.response + {"

#
"} + obj.response + {"

#
Guru Meditation:

#
XID: "} + req.xid + {"

#

#
Varnish cache server

#
#
# "};
#     return (deliver);
# }
#
# sub vcl_init {
# 	return (ok);
# }
#
# sub vcl_fini {
# 	return (ok);
# }


Update scheme

Update scheme

# Copyright (c) 2012-2014 Varnish Software AS
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# detectdevice.vcl - regex based device detection for Varnish
# https://github.com/varnish/varnish-devicedetect/
#
# Author: Lasse Karstensen <lkarsten@varnish-software.com>

sub devicedetect {
	unset req.http.X-UA-Device;
	set req.http.X-UA-Device = "pc";

	# Handle that a cookie may override the detection alltogether.
	if (req.http.Cookie ~ "(?i)X-UA-Device-force") {
		/* ;?? means zero or one ;, non-greedy to match the first. */
		set req.http.X-UA-Device = regsub(req.http.Cookie, "(?i).*X-UA-Device-force=([^;]+);??.*", "\1");
		/* Clean up our mess in the cookie header */
		set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *X-UA-Device-force=[^;]+;? *", "\1");
		/* If the cookie header is now empty, or just whitespace, unset it. */
		if (req.http.Cookie ~ "^ *$") { unset req.http.Cookie; }
	} else {
        if (req.http.User-Agent ~ "\(compatible; Googlebot-Mobile/2.1; \+http://www.google.com/bot.html\)" ||
            (req.http.User-Agent ~ "iPhone" && req.http.User-Agent ~ "\(compatible; Googlebot/2.1; \+http://www.google.com/bot.html")) {
            set req.http.X-UA-Device = "mobile-bot"; }
		elsif (req.http.User-Agent ~ "(?i)(ads|google|bing|msn|yandex|baidu|ro|career|)bot" ||
		    req.http.User-Agent ~ "(?i)(baidu|jike|symantec)spider" ||
		    req.http.User-Agent ~ "(?i)scanner" ||
		    req.http.User-Agent ~ "(?i)(web)crawler") {
			set req.http.X-UA-Device = "bot"; }
		elsif (req.http.User-Agent ~ "(?i)ipad")        { set req.http.X-UA-Device = "tablet-ipad"; }
		elsif (req.http.User-Agent ~ "(?i)ip(hone|od)") { set req.http.X-UA-Device = "mobile-iphone"; }
		/* how do we differ between an android phone and an android tablet?
		   http://stackoverflow.com/questions/5341637/how-do-detect-android-tablets-in-general-useragent */
		elsif (req.http.User-Agent ~ "(?i)android.*(mobile|mini)") { set req.http.X-UA-Device = "mobile-android"; }
		// android 3/honeycomb was just about tablet-only, and any phones will probably handle a bigger page layout.
		elsif (req.http.User-Agent ~ "(?i)android 3")              { set req.http.X-UA-Device = "tablet-android"; }
		/* Opera Mobile */
		elsif (req.http.User-Agent ~ "Opera Mobi")                  { set req.http.X-UA-Device = "mobile-smartphone"; }
		// May very well give false positives towards android tablets. Suggestions welcome.
		elsif (req.http.User-Agent ~ "(?i)android")         { set req.http.X-UA-Device = "tablet-android"; }
		elsif (req.http.User-Agent ~ "PlayBook; U; RIM Tablet")         { set req.http.X-UA-Device = "tablet-rim"; }
		elsif (req.http.User-Agent ~ "hp-tablet.*TouchPad")         { set req.http.X-UA-Device = "tablet-hp"; }
		elsif (req.http.User-Agent ~ "Kindle/3")         { set req.http.X-UA-Device = "tablet-kindle"; }
		elsif (req.http.User-Agent ~ "Touch.+Tablet PC")            { set req.http.X-UA-Device = "tablet-microsoft"; }
		elsif (req.http.User-Agent ~ "Mobile.+Firefox")     { set req.http.X-UA-Device = "mobile-firefoxos"; }
		elsif (req.http.User-Agent ~ "^HTC" ||
		    req.http.User-Agent ~ "Fennec" ||
		    req.http.User-Agent ~ "IEMobile" ||
		    req.http.User-Agent ~ "BlackBerry" ||
		    req.http.User-Agent ~ "BB10.*Mobile" ||
		    req.http.User-Agent ~ "GT-.*Build/GINGERBREAD" ||
		    req.http.User-Agent ~ "SymbianOS.*AppleWebKit") {
			set req.http.X-UA-Device = "mobile-smartphone";
		}
		elsif (req.http.User-Agent ~ "(?i)symbian" ||
		    req.http.User-Agent ~ "(?i)^sonyericsson" ||
		    req.http.User-Agent ~ "(?i)^nokia" ||
		    req.http.User-Agent ~ "(?i)^samsung" ||
		    req.http.User-Agent ~ "(?i)^lg" ||
		    req.http.User-Agent ~ "(?i)bada" ||
		    req.http.User-Agent ~ "(?i)blazer" ||
		    req.http.User-Agent ~ "(?i)cellphone" ||
		    req.http.User-Agent ~ "(?i)iemobile" ||
		    req.http.User-Agent ~ "(?i)midp-2.0" ||
		    req.http.User-Agent ~ "(?i)u990" ||
		    req.http.User-Agent ~ "(?i)netfront" ||
		    req.http.User-Agent ~ "(?i)opera mini" ||
		    req.http.User-Agent ~ "(?i)palm" ||
		    req.http.User-Agent ~ "(?i)nintendo wii" ||
		    req.http.User-Agent ~ "(?i)playstation portable" ||
		    req.http.User-Agent ~ "(?i)portalmmm" ||
		    req.http.User-Agent ~ "(?i)proxinet" ||
		    req.http.User-Agent ~ "(?i)sonyericsson" ||
		    req.http.User-Agent ~ "(?i)symbian" ||
		    req.http.User-Agent ~ "(?i)windows\ ?ce" ||
		    req.http.User-Agent ~ "(?i)winwap" ||
		    req.http.User-Agent ~ "(?i)eudoraweb" ||
		    req.http.User-Agent ~ "(?i)htc" ||
		    req.http.User-Agent ~ "(?i)240x320" ||
		    req.http.User-Agent ~ "(?i)avantgo") {
			set req.http.X-UA-Device = "mobile-generic";
		}
	}
}

# Copyright (c) 2012-2014 Varnish Software AS
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# detectdevice.vcl - regex based device detection for Varnish
# http://github.com/varnish/varnish-devicedetect/
#
# Author: Lasse Karstensen <lkarsten@varnish-software.com>

sub devicedetect {
	unset req.http.X-UA-Device;
	set req.http.X-UA-Device = "pc";

	# Handle that a cookie may override the detection alltogether.
	if (req.http.Cookie ~ "(?i)X-UA-Device-force") {
		/* ;?? means zero or one ;, non-greedy to match the first. */
		set req.http.X-UA-Device = regsub(req.http.Cookie, "(?i).*X-UA-Device-force=([^;]+);??.*", "\1");
		/* Clean up our mess in the cookie header */
		set req.http.Cookie = regsuball(req.http.Cookie, "(^|; ) *X-UA-Device-force=[^;]+;? *", "\1");
		/* If the cookie header is now empty, or just whitespace, unset it. */
		if (req.http.Cookie ~ "^ *$") { unset req.http.Cookie; }
	} else {
        if (req.http.User-Agent ~ "\(compatible; Googlebot-Mobile/2.1; \+http://www.google.com/bot.html\)" ||
            (req.http.User-Agent ~ "iPhone" && req.http.User-Agent ~ "\(compatible; Googlebot/2.1; \+http://www.google.com/bot.html")) {
            set req.http.X-UA-Device = "mobile-bot"; }
		elsif (req.http.User-Agent ~ "(?i)(ads|google|bing|msn|yandex|baidu|ro|career|)bot" ||
		    req.http.User-Agent ~ "(?i)(baidu|jike|symantec)spider" ||
		    req.http.User-Agent ~ "(?i)scanner" ||
		    req.http.User-Agent ~ "(?i)(web)crawler") {
			set req.http.X-UA-Device = "bot"; }
		elsif (req.http.User-Agent ~ "(?i)ipad")        { set req.http.X-UA-Device = "tablet-ipad"; }
		elsif (req.http.User-Agent ~ "(?i)ip(hone|od)") { set req.http.X-UA-Device = "mobile-iphone"; }
		/* how do we differ between an android phone and an android tablet?
		   http://stackoverflow.com/questions/5341637/how-do-detect-android-tablets-in-general-useragent */
		elsif (req.http.User-Agent ~ "(?i)android.*(mobile|mini)") { set req.http.X-UA-Device = "mobile-android"; }
		// android 3/honeycomb was just about tablet-only, and any phones will probably handle a bigger page layout.
		elsif (req.http.User-Agent ~ "(?i)android 3")              { set req.http.X-UA-Device = "tablet-android"; }
		/* Opera Mobile */
		elsif (req.http.User-Agent ~ "Opera Mobi")                  { set req.http.X-UA-Device = "mobile-smartphone"; }
		// May very well give false positives towards android tablets. Suggestions welcome.
		elsif (req.http.User-Agent ~ "(?i)android")         { set req.http.X-UA-Device = "tablet-android"; }
		elsif (req.http.User-Agent ~ "PlayBook; U; RIM Tablet")         { set req.http.X-UA-Device = "tablet-rim"; }
		elsif (req.http.User-Agent ~ "hp-tablet.*TouchPad")         { set req.http.X-UA-Device = "tablet-hp"; }
		elsif (req.http.User-Agent ~ "Kindle/3")         { set req.http.X-UA-Device = "tablet-kindle"; }
		elsif (req.http.User-Agent ~ "Touch.+Tablet PC")            { set req.http.X-UA-Device = "tablet-microsoft"; }
		elsif (req.http.User-Agent ~ "Mobile.+Firefox")     { set req.http.X-UA-Device = "mobile-firefoxos"; }
		elsif (req.http.User-Agent ~ "^HTC" ||
		    req.http.User-Agent ~ "Fennec" ||
		    req.http.User-Agent ~ "IEMobile" ||
		    req.http.User-Agent ~ "BlackBerry" ||
		    req.http.User-Agent ~ "BB10.*Mobile" ||
		    req.http.User-Agent ~ "GT-.*Build/GINGERBREAD" ||
		    req.http.User-Agent ~ "SymbianOS.*AppleWebKit") {
			set req.http.X-UA-Device = "mobile-smartphone";
		}
		elsif (req.http.User-Agent ~ "(?i)symbian" ||
		    req.http.User-Agent ~ "(?i)^sonyericsson" ||
		    req.http.User-Agent ~ "(?i)^nokia" ||
		    req.http.User-Agent ~ "(?i)^samsung" ||
		    req.http.User-Agent ~ "(?i)^lg" ||
		    req.http.User-Agent ~ "(?i)bada" ||
		    req.http.User-Agent ~ "(?i)blazer" ||
		    req.http.User-Agent ~ "(?i)cellphone" ||
		    req.http.User-Agent ~ "(?i)iemobile" ||
		    req.http.User-Agent ~ "(?i)midp-2.0" ||
		    req.http.User-Agent ~ "(?i)u990" ||
		    req.http.User-Agent ~ "(?i)netfront" ||
		    req.http.User-Agent ~ "(?i)opera mini" ||
		    req.http.User-Agent ~ "(?i)palm" ||
		    req.http.User-Agent ~ "(?i)nintendo wii" ||
		    req.http.User-Agent ~ "(?i)playstation portable" ||
		    req.http.User-Agent ~ "(?i)portalmmm" ||
		    req.http.User-Agent ~ "(?i)proxinet" ||
		    req.http.User-Agent ~ "(?i)sonyericsson" ||
		    req.http.User-Agent ~ "(?i)symbian" ||
		    req.http.User-Agent ~ "(?i)windows\ ?ce" ||
		    req.http.User-Agent ~ "(?i)winwap" ||
		    req.http.User-Agent ~ "(?i)eudoraweb" ||
		    req.http.User-Agent ~ "(?i)htc" ||
		    req.http.User-Agent ~ "(?i)240x320" ||
		    req.http.User-Agent ~ "(?i)avantgo") {
			set req.http.X-UA-Device = "mobile-generic";
		}
	}
}


Remove cookie _gat for Google analytics

Remove cookie _gat for Google analytics

vcl 4.0;
# Based on: https://github.com/mattiasgeniar/varnish-4.0-configuration-templates/blob/master/default.vcl

import std;
import directors;

probe health
{
    #.url = "/varnish-enabled";
    # We prefer to only do a HEAD /
    .request =
        "HEAD /varnish-enabled HTTP/1.1"
        "Host: localhost"
        "Connection: close";
    .interval = 5s;   # check the health of each backend every 5 seconds
    .timeout = 1s;    # timing out after 1 second.
    # If 3 out of the last 5 polls succeeded the backend is considered healthy, otherwise it will be marked as sick
    .window = 5;
    .threshold = 3;
    .expected_response = 200;
}

backend default
{
    .host = "127.0.0.1";        # IP or Hostname of backend
    .port = "8080";             # Port Apache or whatever is listening
    .max_connections = 300;     # That's it
    .probe = health;
    .connect_timeout            = 600s;  # How long to wait before we receive a first byte from our backend?
    .first_byte_timeout         = 600s;  # How long to wait for a backend connection?
    .between_bytes_timeout      = 600s;  # How long to wait between bytes received from our backend?
}

backend passthrough
{
    .host = "127.0.0.1";        # IP or Hostname of backend
    .port = "8080";             # Port Apache or whatever is listening
}

acl localhost
{
    "localhost";
    "33.33.33.63";
    "::1";
}

sub vcl_init
{
    # Called when VCL is loaded, before any requests pass through it.
    # Typically used to initialize VMODs.

    new vdir = directors.round_robin();
    vdir.add_backend(default);
    # vdir.add_backend(server...);
    # vdir.add_backend(servern);
}

sub vcl_recv
{
    # 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 and if needed to modify the request.

    # Send all traffic to the vdir director
    set req.backend_hint = vdir.backend();

    if (req.restarts == 0)
    {
        # Set or append the client.ip to X-Forwarded-For header
        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.X-Forwarded-By = server.ip;
        set req.http.X-Forwarded-Port = std.port(client.ip);
    }

    # 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 the query arguments
    set req.url = std.querysort(req.url);

    # Allow purging
    if (req.method == "PURGE")
    {
        # purge is the ACL defined at the begining
        if (!client.ip ~ localhost) {
            return (synth(405, "This IP is not allowed to send PURGE requests."));
        }

        # If you got this stage (and didn't error out above), purge the cached result
        return (purge);
    }

    # Check if we've still enabled Varnish, if not, passthrough every request
    if (! std.healthy(req.backend_hint))
    {
        set req.backend_hint = passthrough;
        return (pass);
    }

    # 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);
    }

    # Specific Nooku Platform rules

        # Do not cache /administrator
        if(req.url ~ "^/administrator") {
            return (pass);
        }

    # Specific Nooku Server rules

        # Do not cache webgrind.nooku.dev
        if (req.http.host == "webgrind.nooku.dev") {
            return (pass);
        }

        # Do not cache phpmyadmin.nooku.dev
        if (req.http.host == "phpmyadmin.nooku.dev") {
            return (pass);
        }

        # Do not cache /apc and /phpinfo
        if (req.url == "/apc" || req.url == "/phpinfo") {
            return (pass);
        }

    # Generic URL manipulation, useful for all templates that follow

        # Remove the Google Analytics added parameters, useless for our backend
        if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
            set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
            set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
            set req.url = regsub(req.url, "\?&", "?");
            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, "\?$", "");
        }

    # Cookie manipulation

        # 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*", "");

        # Remove the csrf_token cookie
        set req.http.Cookie = regsuball(req.http.Cookie, "csrf_token=[^;]+(; )?", "");

        # Are there cookies left with only spaces or that are empty?
        if (req.http.cookie ~ "^\s*$") {
            unset req.http.cookie;
        }

        # Large static files are delivered directly to the end-user without waiting for Varnish to fully read the file first.
        # Varnish 4 supports Streaming, so set do_stream in vcl_backend_response()
        if (req.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip|bz2|xz|7z|avi|mov|og[gvaxm]|mpe?g|mk[av])(\?.*)?$") {
            unset req.http.Cookie;
            return (hash);
        }

        # Remove all cookies for static files
        # Before you blindly enable this read: https://ma.ttias.be/stop-caching-static-files/
        #if (req.method == "GET")
        #{
        #    # Cache files with these extensions and remove cookie
        #    if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|pdf|png|rtf|swf|txt|woff|xml)(\?.*)?$") {
        #        unset req.http.Cookie;
        #        return (hash);
        #    }
        #}

    # Normalize Accept-Encoding header
    # straight from the manual: https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
    # TODO: Test if it's still needed, Varnish 4 now does this by itself if http_gzip_support = on
    # https://www.varnish-cache.org/docs/trunk/users-guide/compression.html
    # https://www.varnish-cache.org/docs/trunk/phk/gzip.html
    if (req.http.Accept-Encoding)
    {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
            # No point in compressing these
            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 {
            # unkown algorithm
            unset req.http.Accept-Encoding;
        }
    }

    if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ localhost)
    {
        # http://varnish.projects.linpro.no/wiki/VCLExampleEnableForceRefresh
        # 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))
        {
            # Doesn't seems to refresh the object in the cache
            set req.hash_always_miss = true;

            # Couple this with restart in vcl_purge and X-Purge header to avoid loops
            return(purge);
        }
    }

    # Send Surrogate-Capability headers to announce ESI support to backend
    set req.http.Surrogate-Capability = "varnish=ESI/1.0";

    # Requests that require authorization are not cacheable by default
    if (req.http.Authorization) {
        return (pass);
    }

    # We do not support SPDY or HTTP/2.0
    if (req.method == "PRI") {
        return (synth(405));
    }

    return (hash);
}

# 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.
sub 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";
    # 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);
}

# 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 (fetch);
}

# 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);
    }
}

# Called when a cache lookup is successful.
sub vcl_hit
{
    # A pure unadultered hit, deliver it
    if (obj.ttl >= 0s) {
        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.

    # if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
    #   return (deliver);
    # } else {
    #   return (fetch);
    # }

    # We have no fresh fish. Lets look at the stale ones.
    if (std.healthy(req.backend_hint))
    {
        # Backend is healthy. Limit age to 10s.
        if (obj.ttl + 10s > 0s)
        {
            #set req.http.grace = "normal(limited)";
            return (deliver);
        }
        else
        {
            # No candidate for grace. Fetch a fresh object.
            return(fetch);
        }
    }
    else
    {
        # backend is sick - use full grace
        if (obj.ttl + obj.grace > 0s)
        {
            #set req.http.grace = "full";
            return (deliver);
        }
        else
        {
            # no graced object.
            return (fetch);
        }
    }

    # fetch & deliver once we get the result
    return (fetch); # Dead code, keep as a safeguard
}

# 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);
}

 # Called after the response headers has been successfully retrieved from the backend.
sub vcl_backend_response
{
    # Enable ESI handling
    if (beresp.http.Surrogate-Control ~ "ESI/1.0" ) {
        set beresp.do_esi = true;
    }

    # Store the csrf_token cookie temporarily if the response is cacheabale
    if (beresp.http.Set-Cookie && !beresp.uncacheable)
    {
        set beresp.http.X-Varnish-Cookie = beresp.http.Set-Cookie;
        unset beresp.http.Set-Cookie;
    }

    # Cache handling all static files
    if (bereq.method == "GET")
    {
        # Before you blindly enable this, read: https://ma.ttias.be/stop-caching-static-files/
        #if (bereq.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|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. Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend
        # doesn't send a Content-Length header. Only enable it for large files
        if (bereq.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip|bz2|xz|7z|avi|mov|og[gvaxm]|mpe?g|mk[av])(\?.*)?$")
        {
            unset beresp.http.Set-Cookie;

            # Use streaming to avoid locking
            set beresp.do_stream = true;

            # Don't try to compress it for storage
            set beresp.do_gzip = false;

            # Disable Transfer-encoding chunked when serving HTML5 video
            # See : http://stackoverflow.com/questions/23643233/how-do-i-disable-transfer-encoding-chunked-encoding-in-varnish
            # See : https://www.varnish-cache.org/trac/ticket/1506
            if(beresp.http.Content-Type ~ "video") {
                set beresp.do_stream = true;
                set beresp.do_esi    = true;
            }
        }

        # 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);
        }
    }

    # 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]+", "");
    }

    # Do not cache errors from the backend
    if (beresp.status >= 400)
    {
        set beresp.uncacheable = true;
        set beresp.ttl = 0s;

        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;

    # Set ban-lurker friendly custom headers
    set beresp.http.X-Varnish-Url  = bereq.url;
    set beresp.http.X-Varnish-Host = bereq.http.host;

    return (deliver);
}

# Called when the backend returns an error
sub vcl_backend_error
{
    if (beresp.status == 503 && bereq.retries < 5)
    {
        set beresp.http.X-Varnish-Retries = bereq.retries;
        return(retry);
    }

    return(deliver);
}

# Called before a cached object is delivered to the client.
sub vcl_deliver
{
    # Send the Cookie header again if a temporay header was stored
    if (req.http.X-Varnish-Cookie) {
        set resp.http.Set-Cookie = req.http.X-Varnish-Cookie;
    }

    # Add extra headers if debugging is enabled
    if (resp.http.x-varnish-debug && server.ip ~ localhost)
    {
        set resp.http.X-Served-By = server.hostname;

        if (resp.http.x-varnish ~ " ") {
            set resp.http.X-Varnish-Status = "HIT";
        } else {
            set resp.http.X-Varnish-Status = "MISS";
        }

        # 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-Varnish-Hits = obj.hits;
    }
    else
    {
        # Remove ban-lurker friendly custom headers when delivering to client
        unset resp.http.X-Url;
        unset resp.http.X-Host;

        # Remove some headers: PHP version
        unset resp.http.X-Powered-By;

        # Remove some headers: Apache version & OS
        unset resp.http.Server;
        unset resp.http.Via;
        unset resp.http.Link;
        unset resp.http.X-Varnish;
        unset resp.http.X-Varnish-Tag;
        unset resp.http.X-Varnish-Debug;
        unset resp.http.X-Varnish-Host;
        unset resp.http.X-Varnish-Url;
        unset resp.http.X-Varnish-Retries;
        unset resp.http.X-Varnish-Cookie;
        unset resp.http.Surrogate-Control;
    }

    return (deliver);
}

sub vcl_purge
{
    # Only handle actual PURGE HTTP methods, everything else is discarded
    if (req.method != "PURGE" && server.ip ~ localhost)
    {
        set req.http.X-Varnish-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);
}

# Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.
sub vcl_fini
{
  return (ok);
}

vcl 4.0;
# Based on: https://github.com/mattiasgeniar/varnish-4.0-configuration-templates/blob/master/default.vcl

import std;
import directors;

probe health
{
    #.url = "/varnish-enabled";
    # We prefer to only do a HEAD /
    .request =
        "HEAD /varnish-enabled HTTP/1.1"
        "Host: localhost"
        "Connection: close";
    .interval = 5s;   # check the health of each backend every 5 seconds
    .timeout = 1s;    # timing out after 1 second.
    # If 3 out of the last 5 polls succeeded the backend is considered healthy, otherwise it will be marked as sick
    .window = 5;
    .threshold = 3;
    .expected_response = 200;
}

backend default
{
    .host = "127.0.0.1";        # IP or Hostname of backend
    .port = "8080";             # Port Apache or whatever is listening
    .max_connections = 300;     # That's it
    .probe = health;
    .connect_timeout            = 600s;  # How long to wait before we receive a first byte from our backend?
    .first_byte_timeout         = 600s;  # How long to wait for a backend connection?
    .between_bytes_timeout      = 600s;  # How long to wait between bytes received from our backend?
}

backend passthrough
{
    .host = "127.0.0.1";        # IP or Hostname of backend
    .port = "8080";             # Port Apache or whatever is listening
}

acl localhost
{
    "localhost";
    "33.33.33.63";
    "::1";
}

sub vcl_init
{
    # Called when VCL is loaded, before any requests pass through it.
    # Typically used to initialize VMODs.

    new vdir = directors.round_robin();
    vdir.add_backend(default);
    # vdir.add_backend(server...);
    # vdir.add_backend(servern);
}

sub vcl_recv
{
    # 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 and if needed to modify the request.

    # Send all traffic to the vdir director
    set req.backend_hint = vdir.backend();

    if (req.restarts == 0)
    {
        # Set or append the client.ip to X-Forwarded-For header
        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.X-Forwarded-By = server.ip;
        set req.http.X-Forwarded-Port = std.port(client.ip);
    }

    # 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 the query arguments
    set req.url = std.querysort(req.url);

    # Allow purging
    if (req.method == "PURGE")
    {
        # purge is the ACL defined at the begining
        if (!client.ip ~ localhost) {
            return (synth(405, "This IP is not allowed to send PURGE requests."));
        }

        # If you got this stage (and didn't error out above), purge the cached result
        return (purge);
    }

    # Check if we've still enabled Varnish, if not, passthrough every request
    if (! std.healthy(req.backend_hint))
    {
        set req.backend_hint = passthrough;
        return (pass);
    }

    # 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);
    }

    # Specific Nooku Platform rules

        # Do not cache /administrator
        if(req.url ~ "^/administrator") {
            return (pass);
        }

    # Specific Nooku Server rules

        # Do not cache webgrind.nooku.dev
        if (req.http.host == "webgrind.nooku.dev") {
            return (pass);
        }

        # Do not cache phpmyadmin.nooku.dev
        if (req.http.host == "phpmyadmin.nooku.dev") {
            return (pass);
        }

        # Do not cache /apc and /phpinfo
        if (req.url == "/apc" || req.url == "/phpinfo") {
            return (pass);
        }

    # Generic URL manipulation, useful for all templates that follow

        # Remove the Google Analytics added parameters, useless for our backend
        if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
            set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
            set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
            set req.url = regsub(req.url, "\?&", "?");
            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, "\?$", "");
        }

    # Cookie manipulation

        # 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, "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*", "");

        # Remove the csrf_token cookie
        set req.http.Cookie = regsuball(req.http.Cookie, "csrf_token=[^;]+(; )?", "");

        # Are there cookies left with only spaces or that are empty?
        if (req.http.cookie ~ "^\s*$") {
            unset req.http.cookie;
        }

        # Large static files are delivered directly to the end-user without waiting for Varnish to fully read the file first.
        # Varnish 4 supports Streaming, so set do_stream in vcl_backend_response()
        if (req.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip|bz2|xz|7z|avi|mov|og[gvaxm]|mpe?g|mk[av])(\?.*)?$") {
            unset req.http.Cookie;
            return (hash);
        }

        # Remove all cookies for static files
        # Before you blindly enable this read: https://ma.ttias.be/stop-caching-static-files/
        #if (req.method == "GET")
        #{
        #    # Cache files with these extensions and remove cookie
        #    if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|pdf|png|rtf|swf|txt|woff|xml)(\?.*)?$") {
        #        unset req.http.Cookie;
        #        return (hash);
        #    }
        #}

    # Normalize Accept-Encoding header
    # straight from the manual: https://www.varnish-cache.org/docs/3.0/tutorial/vary.html
    # TODO: Test if it's still needed, Varnish 4 now does this by itself if http_gzip_support = on
    # https://www.varnish-cache.org/docs/trunk/users-guide/compression.html
    # https://www.varnish-cache.org/docs/trunk/phk/gzip.html
    if (req.http.Accept-Encoding)
    {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
            # No point in compressing these
            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 {
            # unkown algorithm
            unset req.http.Accept-Encoding;
        }
    }

    if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ localhost)
    {
        # http://varnish.projects.linpro.no/wiki/VCLExampleEnableForceRefresh
        # 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))
        {
            # Doesn't seems to refresh the object in the cache
            set req.hash_always_miss = true;

            # Couple this with restart in vcl_purge and X-Purge header to avoid loops
            return(purge);
        }
    }

    # Send Surrogate-Capability headers to announce ESI support to backend
    set req.http.Surrogate-Capability = "varnish=ESI/1.0";

    # Requests that require authorization are not cacheable by default
    if (req.http.Authorization) {
        return (pass);
    }

    # We do not support SPDY or HTTP/2.0
    if (req.method == "PRI") {
        return (synth(405));
    }

    return (hash);
}

# 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.
sub 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";
    # 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);
}

# 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 (fetch);
}

# 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);
    }
}

# Called when a cache lookup is successful.
sub vcl_hit
{
    # A pure unadultered hit, deliver it
    if (obj.ttl >= 0s) {
        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.

    # if (!std.healthy(req.backend_hint) && (obj.ttl + obj.grace > 0s)) {
    #   return (deliver);
    # } else {
    #   return (fetch);
    # }

    # We have no fresh fish. Lets look at the stale ones.
    if (std.healthy(req.backend_hint))
    {
        # Backend is healthy. Limit age to 10s.
        if (obj.ttl + 10s > 0s)
        {
            #set req.http.grace = "normal(limited)";
            return (deliver);
        }
        else
        {
            # No candidate for grace. Fetch a fresh object.
            return(fetch);
        }
    }
    else
    {
        # backend is sick - use full grace
        if (obj.ttl + obj.grace > 0s)
        {
            #set req.http.grace = "full";
            return (deliver);
        }
        else
        {
            # no graced object.
            return (fetch);
        }
    }

    # fetch & deliver once we get the result
    return (fetch); # Dead code, keep as a safeguard
}

# 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);
}

 # Called after the response headers has been successfully retrieved from the backend.
sub vcl_backend_response
{
    # Enable ESI handling
    if (beresp.http.Surrogate-Control ~ "ESI/1.0" ) {
        set beresp.do_esi = true;
    }

    # Store the csrf_token cookie temporarily if the response is cacheabale
    if (beresp.http.Set-Cookie && !beresp.uncacheable)
    {
        set beresp.http.X-Varnish-Cookie = beresp.http.Set-Cookie;
        unset beresp.http.Set-Cookie;
    }

    # Cache handling all static files
    if (bereq.method == "GET")
    {
        # Before you blindly enable this, read: https://ma.ttias.be/stop-caching-static-files/
        #if (bereq.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|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. Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend
        # doesn't send a Content-Length header. Only enable it for large files
        if (bereq.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip|bz2|xz|7z|avi|mov|og[gvaxm]|mpe?g|mk[av])(\?.*)?$")
        {
            unset beresp.http.Set-Cookie;

            # Use streaming to avoid locking
            set beresp.do_stream = true;

            # Don't try to compress it for storage
            set beresp.do_gzip = false;

            # Disable Transfer-encoding chunked when serving HTML5 video
            # See : http://stackoverflow.com/questions/23643233/how-do-i-disable-transfer-encoding-chunked-encoding-in-varnish
            # See : https://www.varnish-cache.org/trac/ticket/1506
            if(beresp.http.Content-Type ~ "video") {
                set beresp.do_stream = true;
                set beresp.do_esi    = true;
            }
        }

        # 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);
        }
    }

    # 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]+", "");
    }

    # Do not cache errors from the backend
    if (beresp.status >= 400)
    {
        set beresp.uncacheable = true;
        set beresp.ttl = 0s;

        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;

    # Set ban-lurker friendly custom headers
    set beresp.http.X-Varnish-Url  = bereq.url;
    set beresp.http.X-Varnish-Host = bereq.http.host;

    return (deliver);
}

# Called when the backend returns an error
sub vcl_backend_error
{
    if (beresp.status == 503 && bereq.retries < 5)
    {
        set beresp.http.X-Varnish-Retries = bereq.retries;
        return(retry);
    }

    return(deliver);
}

# Called before a cached object is delivered to the client.
sub vcl_deliver
{
    # Send the Cookie header again if a temporay header was stored
    if (req.http.X-Varnish-Cookie) {
        set resp.http.Set-Cookie = req.http.X-Varnish-Cookie;
    }

    # Add extra headers if debugging is enabled
    if (resp.http.x-varnish-debug && server.ip ~ localhost)
    {
        set resp.http.X-Served-By = server.hostname;

        if (resp.http.x-varnish ~ " ") {
            set resp.http.X-Varnish-Status = "HIT";
        } else {
            set resp.http.X-Varnish-Status = "MISS";
        }

        # 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-Varnish-Hits = obj.hits;
    }
    else
    {
        # Remove ban-lurker friendly custom headers when delivering to client
        unset resp.http.X-Url;
        unset resp.http.X-Host;

        # Remove some headers: PHP version
        unset resp.http.X-Powered-By;

        # Remove some headers: Apache version & OS
        unset resp.http.Server;
        unset resp.http.Via;
        unset resp.http.Link;
        unset resp.http.X-Varnish;
        unset resp.http.X-Varnish-Tag;
        unset resp.http.X-Varnish-Debug;
        unset resp.http.X-Varnish-Host;
        unset resp.http.X-Varnish-Url;
        unset resp.http.X-Varnish-Retries;
        unset resp.http.X-Varnish-Cookie;
        unset resp.http.Surrogate-Control;
    }

    return (deliver);
}

sub vcl_purge
{
    # Only handle actual PURGE HTTP methods, everything else is discarded
    if (req.method != "PURGE" && server.ip ~ localhost)
    {
        set req.http.X-Varnish-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);
}

# Called when VCL is discarded only after all requests have exited the VCL. Typically used to clean up VMODs.
sub vcl_fini
{
  return (ok);
}