no need for checking GET method

no need for checking GET method

# Managed by saltstack.
# host id: {{ salt['grains.get']('id', '') }}
{% set settings = salt['pillar.get']('varnish', {}) -%}
{% set zinibu_basic = salt['pillar.get']('zinibu_basic', {}) -%}
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

import std;
import directors;

{%- for id, haproxy_server in zinibu_basic.project.haproxy_servers.iteritems() %}
backend bk_appsrv_static_{{ id }} {
  .host = "{{ haproxy_server.private_ip }}";
  .port = "{{ haproxy_server.port }}";
  .probe = {
    .url = "{{ zinibu_basic.project.haproxy_check }}";
    .expected_response = 200;
    .timeout = 1s;
    .interval = 3s;
    .window = 2;
    .threshold = 2;
    .initial = 2;
  }
}
{%- endfor %}

sub vcl_init {
    new bar = directors.round_robin();
{%- for id, haproxy_server in zinibu_basic.project.haproxy_servers.iteritems() %}
    bar.add_backend(bk_appsrv_static_{{ id }});
{%- endfor %}
}

acl purge {
    "localhost";
    "127.0.0.1";
}

sub vcl_recv {
    # Happens before we check if we have this in cache already.
    #
    # Typically you clean up the request here, removing cookies you don't need,
    # rewriting the request, etc.

    # debug bypass
    #return (pass);

    #std.log("vcl recv: "+req.request);

    # Health Checking
    if (req.url == "{{ zinibu_basic.project.varnish_check }}") {
        return (synth(751, "health check OK!"));
    }

    # send all traffic to the bar director:
    set req.backend_hint = bar.backend();

    # Normalize the header, remove the port (in case you're testing this on various TCP ports)
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    # Normalize the query arguments
    set req.url = std.querysort(req.url);

    # Allow purging
    if (req.method == "PURGE") {
        if (!client.ip ~ purge) { # purge is the ACL defined at the begining
	    # Not from an allowed IP? Then die with an error.
            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);
    }

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

    # Don't think is needed anymore, just check for sessionid cookie
    # Django is setting this cookie so we only check here
    #if (req.http.Cookie ~ "LOGGED_IN") {
    #  return (pass);
    #}

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

    set req.http.X-Varnish-Use-Cache = "TRUE";
    # unless Django's sessionid or message cookies are in the request, don't pass ANY cookies (referral_source, utm, etc)
    # also, anything inside /media or /static should be cached
    if (req.url ~ "^/media" || req.url ~ "^/static" || (req.http.Cookie !~ "sessionid" && req.http.Cookie !~ "messages" && req.http.Cookie !~ "csrftoken")) {
      unset req.http.Cookie;
      return (hash);
    }

    # Large static files are delivered directly to the end-user without
    # waiting for Varnish to fully read the file first.
    # Varnish 4 fully supports Streaming, so set do_stream in vcl_backend_response()
    if (req.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
      unset req.http.Cookie;
      return (hash);
    }

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

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

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

    if (req.http.Cache-Control ~ "(?i)no-cache") {
    #if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ editors) { # create the acl editors if you want to restrict the Ctrl-F5
      # 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)) {
        #set req.hash_always_miss = true; # Doesn't seems to refresh the object in the cache
        return(purge); # Couple this with restart in vcl_purge and X-Purge header to avoid loops
      }
    }

    # 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, "\?$", "");
    }

    return (hash);
}

sub vcl_pipe {
  # Called upon entering pipe mode.
  # In this mode, the request is passed on to the backend, and any further data from both the client
  # and backend is passed on unaltered until either end closes the connection. Basically, Varnish will
  # degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode,
  # no other VCL subroutine will ever get called after vcl_pipe.

  # Note that only the first request to the backend will have
  # X-Forwarded-For set.  If you use X-Forwarded-For and want to
  # have it set for all requests, make sure to have:
  # set bereq.http.connection = "close";
  # here.  It is not set by default as it might break some broken web
  # applications, like IIS with NTLM authentication.

  # set bereq.http.Connection = "Close";

  # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
  if (req.http.upgrade) {
    set bereq.http.upgrade = req.http.upgrade;
  }

  return (pipe);
}

sub vcl_pass {
  # Called upon entering pass mode. In this mode, the request is passed on to the backend, and the
  # backend's response is passed on to the client, but is not entered into the cache. Subsequent
  # requests submitted over the same client connection are handled normally.

  # return (pass);
}

sub vcl_hash {
    # 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.

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

    return (lookup);
}

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.

    # Called after the response headers has been successfully retrieved from the backend.
    # Enable ESI
    set beresp.do_esi = true;
    # and make sure everything under /no-cache is, well, not cached
    if (bereq.url ~ "^/no-cache/") {
      set beresp.uncacheable = true;
      return(deliver);
    }

    # Pause ESI request and remove Surrogate-Control header
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
      unset beresp.http.Surrogate-Control;
      set beresp.do_esi = true;
    }

    # 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;  # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects
      set beresp.do_gzip   = false;   # Don't try to compress it for storage
    }

    # 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; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend
      set beresp.uncacheable = true;

      # Study and test this
      # Mark as "Hit-For-Pass" for the next 60 minutes - 24 hours
      #if (bereq.url ~ "\.(jpe?g|png|gif|pdf|gz|tgz|bz2|tbz|tar|zip|tiff|tif)$" || bereq.url ~ "/(image|(image_(?:[^/]|(?!view.*).+)))$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 6h;
      #} elseif (bereq.url ~ "\.(svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|flv)$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 6h;
      #} elseif (bereq.url ~ "\.(xls|vsd|doc|ppt|pps|vsd|doc|ppt|pps|xls|pdf|sxw|rar|odc|odb|odf|odg|odi|odp|ods|odt|sxc|sxd|sxi|sxw|dmg|torrent|deb|msi|iso|rpm)$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 6h;
      #} elseif (bereq.url ~ "\.(css|js)$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 24h;
      #} else {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 1h;
      #}

      return (deliver);
    }

    # Don't cache 50x responses
    if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
      return (abandon);
    }

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

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.

    # Called before a cached object is delivered to the client.

    if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
      set resp.http.X-Cache = "HIT";
    } else {
      set resp.http.X-Cache = "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-Cache-Hits = obj.hits;

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

sub vcl_purge {
  # Only handle actual PURGE HTTP methods, everything else is discarded
  if (req.method != "PURGE") {
    # restart request
    set req.http.X-Purge = "Yes";
    return(restart);
  }
}

sub vcl_synth {
    # Health check
    if (resp.status == 751) {
        set resp.status = 200;
        return (deliver);
    }
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";
    synthetic ("Error");
    return (deliver);
}

# Managed by saltstack.
# host id: {{ salt['grains.get']('id', '') }}
{% set settings = salt['pillar.get']('varnish', {}) -%}
{% set zinibu_basic = salt['pillar.get']('zinibu_basic', {}) -%}
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and https://www.varnish-cache.org/trac/wiki/VCLExamples for more examples.

# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;

import std;
import directors;

{%- for id, haproxy_server in zinibu_basic.project.haproxy_servers.iteritems() %}
backend bk_appsrv_static_{{ id }} {
  .host = "{{ haproxy_server.private_ip }}";
  .port = "{{ haproxy_server.port }}";
  .probe = {
    .url = "{{ zinibu_basic.project.haproxy_check }}";
    .expected_response = 200;
    .timeout = 1s;
    .interval = 3s;
    .window = 2;
    .threshold = 2;
    .initial = 2;
  }
}
{%- endfor %}

sub vcl_init {
    new bar = directors.round_robin();
{%- for id, haproxy_server in zinibu_basic.project.haproxy_servers.iteritems() %}
    bar.add_backend(bk_appsrv_static_{{ id }});
{%- endfor %}
}

acl purge {
    "localhost";
    "127.0.0.1";
}

sub vcl_recv {
    # Happens before we check if we have this in cache already.
    #
    # Typically you clean up the request here, removing cookies you don't need,
    # rewriting the request, etc.

    # debug bypass
    #return (pass);

    #std.log("vcl recv: "+req.request);

    # Health Checking
    if (req.url == "{{ zinibu_basic.project.varnish_check }}") {
        return (synth(751, "health check OK!"));
    }

    # send all traffic to the bar director:
    set req.backend_hint = bar.backend();

    # Normalize the header, remove the port (in case you're testing this on various TCP ports)
    set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");

    # Normalize the query arguments
    set req.url = std.querysort(req.url);

    # Allow purging
    if (req.method == "PURGE") {
        if (!client.ip ~ purge) { # purge is the ACL defined at the begining
	    # Not from an allowed IP? Then die with an error.
            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);
    }

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

    # Don't think is needed anymore, just check for sessionid cookie
    # Django is setting this cookie so we only check here
    #if (req.http.Cookie ~ "LOGGED_IN") {
    #  return (pass);
    #}

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

    set req.http.X-Varnish-Use-Cache = "TRUE";
    # unless Django's sessionid or message cookies are in the request, don't pass ANY cookies (referral_source, utm, etc)
    # also, anything inside /media or /static should be cached
    if (req.method == "GET" && (req.url ~ "^/media" || req.url ~ "^/static" || (req.http.Cookie !~ "sessionid" && req.http.Cookie !~ "csrftoken" && req.http.Cookie !~ "messages"))) {
      unset req.http.Cookie;
      return (hash);
    }

    # Large static files are delivered directly to the end-user without
    # waiting for Varnish to fully read the file first.
    # Varnish 4 fully supports Streaming, so set do_stream in vcl_backend_response()
    if (req.url ~ "^[^?]*\.(7z|avi|bz2|flac|flv|gz|mka|mkv|mov|mp3|mp4|mpeg|mpg|ogg|ogm|opus|rar|tar|tgz|tbz|txz|wav|webm|xz|zip)(\?.*)?$") {
      unset req.http.Cookie;
      return (hash);
    }

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

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

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

    if (req.http.Cache-Control ~ "(?i)no-cache") {
    #if (req.http.Cache-Control ~ "(?i)no-cache" && client.ip ~ editors) { # create the acl editors if you want to restrict the Ctrl-F5
      # 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)) {
        #set req.hash_always_miss = true; # Doesn't seems to refresh the object in the cache
        return(purge); # Couple this with restart in vcl_purge and X-Purge header to avoid loops
      }
    }

    # 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, "\?$", "");
    }

    return (hash);
}

