Some sample VCL for Drupal 7 and 8

Access control lists (ACL)

  acl purge_ban {
    /* Simple access control list for allowing item purge for the self machine */
    "127.0.0.1"/32; // We can use '"localhost";' instead
  }
  acl allowed_monitors {
    /* Simple access control list for allowing item purge for the self machine */
    "127.0.0.1"/32; // We can use'"localhost";' instead
  }
  # acl own_proxys {
  #   "127.0.0.1"/32; // We can use'"localhost";' instead
  # }
  # See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#access-control-list-acl

Backend definition

  # See https://www.varnish-cache.org/docs/4.0/reference/vcl.html#backend-definition
  backend default {
    /* Default backend on the same machine. */
    # WARNING: timeouts could be not big enought for certain POST requests.
    .host = "127.0.0.1";
    .port = "8008";
    .max_connections = 100;
    .connect_timeout = 60s;
    .first_byte_timeout = 60s;
    .between_bytes_timeout = 60s;
    .probe = basic;
  }

Check for Varnish special requests

    /* 1st: Check for Varnish special requests */
  sub vcl_recv {
    if ( ( req.http.host == "monitor.server.health"
        || req.http.host == "health.varnish" )
      && client.ip ~ allowed_monitors
      && ( req.method == "OPTIONS" || req.method == "GET" )
    ) {
      return (synth(200, "OK"));
    }
  }

Purging

  sub vcl_recv {
    # Purge logic
    # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#http-purging
    # SeeV3 https://www.varnish-software.com/static/book/Cache_invalidation.html#removing-a-single-object
    if ( req.method == "PURGE" ) {
      if ( client.ip !~ purge_ban ) {
        return (synth(405, "Not allowed."));
      }
      return (purge);
    }
  }

Ban logic

  sub vcl_recv {
    # Ban logic
    # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#bans
    if ( req.method == "BAN" ) {
      if ( client.ip !~ purge_ban ) {
        return (synth(405, "Not allowed."));
      }
      if (req.http.Purge-Cache-Tags) {
        ban(  "obj.http.X-Host == " + req.http.host +
          " && obj.http.Purge-Cache-Tags ~ " + req.http.Purge-Cache-Tags
          );
      }
      else {
        # Assumes req.url is a regex. This might be a bit too simple
        ban(  "obj.http.X-Host == " + req.http.host +
          " && obj.http.X-Url ~ " + req.url
          );
      }
      return (synth(200, "Ban added"));
    }
  }

Custom client redirection

Call subroutine, call perm_redirections_recv

Add Proxy IPs manually in the exclude list from Client IP

  sub vcl_recv {
    # if ( req.restarts == 0
    #   && client.ip ~ own_proxys
    #   && req.http.X-Forwarded-For
    # ) {
    #   set req.http.X-Forwarded-For
    #     = regsub(req.http.X-Forwarded-For,
    #         "(, )?(10\.10\.10\.10|10\.11\.11\.11)", "");
    # }
    # An alternative could be to skip all this and try to modify the header
    # manually so Varnish doesn't touch it.
    # set req.http.X-Forwarded-For = req.http.X-Forwarded-For + "";
    #
    # Example normalize the host header, remove the port (in case you're testing
    # this on various TCP ports)
    # set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
  }

Websocket support

  sub vcl_recv {
    # Websocket support
    # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html
    if ( req.http.Upgrade ~ "(?i)websocket" ) {
      return (pipe);
    }
  }
  sub vcl_pipe {
    # Websocket support
    # See 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;
    }
  }

Access control for some URLs by ACL

  sub vcl_recv {
    # By example denial some URLs depending on client-ip, we'll need to define
    # corresponding ACL 'internal'.
    # if ( req.url ~ "^/(cron|install)\.php"
    #   && client.ip !~ internal
    # ) {
    #   # Have Varnish throw the error directly.
    #   return (synth(403, "Forbidden."));
    #   # Use a custom error page that you've defined in Drupal at the path "404".
    #   # set req.url = "/403";
    # }
  }

