Mark Dorison

Baking Your Blog with Varnish

With all the recent talk around the web about "baked blogs", I wanted to give setting up Varnish a shot on my blog which is powered by Drupal 7. Varnish can provide a specific speed boost; their about page describes what it does quite succinctly:

Varnish stores web pages in memory so the web servers don't have to create the same web page over and over again. The web server only recreate a page when it is changed. Additionally Varnish can serve web pages much faster then any application server is capable of - giving the website a significant speed up.

I wanted to get Varnish up and running on my personal web server as a learning exercise. During the time I was attempting to get started, Nate Haug of Lullabot published a hugely informative article on Configuring Varnish for High-Availability with Multiple Web Servers. This helped me out a lot, but the big difference was the last part of the title in Nate's post; "with Multiple Servers"; I only have just the one.

As I worked through some different configuration issues I quickly came to realize that there is not a great deal of information out there on this type of setup so I decided to document my experience. Before I really begin, I should preface this by saying that I am a Varnish novice. Your mileage may vary based on these instructions but this is what worked for me.

Getting Varnish Installed #

I scoured Google to find some specific instructions on how to install Varnish on CentOS. Turns out, I should have started with the official site. It's two lines, and it worked like a charm.

rpm --nosignature -i http://repo.varnish-cache.org/redhat/el5/noarch/varnish-release-2.1-2.noarch.rpm
yum install varnish

Getting Varnish Running #

Since I am setting this up on a single box, what I wanted was Varnish on port 80 and Apache on port 8080 so that when users type the domain in their browser, their request will go through Varnish by default. Nevertheless, I recommend setting it up in reverse for testing purposes and then once you have everything running smoothly, switching the ports.

Depending on how you have your server configured, you probably will need to open up your firewall to allow connections on port 8080 for testing. You can do this by editing the iptables configuration located at /etc/sysconfig/iptables and adding the following rule:

-A INPUT -p tcp -m tcp --dport 8080 -j ACCEPT

Save your changes and then restart iptables:

/etc/init.d/iptables restart

Before you start Varnish you need to edit two configuration files. The first is located at /etc/sysconfig/varnish. Two items are of note.

  1. The first is the port, 8080, on the first line. This is the port that you are setting up Varnish to listen on. You will need to come back and change this to answer on port 80 once we are ready to serve from Varnish.
  2. The second item is the last line, which specifies the amount of memory to be made available to Varnish. In a setup where Varnish is running on a dedicated server, it is normal to max out the memory here. However, in this configuration, sharing a server with Apache, I have set the memory allocation to be one half of the available memory. So on a server with 1GB, I would set the memory allocation to 512M. [^1]
DAEMON_OPTS="-a :8080 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-u varnish -g varnish \
-S /etc/varnish/secret \
-p thread_pool_add_delay=2 \
-p thread_pools=<Number of CPU cores> \
-p thread_pool_min=<800 / Number of CPU cores> \
-p thread_pool_max=4000 \
-p session_linger=50 \
-p sess_workspace=262144 \
-s malloc,<Available memory / 2>"

The VCL #

The second configuration file that needs to be changed is a bit more daunting. This is the .vcl configuration file that is located at /etc/varnish/default.vcl. I used some of the configurations listed in Lullabot's example vcl but not all of these make sense for a single server setup. For instance, I removed all references to multiple backends and SSL configurations as I am not making use of these. My vcl config file can be referenced here. I am not going to go through the vcl line by line, since Nate did a really great job of that, but below are a couple important pieces.

The backend(s) you specify is where Varnish is going to send your web requests when they get passed through. In this case this is Apache. For testing we have left Apache on port 80.

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

Why was there a hit/miss? #

You can use the following to your vcl config to add diagnostic headers to the response indicating why there was a Varnish cache hit or miss. You can view these headers by using the Net tab in the Firefox extension, Firebug. [^2]

# Varnish determined the object was not cacheable
if (!beresp.cacheable) {
set beresp.http.X-Cacheable = "NO:Not Cacheable";

# You don't wish to cache content for logged in users
} elsif (req.http.Cookie ~ "(UserID|_session)") {
set beresp.http.X-Cacheable = "NO:Got Session";
return(pass);

# You are respecting the Cache-Control=private header from the backend
} elsif (beresp.http.Cache-Control ~ "private") {
set beresp.http.X-Cacheable = "NO:Cache-Control=private";
return(pass);

# You are extending the lifetime of the object artificially
} elsif (beresp.ttl < 1s) {
set beresp.ttl = 5s;
set beresp.grace = 5s;
set beresp.http.X-Cacheable = "YES:FORCED";

# Varnish determined the object was cacheable
} else {
set beresp.http.X-Cacheable = "YES";
}

return(deliver);

Going Live #

Once you have Varnish up and running, and have tuned it to your liking, you should then switch the ports that Varnish/Apache are listening on so that requests on port 80 from the web pass hit Varnish first.

Update the following two settings in your Apache configuration to listen on port 8080. (/etc/httpd/conf/httpd.conf)

Listen 8080

NameVirtualHost *:8080

You will also need to update any VirtualHost files you are using to listen on port 8080 instead of port 80.

You will then need to reconfigure Varnish to listen on port 80. These files should now be familiar to you /etc/sysconfig/varnish:

DAEMON_OPTS="-a :80 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-u varnish -g varnish \
-S /etc/varnish/secret \
-p thread_pool_add_delay=2 \
-p thread_pools= \
-p thread_pool_min=<800 / Number of CPU cores> \
-p thread_pool_max=4000 \
-p session_linger=50 \
-p sess_workspace=262144 \
-s malloc,"

Update the vcl configuration file so that Varnish is looking for the backend (Apache) on port 8080:

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

Once these configuration changes are complete, you will need to stop both Apache & Varnish and then start both again.

[^1]: I do not know if this is the most efficient setting. It seemed logical.
[^2]: VCLExampleHitMissHeader

← Home