sub vcl_pipe {
  # Called upon entering pipe mode.
  # In this mode, the request is passed on to the backend, and any further data from both the client
  # and backend is passed on unaltered until either end closes the connection. Basically, Varnish will
  # degrade into a simple TCP proxy, shuffling bytes back and forth. For a connection in pipe mode,
  # no other VCL subroutine will ever get called after vcl_pipe.

  # Note that only the first request to the backend will have
  # X-Forwarded-For set.  If you use X-Forwarded-For and want to
  # have it set for all requests, make sure to have:
  # set bereq.http.connection = "close";
  # here.  It is not set by default as it might break some broken web
  # applications, like IIS with NTLM authentication.

  # set bereq.http.Connection = "Close";

  # Implementing websocket support (https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html)
  if (req.http.upgrade) {
    set bereq.http.upgrade = req.http.upgrade;
  }

  return (pipe);
}

sub vcl_pass {
  # Called upon entering pass mode. In this mode, the request is passed on to the backend, and the
  # backend's response is passed on to the client, but is not entered into the cache. Subsequent
  # requests submitted over the same client connection are handled normally.

  # return (pass);
}

sub vcl_hash {
    # 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.

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

    return (lookup);
}

sub vcl_backend_response {
    # Happens after we have read the response headers from the backend.
    #
    # Here you clean the response headers, removing silly Set-Cookie headers
    # and other mistakes your backend does.

    # Called after the response headers has been successfully retrieved from the backend.
    # Enable ESI
    set beresp.do_esi = true;
    # and make sure everything under /no-cache is, well, not cached
    if (bereq.url ~ "^/no-cache/") {
      set beresp.uncacheable = true;
      return(deliver);
    }

    # Pause ESI request and remove Surrogate-Control header
    if (beresp.http.Surrogate-Control ~ "ESI/1.0") {
      unset beresp.http.Surrogate-Control;
      set beresp.do_esi = true;
    }

    # 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;  # Check memory usage it'll grow in fetch_chunksize blocks (128k by default) if the backend doesn't send a Content-Length header, so only enable it for big objects
      set beresp.do_gzip   = false;   # Don't try to compress it for storage
    }

    # 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; # Important, you shouldn't rely on this, SET YOUR HEADERS in the backend
      set beresp.uncacheable = true;

      # Study and test this
      # Mark as "Hit-For-Pass" for the next 60 minutes - 24 hours
      #if (bereq.url ~ "\.(jpe?g|png|gif|pdf|gz|tgz|bz2|tbz|tar|zip|tiff|tif)$" || bereq.url ~ "/(image|(image_(?:[^/]|(?!view.*).+)))$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 6h;
      #} elseif (bereq.url ~ "\.(svg|swf|ico|mp3|mp4|m4a|ogg|mov|avi|wmv|flv)$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 6h;
      #} elseif (bereq.url ~ "\.(xls|vsd|doc|ppt|pps|vsd|doc|ppt|pps|xls|pdf|sxw|rar|odc|odb|odf|odg|odi|odp|ods|odt|sxc|sxd|sxi|sxw|dmg|torrent|deb|msi|iso|rpm)$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 6h;
      #} elseif (bereq.url ~ "\.(css|js)$") {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 24h;
      #} else {
      #    set beresp.ttl = std.duration(beresp.http.age+"s",0s) + 1h;
      #}

      return (deliver);
    }

    # Don't cache 50x responses
    if (beresp.status == 500 || beresp.status == 502 || beresp.status == 503 || beresp.status == 504) {
      return (abandon);
    }

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

