1

I have a varnish running on centos 7. My site works whit Drupal. Varnish work perfectly, but the browsers cache stuff as well and it affects what users are seeing.

When adding posts to the site varnish resets the cache, but the browser cache shows the old cached data.

How can I disable caching on browsers whit out it effecting varnish.

My default.vcl:

# This is a basic VCL configuration file for varnish.  See the vcl(7)
# man page for details on VCL syntax and semantics.
# 
# Default backend definition.  Set this to point to your content
# server.
# 
backend default {
  .host = "mysite.com";
  .port = "6060";
  .connect_timeout = 3600s;
  .first_byte_timeout = 3600s;
  .between_bytes_timeout = 3600s;
}

# 
# Below is a commented-out copy of the default VCL logic.  If you
# redefine any of these subroutines, the built-in logic will be
# appended to your code.
# 
 sub vcl_recv {
 
   # Add a unique header containing the client address
  remove req.http.X-Forwarded-For;
  set    req.http.X-Forwarded-For = client.ip;
 
   # set the custom header
   if (req.http.Cookie ~ "ABtesting=B") {
  set req.http.X-ABtesting = "B";
   } else {
  set req.http.X-ABtesting = "A";
   }
 
 # do this only once per request
 if (req.restarts == 0) {
   # normalize Accept-Encoding to reduce vary
   if (req.http.Accept-Encoding) {
  if (req.http.User-Agent ~ "MSIE 6") {
    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;
  }
   }
 }
 
 if (req.http.User-Agent ~ "(Mobile|Android|iPhone|iPad)") {
   set req.http.User-Agent = "mobile";
 } else {
   set req.http.User-Agent = "desktop";
 }
 
 
     if (req.request != "GET" &&
       req.request != "HEAD" &&
       req.request != "PUT" &&
       req.request != "POST" &&
       req.request != "TRACE" &&
       req.request != "OPTIONS" &&
       req.request != "DELETE") {
         /* Non-RFC2616 or CONNECT which is weird. */
         return (pipe);
     }
     if (req.request != "GET" && req.request != "HEAD") {
         /* We only deal with GET and HEAD by default */
         return (pass);
     }
 // Remove has_js and Google Analytics __* cookies.
 set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(_[_a-z]+|has_js)=[^;]*", "");
 // Remove a ";" prefix, if present.
 set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
     if (req.http.Authorization /*|| req.http.Cookie*/) {
         /* Not cacheable by default */
         return (pass);
     }
     return (lookup);
 }

# 
# sub vcl_pipe {
#     # Note that only the first request to the backend will have
#     # X-Forwarded-For set.  If you use X-Forwarded-For and want to
#     # have it set for all requests, make sure to have:
#     # set bereq.http.connection = "close";
#     # here.  It is not set by default as it might break some broken web
#     # applications, like IIS with NTLM authentication.
#     return (pipe);
# }
# 
# sub vcl_pass {
#     return (pass);
# }
# 
# sub vcl_hash {
#     set req.hash += req.url;
#     if (req.http.host) {
#         set req.hash += req.http.host;
#     } else {
#         set req.hash += server.ip;
#     }
#     return (hash);
# }
# 
# sub vcl_hit {
#     if (!obj.cacheable) {
#         return (pass);
#     }
#     return (deliver);
# }
# 
# sub vcl_miss {
#     return (fetch);
# }
# 
 sub vcl_fetch {
 
    # vary on the custom header
   if (beresp.http.Vary) {
  set beresp.http.Vary = beresp.http.Vary ", X-ABtesting";
   } else {
  set beresp.http.Vary = "X-ABtesting";
   }
     if (!beresp.cacheable) {
         return (pass);
     }
     if (beresp.http.Set-Cookie) {
         return (pass);
     }
     return (deliver);
 }
 
 sub vcl_deliver {
 if (resp.http.Vary) {
    set resp.http.Vary = regsub(resp.http.Vary, "X-ABtesting", "Cookie");
 }
 
     return (deliver);
 }
# 
# sub vcl_error {
#     set obj.http.Content-Type = "text/html; charset=utf-8";
#     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">
# <html>
#   <head>
#     <title>"} obj.status " " obj.response {"</title>
#   </head>
#   <body>
#     <h1>Error "} obj.status " " obj.response {"</h1>
#     <p>"} obj.response {"</p>
#     <h3>Guru Meditation:</h3>
#     <p>XID: "} req.xid {"</p>
#     <hr>
#     <p>Varnish cache server</p>
#   </body>
# </html>
# "};
#     return (deliver);
# }
kiamlaluno
  • 24,790
  • 16
  • 70
  • 85
matisa
  • 412
  • 3
  • 20

2 Answers2

4

What you're looking for is different TTL for browser cache and Varnish cache.

The easiest solution, as outlined here would be the use of s-maxage directive inside Cache-Control, e.g.:

Cache-Control: s-maxage=31536000, max-age=300

Where 31536000 is the number of seconds it will be cached by Varnish and 300 is the number of seconds you want the resource to be cached in browsers.

Why this works is because s-maxage overrides expiration for shared caches (which Varnish is) while not applying to private caches (which browsers are).

This is the most elegant solution in my opinion but requires you to adjust your backend app.

The other solution was outlined in this post and can be done by only adjusting your VCL:

    sub vcl_fetch {

            if (beresp.ttl > 0s) {
                    /* Remove Expires from backend, it's not long enough */
                    unset beresp.http.expires;

                    /* Set the clients TTL on this object */
                    set beresp.http.cache-control = "max-age=900";

                    /* Set how long Varnish will keep it */
                    set beresp.ttl = 1w;

                    /* marker for vcl_deliver to reset Age: */
                    set beresp.http.magicmarker = "1";
            }
    }

    sub vcl_deliver {
            if (resp.http.magicmarker) {
                    /* Remove the magic marker */
                    unset resp.http.magicmarker;

                    /* By definition we have a fresh object */
                    set resp.http.age = "0";
            }
    }
Danila Vershinin
  • 6,133
  • 2
  • 20
  • 25
0

To control caching on the browser end you have to use Cache-Control response header. See here. You should have control over this header in your Drupal code.

George
  • 300
  • 3
  • 11