19

I want to use Varnish to cache certain pages even in the presence of cookies. There are 3 possibilities that I need to take care of:

  1. An anonymous user is viewing some page
  2. A logged in user is viewing some page with light customization. These customizations are all stored in a signed-cookie and are dynamically populated by Javascript. The vary-cookie http header is not set.
  3. A logged in user is viewing some page with customized data from the database. The vary-cookie http header is set.

The expected behaviors would be:

  1. Cache the page. This is the most basic scenario for Varnish to handle.
  2. Cache the page and do not delete the cookie because some Javascript logic needs it.
  3. Never cache this page because vary-cookie is signalling the cookie contents will affect the output of this page.

I have read some docs on Varnish and I cannot tell if this is the default behavior or if there is some setup I have to do in VCL to make it happen.

Jason Christa
  • 12,150
  • 14
  • 58
  • 85

1 Answers1

19

Only sessions are unique to every client, not necessarily cookies.

What you want makes sense and is possible with Varnish, it is just a matter of carefully crafting your own vcl. Please pay attention to the following parts of the default.vcl:

sub vcl_recv {
    ...
    if (req.http.Authorization || req.http.Cookie) {
      /* Not cacheable by default */
      return (pass);
    }
}


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


sub vcl_fetch {
    if (!beresp.cacheable) {
        return (pass);
    }
    if (beresp.http.Set-Cookie) {
        return (pass);
    }
    ...
}

You have to replace these parts with your own logic; i.e. define your own vcl_ functions. By default, requests (vcl_recv) and responses (vcl_fetch) with cookies are not cacheable. You know your back-end application best and you should rewrite the generic caching logic to this specific case. That is, you should define in which case varnish does a lookup, pass or deliver.

In your case, you will have pages (case 1 and 2) without a vary-by cookie, which will be cached and shared by everyone (requests with/without cookies); just don't mind req.http.Cookie in vcl_recv. I wouldn't cache pages (case 3) with a vary-by cookie -or at least not for a long time-, as they can not be shared at all; do a 'pass' in vcl_fetch.

ivy
  • 5,539
  • 1
  • 34
  • 48
  • So in *vcl_fetch*, I would want to do: *if (beresp.http.Vary ~ "Cookie") { return (pass); }*. – Jason Christa Nov 30 '10 at 17:17
  • 1
    Yes. And in vcl_recv you should not fall back on the default behavior, but do a lookup "even" if req.http.Cookie is set. I do not completely understand your application, but I would watch out with caching responses that do a Set-Cookie. It does make sense to do some set-cookie stuff (and not cache this), and serve cached responses with javascript that does things based on cookie-values (just check closely where you 'trust' the client). – ivy Nov 30 '10 at 23:01
  • Im having almost the same problem here. My vcl_recv ends with a return (lookup), and my vcl_fetch is this: sub vcl_fetch { if (req.backend == dinamic){ esi; } if (req.backend == static){ unset beresp.http.set-cookie; } } but still, all requests to the dinamic backend (that should be cached) arent... any idea? I'm tring to use esi to make a custom caching, but its getting useless since varnish is not caching anything that come from my application output. – Tiago Dec 01 '10 at 02:52
  • Hi Tiago, I don't have experience with ESI. Can you make sure your response is cached by adding "set obj.ttl=1h;" after ESI? – ivy Dec 01 '10 at 09:34