sub vcl_deliver {
    # Happens when we have all the pieces we need, and are about to send the
    # response to the client.
    #
    # You can do accounting or modifying the final object here.

    # Called before a cached object is delivered to the client.

    if (obj.hits > 0) { # Add debug header to see if it's a HIT/MISS and the number of hits, disable when not needed
      set resp.http.X-Cache = "HIT";
    } else {
      set resp.http.X-Cache = "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-Cache-Hits = obj.hits;

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

sub vcl_purge {
  # Only handle actual PURGE HTTP methods, everything else is discarded
  if (req.method != "PURGE") {
    # restart request
    set req.http.X-Purge = "Yes";
    return(restart);
  }
}

sub vcl_synth {
    # Health check
    if (resp.status == 751) {
        set resp.status = 200;
        return (deliver);
    }
    set resp.http.Content-Type = "text/html; charset=utf-8";
    set resp.http.Retry-After = "5";
    synthetic ("Error");
    return (deliver);
}


Update openstreetmap4.vcl

Update openstreetmap4.vcl

# VCL script for varnish 4

vcl 4.0;

backend default {
  .host = "127.0.0.1";
  .port = "80";
}

backend a_tile {
  .host = "a.tile.openstreetmap.org";
  .port = "80";
}

backend b_tile {
  .host = "b.tile.openstreetmap.org";
  .port = "80";
}

backend c_tile {
  .host = "c.tile.openstreetmap.org";
  .port = "80";
}

sub vcl_recv {

  if (req.http.host ~ "^a.tile") {
    set req.backend_hint = a_tile;
  } else if (req.http.host ~ "^b.tile") {
    set req.backend_hint = b_tile;
  } else if (req.http.host ~ "^c.tile") {
    set req.backend_hint = c_tile;
  } else if (req.http.host ~ "^a.map") {
    set req.backend_hint = a_tile;
  } else if (req.http.host ~ "^b.map") {
    set req.backend_hint = b_tile;
  } else if (req.http.host ~ "^c.map") {
    set req.backend_hint = c_tile;
  }

  unset req.http.cookie;

  // Cache everything
  if (req.method == "GET") {
    return (hash);
  }

}

sub vcl_backend_response {

  // Cache tiles for 3 weeks
  set beresp.ttl = 3w;

  // Remove all cookies
  unset beresp.http.set-cookie;
  unset beresp.http.cookie;

}

sub vcl_deliver {

  if (obj.hits > 0) {
    set resp.http.X-Cache_v = "HIT";
  } else {
    set resp.http.X-Cache_v = "MISS";
  }
}

sub vcl_hash {

  // Cache using only url as a hash.
  // This means if a.tile/1/1/1/tile.png is accessed, b.tile/1/1/1/tile.png will also be fetch from cache
  hash_data(req.url);
  return (lookup);
}

# VCL script for varnish 4

vcl 4.0;

backend default {
  .host = "127.0.0.1";
  .port = "80";
}

backend a_tile {
  .host = "a.tile.openstreetmap.org";
  .port = "80";
}

backend b_tile {
  .host = "b.tile.openstreetmap.org";
  .port = "80";
}

backend c_tile {
  .host = "c.tile.openstreetmap.org";
  .port = "80";
}

sub vcl_recv {

  if (req.http.host ~ "^a.tile") {
    set req.backend_hint = a_tile;
  } else if (req.http.host ~ "^b.tile") {
    set req.backend_hint = b_tile;
  } else if (req.http.host ~ "^c.tile") {
    set req.backend_hint = c_tile;
  } else if (req.http.host ~ "^a.map") {
    set req.backend_hint = a_tile;
  } else if (req.http.host ~ "^b.map") {
    set req.backend_hint = b_tile;
  } else if (req.http.host ~ "^c.map") {
    set req.backend_hint = c_tile;
  }

  unset req.http.cookie;

  // Cache everything
  if (req.method == "GET") {
    return (hash);
  }

}

sub vcl_backend_response {

  // Cache tiles for 3 weeks
  set beresp.ttl = 3w;

  // Remove all cookies
  unset beresp.http.set-cookie;
  unset beresp.http.cookie;

}

sub vcl_deliver {

  if (obj.hits > 0) {
    set resp.http.X-Cache_v = "HIT";
  } else {
    set resp.http.X-Cache_v = "MISS";
  }
}

sub vcl_hash {

  // Cache using only url as a hash.
  // This means if a.tile/1/1/1/tile.png is access, b.tile/1/1/1/tile.png will also be fetch from cache
  hash_data(req.url);
  return (lookup);
}


Strip off Google Adwords, Mailchip etc. tracking query parameters

    # Fixup for Varnish ESI not dealing with https:// absolute URLs well
    if (req.is_esi_subreq && req.url ~ "/https://([^/]+)(/.*)$") {
        set req.http.Host = re.group.1;
        set req.url = re.group.2;
    }

    # Sort the query arguments
    set req.url = boltsort.sort(req.url);

    # bypass language switcher
    if (req.url ~ "(?i)___from_store=.*&___store=.*") {
        set req.http.X-Pass = "1";
    }

    # set HTTPS header for offloaded TLS
    if (req.http.Fastly-SSL) {
        set req.http.Https = "on";
    }

    if (req.http.cookie:FASTLY_CDN_ENV) {
        set req.http.Fastly-Cdn-Env = req.http.cookie:FASTLY_CDN_ENV;
    } else {
        unset req.http.Fastly-Cdn-Env;
    }

    # auth for purging
    if (req.request == "FASTLYPURGE") {

        if (!req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) {
            error 403;
        }

        declare local var.X-Exp STRING;
        declare local var.X-Sig STRING;
        /* extract token expiration and signature */
        set var.X-Exp = re.group.1;
        set var.X-Sig = re.group.2;

        /* validate signature */
        if (var.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path var.X-Exp), "^0x", "")) {
            /* check that expiration time has not elapsed */
            if (time.is_after(now, std.integer2time(std.atoi(var.X-Exp)))) {
                error 410;
            }

        } else {
            error 403;
        }

    }

    # disable ESI processing on Origin Shield
    if (req.http.Fastly-FF) {
        set req.esi = false;
        # Needed for proper handling of stale while revalidated when shielding is involved
        set req.max_stale_while_revalidate = 0s;
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # formkey lookup
    if (req.url ~ "/fastlycdn/getformkey/") {
        # check if we have a formkey cookie
        if (req.http.Cookie:FASTLY_CDN_FORMKEY) {
            set req.http.Formkey = req.http.Cookie:FASTLY_CDN_FORMKEY;
        } else {
            # create formkey
            set req.http.seed = req.http.Cookie client.ip remote.port geoip.longitude geoip.latitude geoip.postal_code;
            set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", "");
        }
        error 760 req.http.Formkey;
    }

    # geoip lookup
    if (req.url ~ "fastlycdn/esi/getcountry/") {
        # check if GeoIP has been already processed by client
        if (req.http.Cookie:FASTLY_CDN_GEOIP_PROCESSED) {
            error 200 "";
        } else {
            # modify req.url and restart request processing
            error 750 geoip.country_code;
        }
    }

    # geoip get country code
    if (req.url ~ "fastlycdn/esi/getcountrycode/") {
        # create and set req.http.X-Country-Code
        error 755 geoip.country_code;
    }

    # check for ESI calls
    if (req.url ~ "esi_data=") {
        # check for valid cookie data
        if (req.http.Cookie ~ "FASTLY_CDN-([A-Za-z0-9-_]+)=([^;]*)") {
            set req.url = querystring.filter(req.url, "esi_data") + "&esi_data=" + re.group.2;
        }
    }

    # Per suggestions in https://github.com/sdinteractive/SomethingDigital_PageCacheParams
    # we'll strip out query parameters used in Google AdWords, Mailchimp tracking
    set req.http.Magento-Original-URL = req.url;
    set req.url = querystring.regfilter(req.url, "^(utm_.*|gclid|gdftrk|_ga|mc_.*)");

    # If object has been marked as pass pass it
    if ( req.http.X-Pass ) {
        return(pass);
    }

    # Fixup for Varnish ESI not dealing with https:// absolute URLs well
    if (req.is_esi_subreq && req.url ~ "/https://([^/]+)(/.*)$") {
        set req.http.Host = re.group.1;
        set req.url = re.group.2;
    }

    # Sort the query arguments
    set req.url = boltsort.sort(req.url);

    # bypass language switcher
    if (req.url ~ "(?i)___from_store=.*&___store=.*") {
        set req.http.X-Pass = "1";
    }

    # set HTTPS header for offloaded TLS
    if (req.http.Fastly-SSL) {
        set req.http.Https = "on";
    }

    if (req.http.cookie:FASTLY_CDN_ENV) {
        set req.http.Fastly-Cdn-Env = req.http.cookie:FASTLY_CDN_ENV;
    } else {
        unset req.http.Fastly-Cdn-Env;
    }

    # auth for purging
    if (req.request == "FASTLYPURGE") {

        if (!req.http.X-Purge-Token ~ "^([^_]+)_(.*)" ) {
            error 403;
        }

        declare local var.X-Exp STRING;
        declare local var.X-Sig STRING;
        /* extract token expiration and signature */
        set var.X-Exp = re.group.1;
        set var.X-Sig = re.group.2;

        /* validate signature */
        if (var.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path var.X-Exp), "^0x", "")) {
            /* check that expiration time has not elapsed */
            if (time.is_after(now, std.integer2time(std.atoi(var.X-Exp)))) {
                error 410;
            }

        } else {
            error 403;
        }

    }

    # disable ESI processing on Origin Shield
    if (req.http.Fastly-FF) {
        set req.esi = false;
        # Needed for proper handling of stale while revalidated when shielding is involved
        set req.max_stale_while_revalidate = 0s;
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # formkey lookup
    if (req.url ~ "/fastlycdn/getformkey/") {
        # check if we have a formkey cookie
        if (req.http.Cookie:FASTLY_CDN_FORMKEY) {
            set req.http.Formkey = req.http.Cookie:FASTLY_CDN_FORMKEY;
        } else {
            # create formkey
            set req.http.seed = req.http.Cookie client.ip remote.port geoip.longitude geoip.latitude geoip.postal_code;
            set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", "");
        }
        error 760 req.http.Formkey;
    }

    # geoip lookup
    if (req.url ~ "fastlycdn/esi/getcountry/") {
        # check if GeoIP has been already processed by client
        if (req.http.Cookie:FASTLY_CDN_GEOIP_PROCESSED) {
            error 200 "";
        } else {
            # modify req.url and restart request processing
            error 750 geoip.country_code;
        }
    }

    # geoip get country code
    if (req.url ~ "fastlycdn/esi/getcountrycode/") {
        # create and set req.http.X-Country-Code
        error 755 geoip.country_code;
    }

    # check for ESI calls
    if (req.url ~ "esi_data=") {
        # check for valid cookie data
        if (req.http.Cookie ~ "FASTLY_CDN-([A-Za-z0-9-_]+)=([^;]*)") {
            set req.url = querystring.filter(req.url, "esi_data") + "&esi_data=" + re.group.2;
        }
    }

    # If object has been marked as pass pass it
    if ( req.http.X-Pass ) {
        return(pass);
    }


update varnish configuration file. :fire:

vcl 4.0;

import directors;

backend server_rails {
  .host = "127.0.0.1";
  .port = "8080";
}

sub vcl_init {
  new load_balancing_servers = directors.random();
  load_balancing_servers.add_backend(server_rails,10);
}

sub vcl_recv {
  if (req.method != "GET"   &&
    req.method != "HEAD"    &&
    req.method != "PUT"     &&
    req.method != "POST"    &&
    req.method != "TRACE"   &&
    req.method != "OPTIONS" &&
    req.method != "DELETE") {
      return (pipe);
    }

    if ((req.method == "POST" || req.method == "PUT") &&
      req.http.transfer-encoding ~ "chunked") {
        return(pipe);
      }

      if (req.method != "GET" && req.method != "HEAD") {
        return (pass);
      }

      if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|jpeg|bmp|swf|png|gif|gz|tgz|bz2|tbz|mp3|ogg|ico|pdf|cur)$") {
            # 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 {
          unset req.http.Accept-Encoding;
        }
     }

     set req.backend_hint = load_balancing_servers.backend();
     unset req.http.Cookie;

     return (hash);
}

sub vcl_pipe {
  return (pipe);
}

sub vcl_pass {
  return (fetch);
}

sub vcl_backend_response {
  #  set beresp.grace = 1h;
  set beresp.ttl = 5m;

  if (beresp.status != 200 && beresp.status != 403 && beresp.status != 404 && beresp.status != 301 && beresp.status != 302 && beresp.status != 503) {
     # set beresp.saintmode = 10s;
    return (retry);
  }
  unset beresp.http.set-cookie;
  return (deliver);
}

sub vcl_hash {
  hash_data(req.url);
    if (req.http.host) {
      hash_data(req.http.host);
    } else {
      hash_data(server.ip);
    }
    return (lookup);
}

sub vcl_deliver {
  unset resp.http.X-Varnish;
  unset resp.http.via;
  unset resp.http.Age;

  if (obj.hits > 0) {
    set resp.http.Cache = "H";
  }
  else {
    set resp.http.Cache = "M";
  }
  return (deliver);
}

sub vcl_hit {
  return (deliver);
}

sub vcl_miss {
  return (fetch);
}

sub vcl_backend_error {
   set beresp.http.Content-Type = "text/html; charset=utf-8";
   set beresp.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>"} + beresp.status + " " + beresp.reason + {"</title>

Error "} + beresp.status + " " + beresp.reason + {"

"} + beresp.reason + {"

Guru Meditation:

XID: "} + bereq.xid + {"

Squid cache server

 "});
  return (deliver);
}

sub vcl_synth {
  set resp.http.Content-Type = "text/html; charset=utf-8";
  set resp.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>"} + resp.status + " " + resp.reason + {"</title>

Error "} + resp.status + " " + resp.reason + {"

"} + resp.reason + {"

Guru Meditation:

XID: "} + req.xid + {"

Squid cache server

 "});
  return (deliver);
}

sub vcl_fini {
  return (ok);
}


Enable GZipping on origin

Enable GZipping on origin