Custom URL exceptions

  sub vcl_recv {
    /* 8th: Custom exceptions */
    # Host exception example:
    # if ( req.http.host == "ejemplo.exception.com" ) {
    #     return (pass);
    # }
    # Drupal exceptions, edit if we want to cache some AJAX/AHAH request.
    # Add here filters for never cache URLs such as Payment Gateway's callbacks.
    if ( req.url ~ "^/status\.php$"
      || req.url ~ "^/update\.php$"
      || req.url ~ "^/ooyala/ping$"
      || req.url ~ "^/admin/build/features"
      || req.url ~ "^/info/.*$"
      || req.url ~ "^/flag/.*$"
      || req.url ~ "^.*/ajax/.*$"
      || req.url ~ "^.*/ahah/.*$"
    ) {
      /* Do not cache these paths */
      return (pass);
    }
  }

Streaming

  sub vcl_recv {
    if ( req.url ~ "^/admin/content/backup_migrate/export"
      || req.url ~ "^/admin/config/system/backup_migrate"
    ) {
      return (pipe);
    }
    if ( req.url ~ "^/system/files" ) {
      return (pipe);
    }
  }

Grace

  sub vcl_recv {
    /* 9th: Graced objets & Serve from anonymous cahe if all backends are down */
    # See https://www.varnish-software.com/blog/grace-varnish-4-stale-while-revalidate-semantics-varnish
    # set req.http.X-Varnish-Grace = "none";
    if ( ! std.healthy(req.backend_hint) ) {
      # We must do this here since cookie hashing
      unset req.http.Cookie;
      #TODO# Add sick marker
    }
  }
  sub vcl_backend_response {
    # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
    # See https://www.varnish-software.com/blog/grace-varnish-4-stale-while-revalidate-semantics-varnish
    set beresp.grace = 1h;
  # }

Compression

  sub vcl_recv {
    # Althought Varnish 4 handles gziped content itself by default, just to be
    # sure we want to remove Accept-Encoding for some compressed formats.
    # See https://www.varnish-cache.org/docs/4.0/phk/gzip.html#what-does-http-gzip-support-do
    # See https://www.varnish-cache.org/docs/4.0/users-guide/compression.html
    # See https://www.varnish-cache.org/docs/4.0/reference/varnishd.html?highlight=http_gzip_support
    # See (for older configs) https://www.varnish-cache.org/trac/wiki/VCLExampleNormalizeAcceptEncoding
    if ( req.http.Accept-Encoding ) {
      if ( req.url ~ "(?i)\.(7z|avi|bz2|flv|gif|gz|jpe?g|mpe?g|mk[av]|mov|mp[34]|og[gm]|pdf|png|rar|swf|tar|tbz|tgz|woff2?|zip|xz)(\?.*)?$"
      ) {
        /* Already compressed formats, no sense trying to compress again */
        unset req.http.Accept-Encoding;
      }
    }
  }

Request manipulation

  sub vcl_recv {
    # We could add here a custom header grouping User-agent families.
    # Generic URL manipulation.
    # Remove Google Analytics added parameters, useless for our backends.
    if ( req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=" ) {
      set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
      set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
      set req.url = regsub(req.url, "\?&", "?");
      set req.url = regsub(req.url, "\?$", "");
    }
  }

Stripping anchors

  sub vcl_recv {
    # Strip anchors, server doesn't need it.
    if ( req.url ~ "\#" ) {
      set req.url = regsub(req.url, "\#.*$", "");
    }
  }

Stripping trailing ? if they exist

  sub vcl_recv {
    # Strip a trailing ? if it exists
    if ( req.url ~ "\?$" ) {
      set req.url = regsub(req.url, "\?$", "");
  }

Normalizing query string arguments

  sub vcl_recv {
    # Normalize the querystring arguments
    set req.url = std.querysort(req.url);
  }

Removing cookies

  sub vcl_recv {
    # Always cache the following static file types for all users.
    # Use with care if we control certain downloads depending on cookies.
    # Be carefull also if appending .htm[l] via Drupal's clean URLs.
    if ( req.url ~ "(?i)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(itok=)?[a-z0-9_=\.\-]+)?$"
      && req.url !~ "/system/storage/serve"
    ) {
        unset req.http.Cookie;
    }
    # Remove all cookies that backend doesn't need to know about.
    # See https://www.varnish-cache.org/trac/wiki/VCLExampleRemovingSomeCookies
    if ( req.http.Cookie ) {
      /* Warning: Not a pretty solution */
      # Prefix header containing cookies with ';'
      set req.http.Cookie = ";" + req.http.Cookie;
      # Remove any spaces after ';' in header containing cookies
      set req.http.Cookie = regsuball(req.http.Cookie, "; +", ";");
      # Prefix cookies we want to preserve with one space:
      #   'S{1,2}ESS[a-z0-9]+' is the regular expression matching a Drupal session
      #   cookie ({1,2} added for HTTPS support).
      #   'NO_CACHE' is usually set after a POST request to make sure issuing user
      #   see the results of his post.
      #   'OATMEAL' & 'CHOCOLATECHIP' are special cookies used by Drupal's Bakery
      #   module to provide Single Sign On.
      # Keep in mind we should add here any cookie that should reach the backend
      # such as splash avoiding cookies.
      set req.http.Cookie
        = regsuball(
            req.http.Cookie,
            ";(S{1,2}ESS[a-z0-9]+|NO_CACHE|OATMEAL|CHOCOLATECHIP|big_pipe_nojs)=",
            "; \1="
          );
      # Remove from the header any single Cookie not prefixed with a space until
      # next ';' separator.
      set req.http.Cookie = regsuball(req.http.Cookie, ";[^ ][^;]*", "");
      # Remove any '; ' at the start or the end of the header.
      set req.http.Cookie = regsuball(req.http.Cookie, "^[; ]+|[; ]+$", "");
      #If there are no remaining cookies, remove the cookie header.
      if ( req.http.Cookie == "" ) {
        unset req.http.Cookie;
      }
    }
  }

Session and special cookies

  sub vcl_recv {
    /* 13th: Session cookie & special cookies bypass caching stage */
    # As we might want to cache some requests, hashed with its cookies, we don't
    # simply pass when some cookies remain present at this point.
    # Instead we look for request that must be passed due to the cookie header.
    if ( req.http.Cookie ~ "SESS"
      || req.http.Cookie ~ "SSESS"
      || req.http.Cookie ~ "NO_CACHE"
      || req.http.Cookie ~ "OATMEAL"
      || req.http.Cookie ~ "CHOCOLATECHIP"
    ) {
      return (pass);
    }
  }

ESI support

  sub vcl_recv {
    # Send Surrogate-Capability headers
    # See http://www.w3.org/TR/edge-arch
    # Note that myproxyname is an identifier that should avoid collitions
    # set req.http.Surrogate-Capability = "myproxyname=ESI/1.0";
  }

ByPassing cache for debug purposes

  sub vcl_recv {
    # Useful for debugging we can now pipe or pass the request to backend to
    # bypass cache.
    # return (pipe);
    # return (pass);
  }

Bypassing built-in logic

Warning: NOT RECOMMENDED

  sub vcl_recv {
    return (hash);
  }

This returns unconditionally. Use this only if you are confident and have tested your default.vcl

PIPE mode

  # sub vcl_pipe {
  #     # By default Connection: close is set on all piped requests, to stop
  #     # connection reuse from sending future requests directly to the
  #     # (potentially) wrong backend. If you do want this to happen, you can undo
  #     # it here.
  #     # unset bereq.http.connection;
  #     return (pipe);
  # }

Hashing custom headers

    # Example for caching differents object versions by device previously
    # detected (when static content could also vary):
    # if ( req.http.X-UA-Device ) {
    #   hash_data(req.http.X-UA-Device);
    # }
    # Example for caching diferent object versions by X-Forwarded-Proto, trying
    # to be smart about what kind of request could generate diffetent responses.
    if ( req.http.X-Forwarded-Proto
      && req.url !~ "(?i)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(itok=)?[a-z0-9_=\.\-]+)?$"
    ) {
      hash_data(req.http.X-Forwarded-Proto);
    }

Serving state object

  sub vcl_hit {
    /* Allow varnish to serve up stale content if it is responding slowly */
    # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
    # See https://www.varnish-software.com/blog/grace-varnish-4-stale-while-revalidate-semantics-varnish
    if ( obj.ttl + 60s > 0s ) {
      // Object is in grace, deliver it
      // Automatically triggers a background fetch
      set req.http.X-Varnish-Grace = "normal";
      return (deliver);
    }
    /* Allow varish to serve up stale content if all backends are down */
    # See https://www.varnish-cache.org/docs/4.0/users-guide/vcl-grace.html
    # See https://www.varnish-software.com/blog/grace-varnish-4-stale-while-revalidate-semantics-varnish
    if ( ! std.healthy(req.backend_hint)
      && obj.ttl + obj.grace > 0s
    ) {
      // Object is in grace, deliver it
      // Automatically triggers a background fetch
      set req.http.X-Varnish-Grace = "extended";
      return (deliver);
    }
    /* Bypass built-in logic */
    # We make sure no built-in logic is processed after ours returning
    # inconditionally.
    // fetch & deliver once we get the result
    return (fetch);
  }

Ban lurker friendly-ban support

  sub vcl_deliver {
    # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#bans
    unset resp.http.X-Host;
    unset resp.http.X-Url;
  }

Purge head cleanup

  sub vcl_deliver {
    # Purge's headers can become quite big, causing issues in upstream proxies, so we clean it here
    unset resp.http.Purge-Cache-Tags;
  }

Debugging headers

  sub vcl_deliver {
    # Please consider the risks of showing publicly this information, we can wrap
    # this with an ACL.
    # Add whether the object is a cache hit or miss and the number of hits for
    # the object.
    # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Addingaheaderindicatinghitmiss
    # In Varnish 4 the obj.hits counter behaviour has changed (see bug 1492), so
    # we use a different method: if X-Varnish contains only 1 id, we have a miss,
    # if it contains more (and therefore a space), we have a hit.
    if ( resp.http.X-Varnish ~ " " ) {
      set resp.http.X-Varnish-Cache = "HIT";
      # Since in Varnish 4 the behaviour of obj.hits changed, this might not be
      # accurate.
      # See https://www.varnish-cache.org/trac/ticket/1492
      set resp.http.X-Varnish-Cache-Hits = obj.hits;
    } else {
      set resp.http.X-Varnish-Cache = "MISS";
      /* Show the results of cookie sanitization */
      if ( req.http.Cookie ) {
        set resp.http.X-Varnish-Cookie = req.http.Cookie;
      }
    }
    # See https://www.varnish-software.com/blog/grace-varnish-4-stale-while-revalidate-semantics-varnish
    if ( req.http.X-Varnish-Grace ) {
      set resp.http.X-Varnish-Grace = req.http.X-Varnish-Grace;
    }
  }

Restarting counter

When the backend has a problem and a restart is issued, it is recorded for debugging purposes.

  sub vcl_deliver {
    # Purge's headers can become quite big, causing issues in upstream proxies, so we clean it here
    unset resp.http.Purge-Cache-Tags;
  }

Setting Varnish server hostname

  sub vcl_deliver {
    set resp.http.X-Varnish-Server = server.hostname;
    # If we have setted a custom header with device's family detected we can show
    # it:
    # if ( req.http.X-UA-Device ) {
    #   set resp.http.X-UA-Device = req.http.X-UA-Device;
    # }
    # If we have recived a custom header indicating the protocol in the request we
    # can show it:
    # if ( req.http.X-Forwarded-Proto ) {
    #   set resp.http.X-Forwarded-Proto = req.http.X-Forwarded-Proto;
    # }
  }

Vary header manipulation

  sub vcl_deliver {
    # if ( resp.http.Vary ) {
    #   set resp.http.Vary = resp.http.Vary + ",User-Agent";
    # } else {
    #   set resp.http.Vary = "User-Agent";
    # }
  }

Faking server headers

  sub vcl_deliver {
    # set resp.http.Server = "Deep thought";
    # set resp.http.X-Powered-By = "BOFH";
    # Or have some fun with headers:
    # See http://www.nextthing.org/archives/2005/08/07/fun-with-http-headers
    # See http://royal.pingdom.com/2012/08/15/fun-and-unusual-http-response-headers/
    # set resp.http.X-Thank-You = "for bothering to look at my HTTP headers";
    # set resp.http.X-Answer = "42";
  }

Dealing with failed request

When there is a falure or error in a request, vcl_synth is called to deliver a synthetic object to the client. Set common headers for synthetic responses. We can add some configuration here such as restarting request, loading synthetic response from disk, redirecting to different page, etc.

Restarting Request:

  sub vcl_synth {
    # Note that max_restarts defaults to 4
    # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
    if ( resp.status == 503
      && req.restarts < 4
    ) {
      return (restart);
    }
  }
  sub vcl_backend_error {
    # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleRestarts
    if ( bereq.retries < 4 ) {
      return (retry);
    }
  }

Load synthetic responses from disk:

  sub vcl_synth {
    # Note that files loaded this way are never re-readed (even after a reload).
    # You should consider PROS/CONS of doing an include instead.
    # See https://www.varnish-cache.org/docs/4.0/reference/vmod_std.generated.html#func-fileread
    # Example custom 403 error page.
    # if ( resp.status == 403 ) {
    #   synthetic(std.fileread("/403.html"));
    #   return (deliver);
    # }
  }

Redirection:

  sub vcl_synth {
    if ( resp.status != 200 ) {
      set resp.http.Retry-After = "5";
    }
  }

Lurker-friendly support

  sub vcl_backend_response {
    /* Ban lurker friendly bans support */
    # See https://www.varnish-cache.org/docs/4.0/users-guide/purging.html#bans
    set beresp.http.X-Host = bereq.http.host;
    set beresp.http.X-Url = bereq.url;
  # }

Caching exceptions

  sub vcl_backend_response {
    # Varnish will cache objects with response codes:
    #   200, 203, 300, 301, 302, 307, 404 & 410.
    # SeeV3 https://www.varnish-software.com/static/book/VCL_Basics.html#the-initial-value-of-beresp-ttl
    # Drupal's Imagecache module can return a 307 redirection to the requested
    # url itself and, depending on Drupal's cache settings, this could lead to a
    # redirection loop being cached for a long time but also we want Varnish to
    # shield a little the backend.
    # See http://drupal.org/node/1248010
    # See http://drupal.org/node/310656
    if ( beresp.status == 307
         #TODO# verify that this work better than 'bereq.url ~ "imagecache"'
      && beresp.http.Location == bereq.url
      && beresp.ttl > 5s
    ) {
      set beresp.ttl = 5s;
      set beresp.http.cache-control = "max-age=5";
    }
  # }

Retrieving request

  sub vcl_backend_response {
    if ( beresp.status == 500
      || beresp.status == 503
    ) {
      #TODO# consider not restarting POST requests as seenV3 on https://www.varnish-cache.org/trac/wiki/VCLExampleSaintMode
      return (retry);
    }
  # }

Stripping cookies from static file types

  sub vcl_backend_response {
    if ( bereq.url ~ "(?i)\.(bz2|css|eot|gif|gz|html?|ico|jpe?g|js|mp3|ogg|otf|pdf|png|rar|svg|swf|tbz|tgz|ttf|woff2?|zip)(\?(itok=)?[a-z0-9_=\.\-]+)?$"
    ) {
      unset beresp.http.set-cookie;
    }
  # }

Processing ESI response

  sub vcl_backend_response {
    # Check for ESI acknowledgement and remove Surrogate-Control header
    #TODO# Add support for Surrogate-Control Targetting
    # if ( beresp.http.Surrogate-Control ~ "ESI/1.0" ) {
    #   unset beresp.http.Surrogate-Control;
    #   set beresp.do_esi = true;
    # }
  # }

GZIP response

  sub vcl_backend_response {
    # Use Varnish to Gzip respone, if suitable, before storing it on cache.
    # See https://www.varnish-cache.org/docs/4.0/users-guide/compression.html
    # See https://www.varnish-cache.org/docs/4.0/phk/gzip.html
    if ( ! beresp.http.Content-Encoding
      && ( beresp.http.content-type ~ "(?i)text"
        || beresp.http.content-type ~ "(?i)application/x-javascript"
        || beresp.http.content-type ~ "(?i)application/javascript"
        || beresp.http.content-type ~ "(?i)application/rss+xml"
        || beresp.http.content-type ~ "(?i)application/xml"
        || beresp.http.content-type ~ "(?i)Application/JSON")
    ) {
      set beresp.do_gzip = true;
    }
  # }

Drupal 8’s pipe support

  sub vcl_backend_response {
    /* Drupal 8's Big Pipe support */
    # Tentative support, maybe 'set beresp.ttl = 0s;' is also needed
    if ( beresp.http.Surrogate-Control ~ "BigPipe/1.0" ) {
      set beresp.do_stream = true;
      # Varnish gzipping breaks streaming of the first response
      set beresp.do_gzip = false;
    }
  # }

Debugging header

  sub vcl_backend_response {
    # Please consider the risks of showing publicly this information, we can wrap
    # this with an ACL.
    # We can add the name of the backend that has processed the request:
    # set beresp.http.X-Varnish-Backend = beresp.backend.name;
    # We can use a header to tell if the object was gziped by Varnish:
    # if ( beresp.do_gzip ) {
    #   set beresp.http.X-Varnish-Gzipped = "yes";
    # } else {
    #   set beresp.http.X-Varnish-Gzipped = "no";
    # }
    # We can do the same to tell if Varnish is streaming it:
    # if ( beresp.do_stream ) {
    #   set beresp.http.X-Varnish-Streaming = "yes";
    # } else {
    #   set beresp.http.X-Varnish-Streaming = "no";
    # }
    # We can also add headers informing whether the object is cacheable or not and why:
    # SeeV3 https://www.varnish-cache.org/trac/wiki/VCLExampleHitMissHeader#Varnish3.0
    if ( beresp.ttl <= 0s ) {
      /* Varnish determined the object was not cacheable */
      set beresp.http.X-Varnish-Cacheable = "NO:Not Cacheable";
    } elsif ( bereq.http.Cookie ~ "(SESS|SSESS|NO_CACHE|OATMEAL|CHOCOLATECHIP)" ) {
      /* We don't wish to cache content for logged in users or with certain cookies. */
      # Related with our 9th stage on vcl_recv
      set beresp.http.X-Varnish-Cacheable = "NO:Cookies";
      # set beresp.uncacheable = true;
    } elsif ( beresp.http.Cache-Control ~ "private" ) {
      /* We are respecting the Cache-Control=private header from the backend */
      set beresp.http.X-Varnish-Cacheable = "NO:Cache-Control=private";
      # set beresp.uncacheable = true;
    } else {
      /* Varnish determined the object was cacheable */
      set beresp.http.X-Varnish-Cacheable = "YES";
    }
    # We can also unset some headers to prevent information disclosure and save
    # some cache space.
    # unset beresp.http.Server;
    # unset beresp.http.X-Powered-By;
    # Retry count.
    if ( bereq.retries > 0 ) {
      set beresp.http.X-Varnish-Retries = bereq.retries;
    }
  # }
  sub vcl_backend_error {
    # Please consider the risks of showing publicly this information, we can wrap
    # this with an ACL.
    # Retry count
    if ( bereq.retries > 0 ) {
      set beresp.http.X-Varnish-Retries = bereq.retries;
    }
  }

Source: https://github.com/NITEMAN/varnish-bites/blob/master/varnish4/drupal-base.vcl

Collected: 16th August 2016