You are here

Varnish and Apache in Ubuntu 10.04

This article is not related in any way with the others in this series, and it represents only another option instead of having NginX. Varnish is an HTTP accelerator, which serves static content from disk or RAM memory. Unlike Squid or other similar software that was created to be mainly a proxy, Varnish has resolved the problems of having data in the virtual memory, and was created from ground up as an HTTP accelerator. It is also very configurable allowing a multitude of uses.

You will probably ask how is this different from memcached, used in conjunction with nginx. The answer is that they are two completely different systems, varnish is an accelerator while memcached is an in-memory key-value store for small chunks of arbitrary data.

Now let's install a typical LAMP system, that everybody blames as being slow and memory consuming. By simply adding varnish as a buffer in front of it, you will notice not only a more linear memory consumption but also an increase in the speed.

We will start by installing MySQL:

apt-get install mysql-server mysql-client

Now bring the example configuration. The path might be different in your case though.

cp -f /usr/share/doc/mysql-server-5.1/examples/my-medium.cnf /etc/mysql/my.cnf
/etc/init.d/mysql restart

Install apache and enable a few modules:

apt-get install apache2-mpm-prefork apache2-utils
a2enmod rewrite
a2enmod expires
a2enmod headers

Slow it down by limiting the max clients in the /etc/apache2/apache2.conf file:

<IfModule mpm_prefork_module>
        StartServers 1
        MinSpareServers 3
        MaxSpareServers 9
        ServerLimit 24
        MaxClients 24
        MaxRequestsPerChild 3000
</IfModule>

Install PHP and a few extra modules, such as suhosin for increased security and APC, an opcode cache:

apt-get install php5 php5-mysql libapache2-mod-php5 php5-suhosin php5-dev php-pear php5-curl php5-cli php5-gd php-apc

Enable the APC engine:

echo"apc.enabled = 1
apc.shm_size = 128
apc.shm_segments=1
apc.write_lock = 1
apc.rfc1867 = On
apc.ttl=7200
apc.user_ttl=7200
apc.num_files_hint=1024
apc.mmap_file_mask=/tmp/apc.XXXXXX
apc.enable_cli=1
apc.slam_defense = Off
"
>> /etc/php5/conf.d/apc.ini

And now Varnish:

curl http://repo.varnish-cache.org/debian/GPG-key.txt | apt-key add -
echo "deb http://repo.varnish-cache.org/debian/ $(lsb_release -s -c) varnish-2.1" >> /etc/apt/sources.list
apt-get update
apt-get install varnish

Now, before you start the servers, let's adjust Apache and Varnish to work together. First change the default port for your virtual host in apache:

vi /etc/apache2/sites-available/default

Change from <VirtualHost *:80> into <VirtualHost *:8008> (this is just a preference)

The configuration daemon for Varnish is located in /etc/default/varnish. Here you can pass the startup options:

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

-f /etc/varnish/default.vcl is the configuration file, and -s malloc,256M means that I allowed Varnish to use 256M of my RAM. Further configurations are very well documented in the comments of this file. For me, setting Varnish to use the disk instead of the virtual memory wasn't too much of an improvement. Of course if you have more memory to spare, you can allow it to use more. -a 80 is the port on which varnish listens, which is the default 80 (we want it in front of Apache), and -T localhost:6082 is the administration panel.

Now let's get to the configuration file (/etc/varnish/default.vcl). This is a very simple use of Varnish which strips the cookies of some static files, like jpg and png, allowing them to be cached. In my case this works best, and it also gives me a header information of what was cached and what not (if you check the headers with something like FireBug). Of course you can find even better configurations available. Having a specific configuration for your platform, like Drupal or WordPress, is not a bad thing either.

backend apache {
        .host = "127.0.0.1";
        .port = "8008";
}

acl purge {
        "localhost";
        "127.0.0.1";
}

sub vcl_recv {

        // Strip cookies for static files:
        if (req.url ~ "\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$") {
                unset req.http.Cookie;
                return(lookup);
        }      

        // Remove has_js and Google Analytics __* cookies.
        set req.http.Cookie = regsuball(req.http.Cookie, "(^|;\s*)(__[a-z]+|has_js)=[^;]*", "");
       
        // Remove a ";" prefix, if present.
        set req.http.Cookie = regsub(req.http.Cookie, "^;\s*", "");
       
        // Remove empty cookies.
        if (req.http.Cookie ~ "^\s*$") {
                unset req.http.Cookie;
        }
       
        if (req.request == "PURGE") {
                if (!client.ip ~ purge) {
                        error 405 "Not allowed.";
                }
                purge("req.url ~ " req.url " && req.http.host == " req.http.host);
                error 200 "Purged.";
        }      
}

sub vcl_hash {
  if (req.http.Cookie) {
    set req.hash += req.http.Cookie;
  }
}

sub vcl_fetch {

        // Strip cookies for static files:
        if (req.url ~ "\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|pdf|txt|tar|wav|bmp|rtf|js|flv|swf|html|htm)$") {
                unset beresp.http.set-cookie;
        }

        // 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   = 300s;
                set beresp.grace = 300s;
                set beresp.http.X-Cacheable = "YES:Forced";
        }
       
        // Varnish determined the object was cacheable
        else {
                set beresp.http.X-Cacheable = "YES";
        }

        return(deliver);
}

You can make sure that it works by checking the headers for: Via - 1.1 Varnish


If you found this useful and you want to contribute, please consider sending a donation (click the button below).

Add new comment

Recent comments