###############################################################################
#
# Fastly CDN for Magento
#
# NOTICE OF LICENSE
#
# This source file is subject to the Fastly CDN for Magento End User License
# Agreement that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
#
# @copyright   Copyright (c) 2015 Fastly, Inc. (http://www.fastly.com)
# @license     BSD, see LICENSE_FASTLY_CDN.txt
#
###############################################################################

# This is a basic VCL configuration file for fastly CDN for Magento module.

sub vcl_recv {
#FASTLY recv
    # we only deal with GET and HEAD by default
    if (req.request != "GET" && req.request != "HEAD"  && req.request != "FASTLYPURGE") {
        return (pass);
    }

    # auth for purging
    if (req.request == "FASTLYPURGE") {
        # extract token signature and expiration
        set req.http.X-Sig = regsub(req.http.X-Purge-Token, "^[^_]+_(.*)", "\1");
        set req.http.X-Exp = regsub(req.http.X-Purge-Token, "^([^_]+)_.*", "\1");

        # validate signature
        if (req.http.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path req.http.X-Exp), "^0x", "")) {

            # use vcl time math to check expiration timestamp
            set req.http.X-Original-Grace = req.grace;
            set req.grace = std.atoi(strftime({"%s"}, now));
            set req.grace -= std.atoi(req.http.X-Exp);

            if (std.atoi(req.grace) > 0) {
                error 410;
            }

            # clean up grace since we used it for time math
            set req.grace = std.atoi(req.http.X-Original-Grace);
            unset req.http.X-Original-Grace;

        } else {
            error 403;
        }

        # cleanup variables
        unset req.http.X-Purge-Token;
        unset req.http.X-Sig;
        unset req.http.X-Exp;
    }

    # set HTTPS header for offloaded TLS
    if (req.http.Fastly-SSL) {
        set req.http.Https = "on";
    }

    # disable ESI processing on Origin Shield
    if (req.http.Fastly-FF) {
        set req.esi = false;
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # formkey lookup
    if (req.url ~ "/fastlycdn/getformkey/") {
        # check if we have a formkey cookie
        if (req.http.Cookie ~ "FASTLY_CDN_FORMKEY") {
            set req.http.Formkey = regsub(req.http.cookie, ".*FASTLY_CDN_FORMKEY=([^;]*)(;*.*)?", "\1");
        } else {
            # create formkey
            set req.http.seed = req.http.Cookie client.ip remote.port geoip.longitude geoip.latitude geoip.postal_code;
            set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", "");
        }
        error 760 req.http.Formkey;
    }

    # geoip lookup
    if (req.url ~ "fastlycdn/esi/getcountry/") {
        # check if GeoIP has been already processed by client
        if (req.http.Cookie ~ "FASTLY_CDN_GEOIP_PROCESSED") {
            error 200 "";
        } else {
            # modify req.url and restart request processing
            error 750 geoip.country_code;
        }
    }

    # geoip get country code
    if (req.url ~ "fastlycdn/esi/getcountrycode/") {
        # create and set req.http.X-Country-Code
        error 755 geoip.country_code;
    }

    # check for ESI calls
     if (req.url ~ "esi_data=") {
         # check for valid cookie data
         if (req.http.Cookie ~ "FASTLY_CDN-") {
             # get the cookie name to look for
             set req.http.fastlyCDNEsiCookieName = regsub(
                 req.url,
                 "(.*)esi_data=([^&]*)(.*)",
                 "\2"
             );

             # get the cookie value for the cookie name
             # tmp string is NAMESPACE-COOKIENAME@@@@@COMPLETE_COOKIE
             # left of @@@@@ is back-referenced in regex to extract value from cookie
             set req.http.fastlyTmp = "FASTLY_CDN-" req.http.fastlyCDNEsiCookieName "@@@@@" req.http.Cookie;
             set req.http.fastlyCDNRequest = regsub(
                 req.http.fastlyTmp,
                 "^([A-Za-z0-9-_]+)@@@@@.*\1=([^;]*)",
                 "\2"
             );

             # do we have a value for the cookie name?
             if (!req.http.fastlyCDNRequest) {
                 set req.http.fastlyCDNRequest = "default";
             }

             # build backend url
             set req.url = regsub(
                   req.url,
                   "(.*)esi_data=([^&]*)[&]?(.*)",
                   "\1\3"
                 )
                 "&esi_data="
                 req.http.fastlyCDNRequest;

             # clean up temp variables
             remove req.http.fastlyCDNEsiCookieName;
             remove req.http.fastlyCDNRequest;

             return (lookup);
         }
     }

    return(lookup);
}

sub vcl_pass {
#FASTLY pass
}

sub vcl_hash {
    set req.hash += req.http.Https;
    set req.hash += req.http.host;
    set req.hash += req.url;

    if (req.http.cookie ~ "FASTLY_CDN_ENV=") {
        set req.http.fastlyCDNEnv = regsub(
            req.http.cookie,
            "(.*)FASTLY_CDN_ENV=([^;]*)(.*)",
            "\2"
        );
        set req.hash += req.http.fastlyCDNEnv;
        unset req.http.fastlyCDNEnv;
    }

    set req.hash += "#####GENERATION#####";

    if (!(req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$")) {
        call design_exception;
    }
    return (hash);
}

sub vcl_hit {
#FASTLY hit

    if (!obj.cacheable) {
        return(pass);
    }
    return(deliver);
}

sub vcl_miss {
    # Deactivate gzip on origin
    unset bereq.http.Accept-Encoding;

#FASTLY miss

    return(fetch);
}

sub vcl_fetch {
#FASTLY fetch

    if (beresp.status >= 500) {
        # let SOAP errors pass - better debugging
        if (beresp.http.Content-Type ~ "text/xml") {
            return (deliver);
        }

        if (req.restarts < 1 && (req.request == "GET" || req.request == "HEAD")) {
            restart;
        }
    }

    if (req.restarts > 0 ) {
        set beresp.http.Fastly-Restarts = req.restarts;
    }

    if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {
        # enable ESI feature for Magento response by default
        esi;
    } else {
        # enable gzip for all static content
        if ((beresp.status == 200 || beresp.status == 404) && (beresp.http.content-type ~ "^(application\/x\-javascript|text\/css|application\/javascript|text\/javascript|application\/json|application\/vnd\.ms\-fontobject|application\/x\-font\-opentype|application\/x\-font\-truetype|application\/x\-font\-ttf|application\/xml|font\/eot|font\/opentype|font\/otf|image\/svg\+xml|image\/vnd\.microsoft\.icon|text\/plain)\s*($|;)" || req.url ~ "\.(css|js|html|eot|ico|otf|ttf|json)($|\?)" ) ) {
            # always set vary to make sure uncompressed versions dont always win
            if (!beresp.http.Vary ~ "Accept-Encoding") {
                if (beresp.http.Vary) {
                    set beresp.http.Vary = beresp.http.Vary ", Accept-Encoding";
                } else {
                    set beresp.http.Vary = "Accept-Encoding";
                }
            }
            if (req.http.Accept-Encoding == "gzip") {
                set beresp.gzip = true;
            }
        }
    }

    if (beresp.http.Cache-Control ~ "private") {
        set req.http.Fastly-Cachetype = "PRIVATE";
        return (pass);
    }

    if (beresp.status == 500 || beresp.status == 503) {
        set req.http.Fastly-Cachetype = "ERROR";
        set beresp.ttl = 1s;
        set beresp.grace = 5s;
        return (deliver);
    }

    if (beresp.status == 200 || beresp.status == 301 || beresp.status == 404) {
        if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {
            # marker for vcl_deliver to reset Age:
            set beresp.http.magentomarker = "1";

            # Don't cache cookies
            unset beresp.http.set-cookie;
        } else {
            if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
                # keep the ttl here
            } else {
                # apply the default ttl
                set beresp.ttl = 3600s;
            }
        }

        # init surrogate keys
        if (beresp.http.Surrogate-Key) {
            set beresp.http.Surrogate-Key = beresp.http.Surrogate-Key " text";
        } else {
            set beresp.http.Surrogate-Key = "text";
        }

        # set surrogate keys by content type
        if (beresp.http.Content-Type ~ "image") {
            set beresp.http.Surrogate-Key = "image";
        } elsif (beresp.http.Content-Type ~ "script") {
            set beresp.http.Surrogate-Key = "script";
        } elsif (beresp.http.Content-Type ~ "css") {
            set beresp.http.Surrogate-Key = "css";
        }

        set beresp.http.X-Surrogate-Key = beresp.http.Surrogate-Key;
    }

    return (deliver);
}

sub vcl_deliver {
    # debug info
    if (resp.http.X-Cache-Debug) {
        if (obj.hits > 0) {
            set resp.http.X-Cache      = "HIT";
            set resp.http.X-Cache-Hits = obj.hits;
        } else {
            set resp.http.X-Cache      = "MISS";
        }
        set resp.http.X-Cache-Expires  = resp.http.Expires;
    } else {
        # remove Varnish/proxy header
        remove resp.http.X-Varnish;
        remove resp.http.Via;
        remove resp.http.Age;
        remove resp.http.X-Purge-URL;
        remove resp.http.X-Purge-Host;
        remove resp.http.X-Surrogate-Key;
    }

    if (resp.http.magentomarker) {
        # Remove the magic marker
        unset resp.http.magentomarker;

        set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
        set resp.http.Pragma        = "no-cache";
        set resp.http.Expires       = "Mon, 31 Mar 2008 10:00:00 GMT";
        set resp.http.Age           = "0";
    }

#FASTLY deliver

    return (deliver);
}

