Varnish configuration to only cache for non-logged in users

10,191

Ok, in the end I managed to solve this using the following vcl file. Note that I added a couple of extra bits to allow cache expiration grace when the backend has died.

It seems my main failure was using unset req.http.Set-Cookie; when I should have been using unset obj.http.Set-Cookie; in the vcl_fetch section. (obj in vcl_fetch and req in vcl_recv section).

director rails_director round-robin {
  { 
    .backend = { 
      .host = "xxx.xxx.xxx.xxx"; 
      .port = "http";
      .probe = {
        .url = "/lbcheck/lbuptest";
        .timeout = 0.3 s;
        .window = 8;
        .threshold = 3;
      }
    } 
  }
}

sub vcl_recv {

  if (req.backend.healthy) {
    set req.grace = 30s;
  } else {
    set req.grace = 1h;
  }

  if (req.url ~ "^/login") {
    pipe;
  }

  if (req.url ~ "^/sessions") {
    pipe;
  }

  if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
    unset req.http.cookie;
    lookup;
  } else {
    if (req.http.cookie ~ "user_credentials") {
      pipe;
    } else {
      unset req.http.cookie;
    }
  }

  # Only cache GET and HEAD requests
  if (req.request != "GET" && req.request != "HEAD") {
    pipe;
  }

}

sub vcl_fetch {

  set obj.grace = 1h;

  if (req.url ~ "^/login") {
    pass;
  }

  if (req.url ~ "^/sessions") {
    pass;
  }

  if (req.http.cookie ~ "user_credentials") {
    pass;
  } else {
    unset obj.http.Set-Cookie;
  }

  # cache CSS and JS files
  if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
    unset obj.http.Set-Cookie;
  } 

  if (obj.status >=400 && obj.status <500) {
    error 404 "File not found";
  }

  if (obj.status >=500 && obj.status <600) {
    error 503 "File is Temporarily Unavailable";
  }

}

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

Related videos on Youtube

davidsmalley
Author by

davidsmalley

Updated on September 17, 2022

Comments

  • davidsmalley
    davidsmalley almost 2 years

    I have a Ruby on Rails application fronted by varnish+nginx. As most of the sites content is static unless you are a logged in user, I want to cache the site heavily with varnish when a user is logged out but only to cache static assets when they are logged in.

    When a user is logged in they will have the cookie 'user_credentials' present in their Cookie: header, in addition I need to skip caching on /login and /sessions in order that a user can get their 'user_credentials' cookie in the first place.

    Rails by default does not set a cache friendly Cache-control header, but my application sets a "public,s-max-age=60" header when a user is not logged in. Nginx is set to return 'far future' expires headers for all static assets.

    The configuration I have at the moment is totally bypassing the cache for everything when logged in, including static assets — and is returning cache MISS for everything when logged out. I've spent hours going around in circles and here is my current default.vcl

        director rails_director round-robin {
      { 
        .backend = { 
          .host = "xxx.xxx.xxx.xxx"; 
          .port = "http";
          .probe = {
            .url = "/lbcheck/lbuptest";
            .timeout = 0.3 s;
            .window = 8;
            .threshold = 3;
          }
        } 
      }
    }
    
    sub vcl_recv {
    
      if (req.url ~ "^/login") {
        pipe;
      }
    
      if (req.url ~ "^/sessions") {
        pipe;
      }
      # The regex used here matches the standard rails cache buster urls
      # e.g. /images/an-image.png?1234567
      if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
        unset req.http.cookie;
        lookup;
      } else {
        if (req.http.cookie ~ "user_credentials") {
          pipe;
        }
      }
    
      # Only cache GET and HEAD requests
      if (req.request != "GET" && req.request != "HEAD") {
        pipe;
      }
    
    }
    
    sub vcl_fetch {
    
      if (req.url ~ "^/login") {
        pass;
      }
    
      if (req.url ~ "^/sessions") {
        pass;
      }
    
      if (req.http.cookie ~ "user_credentials") {
        pass;
      } else {
        unset req.http.Set-Cookie;
      }
    
      # cache CSS and JS files
      if (req.url ~ "\.(css|js|jpg|jpeg|gif|ico|png)\??\d*$") {
        unset req.http.Set-Cookie;
      } 
    
      if (obj.status >=400 && obj.status <500) {
        error 404 "File not found";
      }
    
      if (obj.status >=500 && obj.status <600) {
        error 503 "File is Temporarily Unavailable";
      }
    
    }
    
    sub vcl_deliver {
      if (obj.hits > 0) {
              set resp.http.X-Cache = "HIT";
      } else {
              set resp.http.X-Cache = "MISS";
      }
    }