Using Varnish with Rails

Varnish is an open source cache (more accurately a reverse HTTP proxy or web accelerator) that can be used to speed up HTTP delivery to clients. It has many great features built specifically for HTTP caching and is very stable.

You can use Varnish with Rails to speed up your site delivery. Here is a quick guide about that.

Installing Varnish (on Ubuntu)

Installing Varnish is easy. Here is an example:

apt-get install apt-transport-https  
curl https://repo.varnish-cache.org/GPG-key.txt | apt-key add -  
echo "deb https://repo.varnish-cache.org/ubuntu/ precise varnish-4.0" >> /etc/apt/sources.list.d/varnish-cache.list  
apt-get update  
apt-get install varnish  

Configuring Varnish

A minimum Varnish needs to be configured with two settings: the front end (where it serves the clients) and the backend where it connects to your application.

Configuration exists in /etc/varnish/default.vcl. Open in your favourite editor and start editing:

$ vi /etc/varnish/default.vcl
backend default {  
    .host = "127.0.0.1";
    .port = "8080";
}

This is the default value for the backend part where Varnish connects to your application. If you Varnish is going to share a server with your application then you can leave this as it is as long as your application server (Passenger or Unicorn for example) serve on port 8080.

This is usually not the case as you really want to have your Varnish servers to sit in front of your web servers. In this case, you usually have multiple backends defined in default.vcl file:

backend web1 {  
    .host = "web1.domain.com";
    .port = "8080";
}
backend web2 {  
    .host = "web2.domain.com";
    .port = "8080";
}

Now that you have the backend configured, you can configure the frontend part. Move over to your favourite editor and edit /etc/default/varnish:

$ vi /etc/default/varnish

change this line:

DAEMON_OPTS="-a :6081 \  
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

to

DAEMON_OPTS="-a :80 \  
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

Now you can start Varnish:

$ service varnish start

Configuring Rails

To make sure Rails sends the right HTTP headers over to Varnish, open application_controller.rb and add the following method:

before_filter :set_cache_control_headers, if: :is_prod?

protected

def is_prod?  
    Rails.env.production?
end

def set_cache_control_headers(max_age = 5.minutes.to_s)  
     response.headers['Cache-Control'] = 'public, no-cache'
     response.headers['Surrogate-Control'] = "max-age=#{max_age}"
end  

The is_prod? method is optional if you see the cache settings getting in your way during development.

High Availability

Now you have 1 Varnish server backed by multiple application servers. You can increase this number to multiple Varnish servers and use a load balancer (AWS Elastic Load Balancer if you're running on AWS for example) in front of them to increase your availability.

Try Cloud 66 for Free, No credit card required