sub vcl_error {
    # workaround for possible security issue
    if (req.url ~ "^\s") {
        set obj.status = 400;
        set obj.response = "Malformed request";
        synthetic "";
        return (deliver);
    }

    # geo ip request
    if (obj.status == 750) {
        set req.url = regsub(req.url, "(/fastlycdn/esi/getcountry/.*)", "/fastlycdn/esi/getcountryaction/?country_code=") obj.response;
        return (restart);
    }

    # geo ip country code
    if (obj.status == 755) {
        set obj.status = 200;
	    synthetic obj.response;
        return(deliver);
    }

    # formkey request
    if (obj.status == 760) {
        set obj.status = 200;
	    synthetic obj.response;
        return (deliver);
    }

    # error 200
    if (obj.status == 200) {
        return (deliver);
    }

     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 {"

Fastly CDN server

"};

#FASTLY error
}

sub design_exception {
}

###############################################################################
#
# Fastly CDN for Magento
#
# NOTICE OF LICENSE
#
# This source file is subject to the Fastly CDN for Magento End User License
# Agreement that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
#
# @copyright   Copyright (c) 2015 Fastly, Inc. (http://www.fastly.com)
# @license     BSD, see LICENSE_FASTLY_CDN.txt
#
###############################################################################

# This is a basic VCL configuration file for fastly CDN for Magento module.

sub vcl_recv {
#FASTLY recv
    # we only deal with GET and HEAD by default
    if (req.request != "GET" && req.request != "HEAD"  && req.request != "FASTLYPURGE") {
        return (pass);
    }

    # auth for purging
    if (req.request == "FASTLYPURGE") {
        # extract token signature and expiration
        set req.http.X-Sig = regsub(req.http.X-Purge-Token, "^[^_]+_(.*)", "\1");
        set req.http.X-Exp = regsub(req.http.X-Purge-Token, "^([^_]+)_.*", "\1");

        # validate signature
        if (req.http.X-Sig == regsub(digest.hmac_sha1(req.service_id, req.url.path req.http.X-Exp), "^0x", "")) {

            # use vcl time math to check expiration timestamp
            set req.http.X-Original-Grace = req.grace;
            set req.grace = std.atoi(strftime({"%s"}, now));
            set req.grace -= std.atoi(req.http.X-Exp);

            if (std.atoi(req.grace) > 0) {
                error 410;
            }

            # clean up grace since we used it for time math
            set req.grace = std.atoi(req.http.X-Original-Grace);
            unset req.http.X-Original-Grace;

        } else {
            error 403;
        }

        # cleanup variables
        unset req.http.X-Purge-Token;
        unset req.http.X-Sig;
        unset req.http.X-Exp;
    }

    # set HTTPS header for offloaded TLS
    if (req.http.Fastly-SSL) {
        set req.http.Https = "on";
    }

    # disable ESI processing on Origin Shield
    if (req.http.Fastly-FF) {
        set req.esi = false;
    }

    # static files are always cacheable. remove SSL flag and cookie
    if (req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$") {
        unset req.http.Https;
        unset req.http.Cookie;
    }

    # formkey lookup
    if (req.url ~ "/fastlycdn/getformkey/") {
        # check if we have a formkey cookie
        if (req.http.Cookie ~ "FASTLY_CDN_FORMKEY") {
            set req.http.Formkey = regsub(req.http.cookie, ".*FASTLY_CDN_FORMKEY=([^;]*)(;*.*)?", "\1");
        } else {
            # create formkey
            set req.http.seed = req.http.Cookie client.ip remote.port geoip.longitude geoip.latitude geoip.postal_code;
            set req.http.Formkey = regsub(digest.hash_md5(req.http.seed), "^0x", "");
        }
        error 760 req.http.Formkey;
    }

    # geoip lookup
    if (req.url ~ "fastlycdn/esi/getcountry/") {
        # check if GeoIP has been already processed by client
        if (req.http.Cookie ~ "FASTLY_CDN_GEOIP_PROCESSED") {
            error 200 "";
        } else {
            # modify req.url and restart request processing
            error 750 geoip.country_code;
        }
    }

    # geoip get country code
    if (req.url ~ "fastlycdn/esi/getcountrycode/") {
        # create and set req.http.X-Country-Code
        error 755 geoip.country_code;
    }

    # check for ESI calls
     if (req.url ~ "esi_data=") {
         # check for valid cookie data
         if (req.http.Cookie ~ "FASTLY_CDN-") {
             # get the cookie name to look for
             set req.http.fastlyCDNEsiCookieName = regsub(
                 req.url,
                 "(.*)esi_data=([^&]*)(.*)",
                 "\2"
             );

             # get the cookie value for the cookie name
             # tmp string is NAMESPACE-COOKIENAME@@@@@COMPLETE_COOKIE
             # left of @@@@@ is back-referenced in regex to extract value from cookie
             set req.http.fastlyTmp = "FASTLY_CDN-" req.http.fastlyCDNEsiCookieName "@@@@@" req.http.Cookie;
             set req.http.fastlyCDNRequest = regsub(
                 req.http.fastlyTmp,
                 "^([A-Za-z0-9-_]+)@@@@@.*\1=([^;]*)",
                 "\2"
             );

             # do we have a value for the cookie name?
             if (!req.http.fastlyCDNRequest) {
                 set req.http.fastlyCDNRequest = "default";
             }

             # build backend url
             set req.url = regsub(
                   req.url,
                   "(.*)esi_data=([^&]*)[&]?(.*)",
                   "\1\3"
                 )
                 "&esi_data="
                 req.http.fastlyCDNRequest;

             # clean up temp variables
             remove req.http.fastlyCDNEsiCookieName;
             remove req.http.fastlyCDNRequest;

             return (lookup);
         }
     }

    return(lookup);
}

sub vcl_pass {
#FASTLY pass
}

sub vcl_hash {
    set req.hash += req.http.Https;
    set req.hash += req.http.host;
    set req.hash += req.url;

    if (req.http.cookie ~ "FASTLY_CDN_ENV=") {
        set req.http.fastlyCDNEnv = regsub(
            req.http.cookie,
            "(.*)FASTLY_CDN_ENV=([^;]*)(.*)",
            "\2"
        );
        set req.hash += req.http.fastlyCDNEnv;
        unset req.http.fastlyCDNEnv;
    }

    set req.hash += "#####GENERATION#####";

    if (!(req.url ~ "^/(media|js|skin)/.*\.(png|jpg|jpeg|gif|css|js|swf|ico)$")) {
        call design_exception;
    }
    return (hash);
}

sub vcl_hit {
#FASTLY hit

    if (!obj.cacheable) {
        return(pass);
    }
    return(deliver);
}

sub vcl_miss {
#FASTLY miss

    return(fetch);
}

sub vcl_fetch {
#FASTLY fetch

    if (beresp.status >= 500) {
        # let SOAP errors pass - better debugging
        if (beresp.http.Content-Type ~ "text/xml") {
            return (deliver);
        }

        if (req.restarts < 1 && (req.request == "GET" || req.request == "HEAD")) {
            restart;
        }
    }

    if (req.restarts > 0 ) {
        set beresp.http.Fastly-Restarts = req.restarts;
    }

    if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {
        # enable ESI feature for Magento response by default
        esi;
    }

    if (beresp.http.Cache-Control ~ "private") {
        set req.http.Fastly-Cachetype = "PRIVATE";
        return (pass);
    }

    if (beresp.status == 500 || beresp.status == 503) {
        set req.http.Fastly-Cachetype = "ERROR";
        set beresp.ttl = 1s;
        set beresp.grace = 5s;
        return (deliver);
    }

    if (beresp.status == 200 || beresp.status == 301 || beresp.status == 404) {
        if (beresp.http.Content-Type ~ "text/html" || beresp.http.Content-Type ~ "text/xml") {
            # marker for vcl_deliver to reset Age:
            set beresp.http.magentomarker = "1";

            # Don't cache cookies
            unset beresp.http.set-cookie;
        } else {
            if (beresp.http.Expires || beresp.http.Surrogate-Control ~ "max-age" || beresp.http.Cache-Control ~ "(s-maxage|max-age)") {
                # keep the ttl here
            } else {
                # apply the default ttl
                set beresp.ttl = 3600s;
            }
        }

        # init surrogate keys
        if (beresp.http.Surrogate-Key) {
            set beresp.http.Surrogate-Key = beresp.http.Surrogate-Key " text";
        } else {
            set beresp.http.Surrogate-Key = "text";
        }

        # set surrogate keys by content type
        if (beresp.http.Content-Type ~ "image") {
            set beresp.http.Surrogate-Key = "image";
        } elsif (beresp.http.Content-Type ~ "script") {
            set beresp.http.Surrogate-Key = "script";
        } elsif (beresp.http.Content-Type ~ "css") {
            set beresp.http.Surrogate-Key = "css";
        }

        set beresp.http.X-Surrogate-Key = beresp.http.Surrogate-Key;
    }

    return (deliver);
}

sub vcl_deliver {
    # debug info
    if (resp.http.X-Cache-Debug) {
        if (obj.hits > 0) {
            set resp.http.X-Cache      = "HIT";
            set resp.http.X-Cache-Hits = obj.hits;
        } else {
            set resp.http.X-Cache      = "MISS";
        }
        set resp.http.X-Cache-Expires  = resp.http.Expires;
    } else {
        # remove Varnish/proxy header
        remove resp.http.X-Varnish;
        remove resp.http.Via;
        remove resp.http.Age;
        remove resp.http.X-Purge-URL;
        remove resp.http.X-Purge-Host;
        remove resp.http.X-Surrogate-Key;
    }

    if (resp.http.magentomarker) {
        # Remove the magic marker
        unset resp.http.magentomarker;

        set resp.http.Cache-Control = "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
        set resp.http.Pragma        = "no-cache";
        set resp.http.Expires       = "Mon, 31 Mar 2008 10:00:00 GMT";
        set resp.http.Age           = "0";
    }

#FASTLY deliver

    return (deliver);
}

sub vcl_error {
    # workaround for possible security issue
    if (req.url ~ "^\s") {
        set obj.status = 400;
        set obj.response = "Malformed request";
        synthetic "";
        return (deliver);
    }

    # geo ip request
    if (obj.status == 750) {
        set req.url = regsub(req.url, "(/fastlycdn/esi/getcountry/.*)", "/fastlycdn/esi/getcountryaction/?country_code=") obj.response;
        return (restart);
    }

    # geo ip country code
    if (obj.status == 755) {
        set obj.status = 200;
	    synthetic obj.response;
        return(deliver);
    }

    # formkey request
    if (obj.status == 760) {
        set obj.status = 200;
	    synthetic obj.response;
        return (deliver);
    }

    # error 200
    if (obj.status == 200) {
        return (deliver);
    }

     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 {"

Fastly CDN server

"};

#FASTLY error
}

sub design_exception {
}


Shortened header name.

Shortened header name.

vcl 4.0;

import directors;
import std;

###
# Varnish Documentation
#   https://www.varnish-cache.org/docs/trunk/users-guide/vcl-built-in-subs.html
#   https://www.varnish-cache.org/docs/trunk/reference/vcl.html
##

{% for backend in varnish_backend_hosts %}
backend application_{{ loop.index }} {
  .host = "{{ backend }}";
  .port = "{{ varnish_backend_port }}";
{% if varnish_health_checks_enabled %}
  .probe = {
    .url = "{{ varnish_health_check_url }}";
    .interval = {{ varnish_health_check_interval }};
    .timeout  = {{ varnish_health_check_timeout }};
    .window = {{ varnish_health_check_window }};
    .threshold = {{ varnish_health_check_threshold }};
  }
{% endif %}
}
{% endfor %}

###
# vcl_init
#   Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
###
# The vcl_init subroutine may terminate with calling return() with one of the following keywords:
#
# ok
#   Normal return, VCL continues loading.
##

sub vcl_init {
  new application = directors.round_robin();
{% for backend in varnish_backend_hosts %}
  application.add_backend(application_{{ loop.index }});
{% endfor %}
}

###
# 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.
#   It is also used to modify the request
###
# The vcl_recv subroutine may terminate with calling return() on one of the following keywords:
#
# synth(status code, reason)
#   Return a synthetic object with the specified status code to the client and abandon the request.
# pass
#   Switch to pass mode. Control will eventually pass to vcl_pass.
# pipe
#   Switch to pipe mode. Control will eventually pass to vcl_pipe.
# hash
#   Continue processing the object as a potential candidate for caching. Passes the control over to vcl_hash.
# purge
#   Purge the object and it's variants. Control passes through vcl_hash to vcl_purge.
#

sub vcl_recv {
  set req.backend_hint = application.backend();

  ###
  # Avoid processing uncacheable requests
  ###

  if (req.http.Authorization) {
    set req.http.X-Passthrough-Reason = "No Caching Authenticated Content";
    return (pass);
  }

{% if varnish_uri_blacklist_enabled %}
  if ((req.url ~ "{{ varnish_uri_blacklist_regexp }}")) {
    set req.http.X-Passthrough-Reason = "Path in Blacklist";
    return(pass);
  }
{% endif %}

{% if varnish_diagnostic_headers_forwarded_for %}
  ###
  # Inject X-Forwarded-For headers, but only once.
  ###

  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;
    }
  }
{% endif %}

{% if varnish_cookie_sanitization_enabled %}
  ###
  # Cookie Sanitization
  ###
  if (req.http.Cookie) {
    set req.http.X-Cookie-Unmodified = req.http.Cookie;

  {% for cookie in varnish_cookie_sanitization_blacklist %}
#    set req.http.Cookie = regsuball(req.http.Cookie, "{{ cookie }}=[^;]+(; )?", "");
  {% endfor %}

    ### General Cleanup
    set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
    if (req.http.Cookie ~ "^\s*$") {
        set req.http.X-Cookie-Discarded = "YES:Empty";
        unset req.http.Cookie;
    }
    if (req.http.Cookie) {
      set req.http.X-Cookie-Sanitized = req.http.Cookie;
    }
  }
{% endif %}

{% if varnish_header_sanitization_enabled %}
  ###
  # Header Sanitization
  ###

{% if varnish_header_sanitization_discard_host_port %}
  set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
{% endif %}

{% if varnish_header_sanitization_normalize_accept_encoding %}
  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
      unset req.http.Accept-Encoding;
    } elsif (req.http.Accept-Encoding ~ "gzip") {
      set req.http.Accept-Encoding = "gzip";
    } elsif (req.http.Accept-Encoding ~ "deflate") {
      set req.http.Accept-Encoding = "deflate";
    } else {
      unset req.http.Accept-Encoding;
    }
  }
{% endif %}

