Wednesday, March 30, 2011

How can I log the client IP address on the backend in Varnish?

All I see is the IP address of the varnish server. How can I log the client IP address?

We will need to add the IP address to a header used for the backend request, and configure the backend to log the content of this header instead of the address of the connecting client (which is the varnish server).

Varnish configuration:

sub vcl_recv {
# Add a unique header containing the client address remove
set req.http.X-Forwarded-For = client.ip;
# [...] }

For the apache configuration, we copy the “combined” log format to a new one we call “varnishcombined”, for instance, and change the client IP field to use the content of the variable we set in the varnish configuration:

LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" varnishcombined

And so, in our virtualhost, you need to specify this format instead of “combined” (or “common”, or whatever else you use):

# [...]

CustomLog /var/log/apache2/ varnishcombined

# [...]

Reference: Varnish Website

Installing Varnish on Debian

Varnish is the key software that speeds up your web site. It is Open Source, built on industry standards and requires very few resources.

Install on Debian:

curl | apt-key add -
echo "deb $(lsb_release -s -c) varnish-2.1" >> /etc/apt/sources.list
apt-get update
apt-get install varnish

Change the Apache's port in /etc/apache2/ports.conf

NameVirtualHost *:8000

Listen 8000

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

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

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.

backend apache { 
.host = "";
.port = "8000"; }

acl purge {
""; }

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 " && == ";
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"; }

then Restart Apache2 and Varnish processes:

/etc/init.d/apache2 restart
/etc/init.d/varnish restart