Varnish Tips and Tricks

Varnish Tips and Tricks

default avatar
AfYuriy Gerasimov
februar 18, 2015
Varnish Tips and Tricks

In this article we would like to share some use cases and recipes for configuring Varnish.

Use custom data for building varnish cache hash

By default, Varnish uses URL as a parameter for caching. In the VCL file, it is also possible to add custom data (for example: location, or custom header value) to hashing by using the sub vcl_hash{} configuration part. But there is yet another solution to be used that Varnish comes equipped with out of the box. We can set a Vary header that is respected. So, if we want our cache to be based on header X-MyCustomHeader in Drupal, then we can set the header to

Vary: Cookie,Accept-Encoding,X-MyCustomHeader. This way, different values of our custom header will have different cache records in Varnish.

Limit access to the site by ip address

When we build an intranet website, we can limit access to it on the Varnish level. This can be done in following way:
First we define list of allowed IP addresses:

acl
offices { "localhost"; "127.0.0.1"; "1.2.3.4";` "5.6.7.8"; }

Then we restrict access to non matching addresses:

sub vcl_recv {
  
 if ( req.http.host ~ "(intranet\.example\.com)$" && !(client.ip ~ offices) ) {
       
 error 403 "Access denied";
   }
}

SSL termination

As Varnish is not handling https traffic, we need to terminate SSL before it hits Varnish. For that we can use nginx. Here is a list of links to articles that dive deeper into this topic:

https://www.digitalocean.com/community/tutorials/how-to-configure-varnish-cache-4-0-with-ssl-termination-on-ubuntu-14-04

http://edoceo.com/howto/nginx-varnish-ssl

http://mikkel.hoegh.org/2012/07/24/varnish-as-reverse-proxy-with-nginx-as-web-server-and-ssl-terminator/

https://wiki.deimos.fr/Nginx_%2B_Varnish_:_Cache_even_in_HTTPS_by_offloading_SSL

ESI

On a recent FFW project, we had the requirement to include a block with data from an external website without any caching. The tricky part was that the external site was providing XML with the data. The solution we implemented was to use ESI block pointing to the custom php file that was pulling that XML and parsing it on the fly.

Hiding js requests to external domains

If we need to do some CORS (http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) requests instead of our Javascript doing requests directly to external domain, we can do requests to our site, but with a specific URL. Then, on the Varnish level, we can redirect that request to external domain. In this case, Varnish will act like a proxy. This can be achieved with backend options.

backend google {
 .host = "209.85.147.106";
 
.port = "80";
}
sub vcl_fetch {
 if (req.url ~ "^/masq") {
   set req.backend = google;
   set req.http.host = "www.google.com";
   set req.url = regsub(req.url, "^/masq", "");
   remove req.http.Cookie;
   return(deliver);
 }
}

Multiple backends, load balancing

It is possible to define multiple backends for Varnish and switch between them. Most basic implementation is round robin or random. Here is an example:

backend web01 {
   .host = "example1";
   .port = "80";
   .connect_timeout = 120s;
   .first_byte_timeout = 300s;
   .between_bytes_timeout = 60s;
   .max_connections = 50;
   .probe = {
    .url = "/";
    .timeout = 10s;
    .interval = 20s;
    .window = 5;
    .threshold = 3;
   }
}
 

backend web02 {
   .host = "example2";
   .port = "80";
   .max_connections = 100;
   .connect_timeout = 120s;
   .first_byte_timeout = 300s;
   .between_bytes_timeout = 60s;
   .probe = {
       .url = "/";
       .timeout = 10s;          
       .interval = 20s;       
       .window = 5;
       .threshold = 3;
   }
}
 
director apache round-robin {
 { .backend = web01; }
 { .backend = web02; }
}
 
sub vcl_recv {
 set req.backend = apache;
}

It is also possible to set a specific backend for visitors coming from specific IP addresses. This can have a number of helpful uses, such as making sure that the editors team has a dedicated backend server.

if (client.ip ~ offices) {
 
set req.backend = web03;
}

I hope you have enjoyed our tips regarding Varnish configuration. Please feel free to share your own thoughts and tips on Varnish in the comments below!