{% endif %}

{% if varnish_uri_sanitization_enabled %}
  ###
  # URI Sanitization
  ###

  if (req.url ~ "(\?|&){{ varnish_uri_sanitization_regexp }}=") {
    set req.url = regsuball(req.url, "&{{ varnish_uri_sanitization_regexp }}=([A-z0-9_\-\.%25]+)", "");
    set req.url = regsuball(req.url, "\?{{ varnish_uri_sanitization_regexp }}=([A-z0-9_\-\.%25]+)", "?");
    set req.url = regsub(req.url, "\?&", "?");
    set req.url = regsub(req.url, "\?$", "");
  }
  if (req.url ~ "\#") {
    set req.url = regsub(req.url, "\#.*$", "");
  }
{% endif %}

{% if varnish_workaround_telusdotcom_browser_profile %}
  ###
  # Workaround and Diagnostics for BrowserProfile and Language/Region Detection on TELUS.com
  ###

  if (req.http.Cookie ~ "BrowserProfile") {
    set req.http.X-BrowserProfile = regsuball(req.http.Cookie, "(.*)BrowserProfile=([^;]*)(.*)", "\2");
    if (req.http.X-BrowserProfile ~ "language") {
      set req.http.X-Language = std.tolower(regsuball(req.http.X-BrowserProfile, "(.*)language\\.:\\.([^\\]*)(.*)", "\2"));
      set req.http.X-Language-Found = "YES:BrowserProfile";
    }
    if (req.http.X-BrowserProfile ~ "region") {
      set req.http.X-Region = std.tolower(regsuball(regsuball(req.http.X-BrowserProfile, "geo\\.\:{(.*)\}", ""), "(.*)region\\.:\\.([^\\]*)(.*)", "\2"));
      set req.http.X-Region-Found = "YES:BrowserProfile";
    }
    if (req.http.X-BrowserProfile ~ "geo") {
      set req.http.X-Geolocation = regsuball(req.http.X-BrowserProfile, "(.*)geo..:\\.([^\\]*)(.*)", "\2");
      set req.http.X-Geolocation-Found = "YES:BrowserProfile";

      if (req.http.X-Geolocation ~ "country") {
        set req.http.X-Geolocation-Country = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)country\\.:\\.([^\\]*)(.*)", "\2");
      }
      if (req.http.X-Geolocation ~ "region") {
        set req.http.X-Geolocation-Region = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)region\\.:\\.([^\\]*)(.*)", "\2");
      }
      if (req.http.X-Geolocation ~ "city") {
        set req.http.X-Geolocation-City = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)city\\.:\\.([^\\]*)(.*)", "\2");
      }
      if (req.http.X-Geolocation ~ "isp") {
        set req.http.X-Geolocation-ISP = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)isp\\.:\\.([^\\]*)(.*)", "\2");
      }
    } else {
      set req.http.X-Geolocation-Found = "NO";
    }
  }

  if (!req.http.X-Language) {
    if (req.http.Cookie ~ "lang=") {
      set req.http.X-Language = std.tolower(regsuball(req.http.Cookie, "(.*)lang=([^;]*)(.*)", "\2"));
      set req.http.X-Language-Found = "YES:lang";
    } else {
      set req.http.X-Language = "en";
      set req.http.X-Language-Found = "NO";
    }
  }

  if (!req.http.X-Region) {
    if (req.http.Cookie ~ "prov=") {
      set req.http.X-Region = std.tolower(regsuball(req.http.Cookie, "(.*)prov=([^;]*)(.*)", "\2"));
      set req.http.X-Region-Found = "YES:prov";
    } else {
      set req.http.X-Region = "bc";
      set req.http.X-Region-Found = "NO";
    }
  }

  if (req.url ~ "/(en|fr)/") {
    if (req.url ~ "/en/" && req.http.X-Language != "en") {
      set req.http.X-Passthrough-Reason = "Unaligned Language (Path: /en/) vs (Cookie: " + req.http.X-Language + ")";
      return(pass);
    }
    if (req.url ~ "/fr/" && req.http.X-Language != "fr") {
      set req.http.X-Passthrough-Reason = "Unaligned Language (Path: /fr/) vs (Cookie: " + req.http.X-Language + ")";
      return(pass);
    }
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Language)";
    return(pass);
  }

  if (req.url ~ "/(ab|bc|mb|nb|nl|ns|nt|nu|on|pe|qc|sk|yt)/") {
    {% for province in ['ab', 'bc', 'mb', 'nb', 'nl', 'ns', 'nt', 'nu', 'on', 'pe', 'qc', 'sk', 'yt'] %}
    if (req.url ~ "/{{ province }}/" && req.http.X-Region != "{{ province }}") {
      set req.http.X-Passthrough-Reason = "Unaligned Region (Path: /{{ province }}/) vs (Cookie: " + req.http.X-Region + ")";
      return(pass);
    }
    {% endfor %}
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Province)";
    return(pass);
  }

  if (req.http.Cookie) {
    if (req.http.Cookie ~ "***REMOVED***") {
      set req.http.X-Screen-Resolution = regsuball(req.http.Cookie, "(.*)***REMOVED***=([^;]*)(.*)", "\2");
    }

    if (req.http.Cookie ~ "***REMOVED***") {
      set req.http.X-Customer-Type = regsuball(req.http.Cookie, "(.*)***REMOVED***=([^;]*)(.*)", "\2");
    }
    if (req.http.Cookie ~ "***REMOVED***") {
      set req.http.X-Outdated-Browser = regsuball(req.http.Cookie, "(.*)***REMOVED***=([^;]*)(.*)", "\2");
    }
  }
{% endif %}

