Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Any one know why we are getting a very low cache hit rate average when using Wordpress (With Varnish and Nginx)?

Varnish stat shows :

Hitrate ratio: 10 100 518 Hitrate avg: 0.4143 0.2690 0.1948

Any idea how to fix this? My varnish default.vcl is :

# 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 = "77.81.240.177";
    .port = "8080";
}

acl purge {
    "77.81.240.177";
}

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    req.http.X-Forwarded-For = req.http.rlnclientipaddr;    

    # Let's make sure we aren't compressing already compressed formats.
    if (req.http.Accept-Encoding) {
        if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|mp3|mp4|m4v)(\?.*|)$") {
            remove 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 {
            remove req.http.Accept-Encoding;
        }
    }

    if (req.request == "PURGE") {
        if (!client.ip ~ purge) {
            error 405 "Not allowed.";
        }
        return(lookup);
    }

    if (req.url ~ "^/$") {
        unset req.http.cookie;
    }
}

sub vcl_hit {
    if (req.request == "PURGE") {
        set obj.ttl = 0s;
        error 200 "Purged.";
    }
}

sub vcl_miss {
    if (req.request == "PURGE") {
        error 404 "Not in cache.";
    }

    if (!(req.url ~ "wp-(login|admin)")) {
        unset req.http.cookie;
    }

    if (req.url ~ "^/[^?]+.(jpeg|jpg|png|gif|ico|js|css|txt|gz|zip|lzma|bz2|tgz|tbz|html|htm)(\?.|)$") {
        unset req.http.cookie;
        set req.url = regsub(req.url, "\?.$", "");
    }

    if (req.url ~ "^/$") {
        unset req.http.cookie;
    }
}

sub vcl_fetch {
    if (req.url ~ "^/$") {
        unset beresp.http.set-cookie;
    }

    if (!(req.url ~ "wp-(login|admin)")) {
        unset beresp.http.set-cookie;
    }

    if (req.url ~ "^/w00tw00t") {
        error 403 "Not permitted";
    }
}
share|improve this question

2 Answers 2

up vote 4 down vote accepted

A good approach is to inspect the traffic with varnishlog in order to see what makes which rules apply.

Since you're not enforcing a TTL, my guess is that the wordpress site delivers Cache-Control headers like "max-age: 0", or "no-cache" "private" or something, and varnish honors such headers unless you specifically tell it not to, i.e:

 sub vcl_fetch {
     if (!(req.url ~ "wp-(login|admin)")) {
         unset beresp.http.set-cookie;
         set beresp.ttl = 3600s;
     }

First rule in vcl_fetch does not make sense, as second rule will unset all set-cookies for all urls but wp-login/wp-admin.


Add some config to vcl_deliver to output headers that states if it's a hit or not:

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

Other feedback to you config:

In vcl_recv, you do "unset req.http.cookie" if url is not wp-login or wp-admin, which means that if a user logs on /wp-login then goes to "/", you will unset his cookie. You only need to unset cookies in vcl_recv for urls that shouldn't ever need one, ie .(js|css|png|jpg) etc, and instead remove the set-cookie in vcl_fetch.

share|improve this answer
    
return (deliver); at the end of vcl_deliver is unnecessary; varnish automatically appends this –  yitwail Nov 12 '12 at 17:59

wp-varnish

Checkout wp-varnish - A plugin for WordPress that will purge content in Varnish when content in WordPress is changed. It also comes with a sample VCL which should give you a better hitrate

Sample VCL

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

acl purge {
  "localhost";
}

sub vcl_recv {
  if (req.request == "PURGE") {
    if(!client.ip ~ purge) {
      error 405 "Not allowed.";
    }
    return(lookup);
  }

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

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

  if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") {
    return (pass);
  }

  remove req.http.cookie;
  return (lookup);
}

sub vcl_hit {
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }
}

sub vcl_miss {
  if (req.request == "PURGE") {
    purge;
    error 200 "Purged.";
  }
}

sub vcl_fetch {
  if (req.url ~ "wp-(login|admin)" || req.url ~ "preview=true") {
    return (hit_for_pass);
  }

  set beresp.ttl = 24h;
  return (deliver);
}
share|improve this answer
    
Isn't it available in the wordpress repository? –  EApubs Mar 22 '12 at 13:01
    
Not the latest version. I will set up an automated routine this weekend to make the latest version automatically appear on wordpress.org. –  pkhamre Mar 23 '12 at 7:31
    
Sorry my friend, your plugin also doesn't work for me :( What shall i put for Varnish Secret ? –  EApubs Mar 23 '12 at 8:53
    
Do you use varnish-3.0? It should come with a file called /etc/varnish/secret –  pkhamre Mar 23 '12 at 9:09
    
Yes... i use varnish 3. So, what shall i put in that field? –  EApubs Mar 23 '12 at 9:16

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.