{% if varnish_cookie_sanitization_discard_from_client %}
    set req.http.X-Cookie-Discarded = "YES:No Reason Not To";
    unset req.http.Cookie;
{% endif %}
}

###
# vcl_hit
#   Called when a cache lookup is successful.
###
# The vcl_hit subroutine may terminate with calling return() with one of the following keywords:
#
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
# deliver
#   Deliver the object. Control passes to vcl_deliver.
# synth(status code, reason)
#   Return the specified status code to the client and abandon the request.
###

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

  return (fetch);
{% endif %}
}

###
# vcl_backend_response
#   Called after the response headers has been successfully retrieved from the backend.
###
# The vcl_backend_response subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Possibly insert the object into the cache, then deliver it to the Control will eventually pass to vcl_deliver.
# abandon
#   Abandon the backend request and generates an error.
# retry
#   Retry the backend transaction. Increases the retries counter. If the number of retries is higher than max_retries Varnish emits a guru meditation error.
###

sub vcl_backend_response {
{% if varnish_workaround_telusdotcom_browser_profile %}
  if (bereq.http.X-Language) {
    set beresp.http.X-Language = bereq.http.X-Language;
#    if (bereq.http.X-Language-Found) {
#      set beresp.http.X-Language-Found = bereq.http.X-Language-Found;
#    }
  }
  if (bereq.http.X-Region) {
    set beresp.http.X-Region = bereq.http.X-Region;
#    if (bereq.http.X-Region-Found) {
#      set beresp.http.X-Region-Found = bereq.http.X-Region-Found;
#    }
  }
{% endif %}

{% if varnish_uri_blacklist_enabled %}
  if (bereq.url ~ "{{ varnish_uri_blacklist_regexp }}") {
    set beresp.http.X-Cacheable = "NO:Path in Blacklist";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    if (bereq.http.X-Passthrough-Reason) {
{% if varnish_diagnostic_headers_passthrough_reason %}
      set beresp.http.X-Passthrough-Reason = bereq.http.X-Passthrough-Reason;
{% endif %}
      return(deliver);
    } else {
{% if varnish_cookie_sanitization_discard_from_server %}
      unset beresp.http.Set-Cookie;
{% endif %}
    }
  }
{% else %}
{% if varnish_cookie_sanitization_discard_from_server %}
  unset beresp.http.Set-Cookie;
{% endif %}
{% endif %}

{% if varnish_diagnostic_headers_enabled %}
  if (bereq.http.Cookie) {
    set beresp.http.X-Cacheable = "NO:Cookie in Request";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Set-Cookie) {
    set beresp.http.X-Cacheable = "NO:Set-Cookie in Response";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Cache-Control ~ "private") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.X-No-Cache) {
    set beresp.http.X-Cacheable = "NO:X-No-Cache";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.ttl <= 0s) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    set beresp.http.X-Cacheable = "YES";
  }
{% endif %}

  set beresp.grace = {{ varnish_grace_period }};
}

###
# vcl_deliver
#   Called before a cached object is delivered to the client.
###
# The vcl_deliver subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Deliver the object to the client.
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
###

sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }
}

vcl 4.0;

import directors;
import std;

###
# Varnish Documentation
#   https://www.varnish-cache.org/docs/trunk/users-guide/vcl-built-in-subs.html
#   https://www.varnish-cache.org/docs/trunk/reference/vcl.html
##

{% for backend in varnish_backend_hosts %}
backend application_{{ loop.index }} {
  .host = "{{ backend }}";
  .port = "{{ varnish_backend_port }}";
{% if varnish_health_checks_enabled %}
  .probe = {
    .url = "{{ varnish_health_check_url }}";
    .interval = {{ varnish_health_check_interval }};
    .timeout  = {{ varnish_health_check_timeout }};
    .window = {{ varnish_health_check_window }};
    .threshold = {{ varnish_health_check_threshold }};
  }
{% endif %}
}
{% endfor %}

###
# vcl_init
#   Called when VCL is loaded, before any requests pass through it. Typically used to initialize VMODs.
###
# The vcl_init subroutine may terminate with calling return() with one of the following keywords:
#
# ok
#   Normal return, VCL continues loading.
##

sub vcl_init {
  new application = directors.round_robin();
{% for backend in varnish_backend_hosts %}
  application.add_backend(application_{{ loop.index }});
{% endfor %}
}

###
# 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.
#   It is also used to modify the request
###
# The vcl_recv subroutine may terminate with calling return() on one of the following keywords:
#
# synth(status code, reason)
#   Return a synthetic object with the specified status code to the client and abandon the request.
# pass
#   Switch to pass mode. Control will eventually pass to vcl_pass.
# pipe
#   Switch to pipe mode. Control will eventually pass to vcl_pipe.
# hash
#   Continue processing the object as a potential candidate for caching. Passes the control over to vcl_hash.
# purge
#   Purge the object and it's variants. Control passes through vcl_hash to vcl_purge.
#

sub vcl_recv {
  set req.backend_hint = application.backend();

  ###
  # Avoid processing uncacheable requests
  ###

  if (req.http.Authorization) {
    set req.http.X-Passthrough-Reason = "No Caching Authenticated Content";
    return (pass);
  }

{% if varnish_uri_blacklist_enabled %}
  if ((req.url ~ "{{ varnish_uri_blacklist_regexp }}")) {
    set req.http.X-Passthrough-Reason = "Path in Blacklist";
    return(pass);
  }
{% endif %}

{% if varnish_diagnostic_headers_forwarded_for %}
  ###
  # Inject X-Forwarded-For headers, but only once.
  ###

  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;
    }
  }
{% endif %}

{% if varnish_cookie_sanitization_enabled %}
  ###
  # Cookie Sanitization
  ###
  if (req.http.Cookie) {
    set req.http.X-Cookie-Unmodified = req.http.Cookie;

  {% for cookie in varnish_cookie_sanitization_blacklist %}
#    set req.http.Cookie = regsuball(req.http.Cookie, "{{ cookie }}=[^;]+(; )?", "");
  {% endfor %}

    ### General Cleanup
    set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", "");
    if (req.http.Cookie ~ "^\s*$") {
        set req.http.X-Cookie-Discarded = "YES:Empty";
        unset req.http.Cookie;
    }
    if (req.http.Cookie) {
      set req.http.X-Cookie-Sanitized = req.http.Cookie;
    }
  }
{% endif %}

{% if varnish_header_sanitization_enabled %}
  ###
  # Header Sanitization
  ###

{% if varnish_header_sanitization_discard_host_port %}
  set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
{% endif %}

{% if varnish_header_sanitization_normalize_accept_encoding %}
  if (req.http.Accept-Encoding) {
    if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") {
      unset req.http.Accept-Encoding;
    } elsif (req.http.Accept-Encoding ~ "gzip") {
      set req.http.Accept-Encoding = "gzip";
    } elsif (req.http.Accept-Encoding ~ "deflate") {
      set req.http.Accept-Encoding = "deflate";
    } else {
      unset req.http.Accept-Encoding;
    }
  }
{% endif %}

{% endif %}

{% if varnish_uri_sanitization_enabled %}
  ###
  # URI Sanitization
  ###

  if (req.url ~ "(\?|&){{ varnish_uri_sanitization_regexp }}=") {
    set req.url = regsuball(req.url, "&{{ varnish_uri_sanitization_regexp }}=([A-z0-9_\-\.%25]+)", "");
    set req.url = regsuball(req.url, "\?{{ varnish_uri_sanitization_regexp }}=([A-z0-9_\-\.%25]+)", "?");
    set req.url = regsub(req.url, "\?&", "?");
    set req.url = regsub(req.url, "\?$", "");
  }
  if (req.url ~ "\#") {
    set req.url = regsub(req.url, "\#.*$", "");
  }
{% endif %}

{% if varnish_workaround_telusdotcom_browser_profile %}
  ###
  # Workaround and Diagnostics for BrowserProfile and Language/Region Detection on TELUS.com
  ###

  if (req.http.Cookie ~ "BrowserProfile") {
    set req.http.X-BrowserProfile = regsuball(req.http.Cookie, "(.*)BrowserProfile=([^;]*)(.*)", "\2");
    if (req.http.X-BrowserProfile ~ "language") {
      set req.http.X-Language = std.tolower(regsuball(req.http.X-BrowserProfile, "(.*)language\\.:\\.([^\\]*)(.*)", "\2"));
      set req.http.X-Language-Found = "YES:BrowserProfile";
    }
    if (req.http.X-BrowserProfile ~ "region") {
      set req.http.X-Region = std.tolower(regsuball(regsuball(req.http.X-BrowserProfile, "geo\\.\:{(.*)\}", ""), "(.*)region\\.:\\.([^\\]*)(.*)", "\2"));
      set req.http.X-Region-Found = "YES:BrowserProfile";
    }
    if (req.http.X-BrowserProfile ~ "geo") {
      set req.http.X-BrowserProfile-Geolocation = regsuball(req.http.X-BrowserProfile, "(.*)geo..:\\.([^\\]*)(.*)", "\2");
      set req.http.X-BrowserProfile-Geolocation-Found = "YES";

      if (req.http.X-BrowserProfile-Geolocation ~ "country") {
        set req.http.X-BrowserProfile-Geolocation-Country = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)country\\.:\\.([^\\]*)(.*)", "\2");
      }
      if (req.http.X-BrowserProfile-Geolocation ~ "region") {
        set req.http.X-BrowserProfile-Geolocation-Region = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)region\\.:\\.([^\\]*)(.*)", "\2");
      }
      if (req.http.X-BrowserProfile-Geolocation ~ "city") {
        set req.http.X-BrowserProfile-Geolocation-City = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)city\\.:\\.([^\\]*)(.*)", "\2");
      }
      if (req.http.X-BrowserProfile-Geolocation ~ "isp") {
        set req.http.X-BrowserProfile-Geolocation-ISP = regsuball(req.http.X-BrowserProfile-Geolocation, "(.*)isp\\.:\\.([^\\]*)(.*)", "\2");
      }
    } else {
      set req.http.X-BrowserProfile-Geolocation-Found = "NO";
    }
  }

  if (!req.http.X-Language) {
    if (req.http.Cookie ~ "lang=") {
      set req.http.X-Language = std.tolower(regsuball(req.http.Cookie, "(.*)lang=([^;]*)(.*)", "\2"));
      set req.http.X-Language-Found = "YES:lang";
    } else {
      set req.http.X-Language = "en";
      set req.http.X-Language-Found = "NO";
    }
  }

  if (!req.http.X-Region) {
    if (req.http.Cookie ~ "prov=") {
      set req.http.X-Region = std.tolower(regsuball(req.http.Cookie, "(.*)prov=([^;]*)(.*)", "\2"));
      set req.http.X-Region-Found = "YES:prov";
    } else {
      set req.http.X-Region = "bc";
      set req.http.X-Region-Found = "NO";
    }
  }

  if (req.url ~ "/(en|fr)/") {
    if (req.url ~ "/en/" && req.http.X-Language != "en") {
      set req.http.X-Passthrough-Reason = "Unaligned Language (Path: /en/) vs (Cookie: " + req.http.X-Language + ")";
      return(pass);
    }
    if (req.url ~ "/fr/" && req.http.X-Language != "fr") {
      set req.http.X-Passthrough-Reason = "Unaligned Language (Path: /fr/) vs (Cookie: " + req.http.X-Language + ")";
      return(pass);
    }
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Language)";
    return(pass);
  }

  if (req.url ~ "/(ab|bc|mb|nb|nl|ns|nt|nu|on|pe|qc|sk|yt)/") {
    {% for province in ['ab', 'bc', 'mb', 'nb', 'nl', 'ns', 'nt', 'nu', 'on', 'pe', 'qc', 'sk', 'yt'] %}
    if (req.url ~ "/{{ province }}/" && req.http.X-Region != "{{ province }}") {
      set req.http.X-Passthrough-Reason = "Unaligned Region (Path: /{{ province }}/) vs (Cookie: " + req.http.X-Region + ")";
      return(pass);
    }
    {% endfor %}
  } else {
      set req.http.X-Passthrough-Reason = "Not Set in Path (Province)";
    return(pass);
  }

  if (req.http.Cookie) {
    if (req.http.Cookie ~ "***REMOVED***") {
      set req.http.X-Screen-Resolution = regsuball(req.http.Cookie, "(.*)***REMOVED***=([^;]*)(.*)", "\2");
    }

    if (req.http.Cookie ~ "***REMOVED***") {
      set req.http.X-Customer-Type = regsuball(req.http.Cookie, "(.*)***REMOVED***=([^;]*)(.*)", "\2");
    }
    if (req.http.Cookie ~ "***REMOVED***") {
      set req.http.X-Outdated-Browser = regsuball(req.http.Cookie, "(.*)***REMOVED***=([^;]*)(.*)", "\2");
    }
  }
{% endif %}

{% if varnish_cookie_sanitization_discard_from_client %}
    set req.http.X-Cookie-Discarded = "YES:No Reason Not To";
    unset req.http.Cookie;
{% endif %}
}

###
# vcl_hit
#   Called when a cache lookup is successful.
###
# The vcl_hit subroutine may terminate with calling return() with one of the following keywords:
#
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
# deliver
#   Deliver the object. Control passes to vcl_deliver.
# synth(status code, reason)
#   Return the specified status code to the client and abandon the request.
###

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

  return (fetch);
{% endif %}
}

###
# vcl_backend_response
#   Called after the response headers has been successfully retrieved from the backend.
###
# The vcl_backend_response subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Possibly insert the object into the cache, then deliver it to the Control will eventually pass to vcl_deliver.
# abandon
#   Abandon the backend request and generates an error.
# retry
#   Retry the backend transaction. Increases the retries counter. If the number of retries is higher than max_retries Varnish emits a guru meditation error.
###

sub vcl_backend_response {
{% if varnish_workaround_telusdotcom_browser_profile %}
  if (bereq.http.X-Language) {
    set beresp.http.X-Language = bereq.http.X-Language;
#    if (bereq.http.X-Language-Found) {
#      set beresp.http.X-Language-Found = bereq.http.X-Language-Found;
#    }
  }
  if (bereq.http.X-Region) {
    set beresp.http.X-Region = bereq.http.X-Region;
#    if (bereq.http.X-Region-Found) {
#      set beresp.http.X-Region-Found = bereq.http.X-Region-Found;
#    }
  }
{% endif %}

{% if varnish_uri_blacklist_enabled %}
  if (bereq.url ~ "{{ varnish_uri_blacklist_regexp }}") {
    set beresp.http.X-Cacheable = "NO:Path in Blacklist";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    if (bereq.http.X-Passthrough-Reason) {
{% if varnish_diagnostic_headers_passthrough_reason %}
      set beresp.http.X-Passthrough-Reason = bereq.http.X-Passthrough-Reason;
{% endif %}
      return(deliver);
    } else {
{% if varnish_cookie_sanitization_discard_from_server %}
      unset beresp.http.Set-Cookie;
{% endif %}
    }
  }
{% else %}
{% if varnish_cookie_sanitization_discard_from_server %}
  unset beresp.http.Set-Cookie;
{% endif %}
{% endif %}

{% if varnish_diagnostic_headers_enabled %}
  if (bereq.http.Cookie) {
    set beresp.http.X-Cacheable = "NO:Cookie in Request";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Set-Cookie) {
    set beresp.http.X-Cacheable = "NO:Set-Cookie in Response";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.Cache-Control ~ "private") {
    set beresp.http.X-Cacheable = "NO:Cache-Control=private";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.http.X-No-Cache) {
    set beresp.http.X-Cacheable = "NO:X-No-Cache";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } elsif (beresp.ttl <= 0s) {
    set beresp.http.X-Cacheable = "NO:Not Cacheable";
    set beresp.uncacheable = true;
    set beresp.ttl = {{ varnish_backend_response_ttl }}s;
    return(deliver);
  } else {
    set beresp.http.X-Cacheable = "YES";
  }
{% endif %}

  set beresp.grace = {{ varnish_grace_period }};
}

###
# vcl_deliver
#   Called before a cached object is delivered to the client.
###
# The vcl_deliver subroutine may terminate with calling return() with one of the following keywords:
#
# deliver
#   Deliver the object to the client.
# restart
#   Restart the transaction. Increases the restart counter. If the number of restarts is higher than max_restarts Varnish emits a guru meditation error.
###

sub vcl_deliver {
  if (obj.hits > 0) {
    set resp.http.X-Cache = "HIT";
  } else {
    set resp.http.X-Cache = "MISS";
  }
}


Remove /server-status probe

Remove /server-status probe

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .first_byte_timeout     = 300s;   # How long to wait before we receive a first byte from our backend?
    .connect_timeout        = 5s;     # How long to wait for a backend connection?
    .between_bytes_timeout  = 2s;     # How long to wait between bytes received from our backend?
}

backend default {
    .host = "127.0.0.1";
    .port = "8080";
    .probe = {
        .url = "/server-status";
        .timeout  = 1s;
        .interval = 10s;
        .window    = 5;
        .threshold = 2;
    }
    .first_byte_timeout     = 300s;   # How long to wait before we receive a first byte from our backend?
    .connect_timeout        = 5s;     # How long to wait for a backend connection?
    .between_bytes_timeout  = 2s;     # How long to wait between bytes received from our backend?
}