Gilbert Cao
E-mail: gilbert.cao@rmrf.it
Varnish Cache est un reverse-proxy HTTP qui a pour fonction principale d'accélérer le rendu des contenus Web. Il est typiquement :
Son mode de configuration s'appuie sur un langage de script, appelé VCL (Varnish Configuration Language). Ci-dessous, un script VCL classique, avec mise en cache des ressources de type image (JPEG, PNG et GIF) :
# $hika
# Last-Modified: 2012-12-03
#
# VCL configuration file for varnish. See the vcl(7)
# man page for details on VCL syntax and semantics.
#
# Default backend definition. Set this to point to your content
# server.
#
backend default {
.host = "127.0.0.1";
.port = "8080";
.max_connections = 250;
}
backend lighttpd {
.host = "127.0.0.1";
.port = "8001";
.max_connections = 100;
}
acl purge {
"localhost";
}
#
# Below is a commented-out copy of the default VCL logic. If you
# redefine any of these subroutines, the built-in logic will be
# appended to your code.
sub vcl_recv {
if (req.restarts == 0)
{
# if (req.http.x-forwarded-for)
# {
# set req.http.X-Forwarded-For =
# req.http.X-Forwarded-For + ", " + client.ip;
# }
# else
# {
# set req.http.X-Forwarded-For = client.ip;
# }
set req.http.X-ClientIP-From-Varnish = client.ip;
}
if (req.request == "PURGE")
{
if (!client.ip ~ purge)
{
error 405 "Not allowed !";
}
return (lookup);
}
if (req.request != "GET" &&
req.request != "HEAD" &&
req.request != "PUT" &&
req.request != "POST" &&
req.request != "TRACE" &&
req.request != "OPTIONS" &&
req.request != "DELETE")
{
# Non-RFC2616 or CONNECT which is weird.
return (pipe);
}
# if (req.url ~ "\.(jpeg|jpg|png|gif)$")
# {
# Remove the cookie and make the request static
# unset req.http.cookie;
# return (lookup);
# }
if (req.request != "GET" && req.request != "HEAD")
{
# We only deal with GET and HEAD by default
return (pass);
}
# if (req.http.Authorization || req.http.Cookie)
# {
# # Not cacheable by default
# return (pass);
# }
if (req.http.host == "video.mondomain.fr"
&& req.url ~ "^/video/")
{
set req.url = regsub(req.url, "^/video/(.+)", "\1");
set req.backend = lighttpd;
}
# Default, lookup on cache.
return (lookup);
}
#
# sub vcl_pipe {
# # Note that only the first request to the backend will have
# # X-Forwarded-For set. If you use X-Forwarded-For and want to
# # have it set for all requests, make sure to have:
# # set bereq.http.connection = "close";
# # here. It is not set by default as it might break some broken web
# # applications, like IIS with NTLM authentication.
# return (pipe);
# }
#
# sub vcl_pass {
# return (pass);
# }
#
# sub vcl_hash {
# hash_data(req.url);
# if (req.http.host) {
# hash_data(req.http.host);
# } else {
# hash_data(server.ip);
# }
# return (hash);
# }
#
sub vcl_hit {
if (req.request == "PURGE")
{
purge;
error 200 "Purged.";
}
return (deliver);
}
sub vcl_miss {
if (req.request == "PURGE")
{
purge;
error 404 "Not purged (Cache missed).";
}
return (fetch);
}
sub vcl_fetch {
if (req.http.cache-control ~ "(no-cache|private)"
|| req.http.pragma == "no-cache"
|| beresp.status >= 300)
{
# Do not use cache
set beresp.ttl = 0s;
}
# If the request is static
# elseif (req.url ~ "\.(jpeg|jpg|png|gif)$")
# {
# # Cache it, and make it last 5 minutes
# set beresp.ttl = 300s;
# # Make the request static by removing any cookies set by those static files
# unset beresp.http.Set-Cookie;
# }
else
{
# Default, no cache
set beresp.ttl = 0s;
}
return (deliver);
}
sub vcl_deliver {
# Display hit/miss info
if (obj.hits > 0)
{
set resp.http.X-Cache = "HIT";
set resp.http.X-Cache-Hits = obj.hits;
}
else
{
# set resp.http.X-Cache = "MISS";
# No need to display "Age: 0"
unset resp.http.Age;
}
# Hide some informations
unset resp.http.Via;
unset resp.http.X-Varnish;
unset resp.http.X-Powered-By;
return (deliver);
}
sub vcl_error {
set obj.http.Content-Type = "text/html; charset=utf-8";
set obj.http.Retry-After = "5";
unset obj.http.Server;
unset obj.http.X-Cache;
synthetic {"
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>"} + obj.status + " " + obj.response + {"</title>
</head>
<body>
<h1>Error "} + obj.status + " " + obj.response + {"</h1>
<hr>
</body>
</html>
"};
return (deliver);
}
#
# sub vcl_init {
# return (ok);
# }
#
# sub vcl_fini {
# return (ok);
# }
Il est relativement flexible dans l'élaboration, l'évolution et la maintenance de ses propres règles. Vous trouverez, ci-dessous, une méthode pour la prise en compte des modifications du script VCL actif, sans avoir à redémarrer le service :
#!/bin/sh
# Reload a varnish config
CONFIG_FILE="/usr/local/etc/varnish.vcl"
VARNISH_ADM="localhost:6082"
CONFIG1_NAME="vcl1"
CONFIG2_NAME="vcl2"
_S=`basename $0`
CURRCONFIG_NAME=`varnishadm -t 1 -T $VARNISH_ADM vcl.list 2>/dev/null | grep active | awk '{ print $3 }'`
if [ ! -z $CURRCONFIG_NAME ]; then
echo "$_S : Current config ($CURRCONFIG_NAME)."
if [ $CURRCONFIG_NAME = $CONFIG1_NAME ]; then
# Current configuration $CONFIG1_NAME in use.
# Load a new one
varnishadm -t 1 -T $VARNISH_ADM vcl.load $CONFIG2_NAME $CONFIG_FILE >/dev/null 2>&1
if [ $? -eq 0 ]; then
varnishadm -t 1 -T $VARNISH_ADM vcl.use $CONFIG2_NAME >/dev/null 2>&1
echo "$_S : Varnishd reloaded ($CONFIG2_NAME)."
varnishadm -t 1 -T $VARNISH_ADM vcl.discard $CONFIG1_NAME >/dev/null 2>&1
else
echo "$_S : Cannot load $CONFIG_FILE."
fi
elif [ $CURRCONFIG_NAME = $CONFIG2_NAME ] || [ $CURRCONFIG_NAME = "boot" ]; then
# Current configuration $CONFIG2_NAME (or "boot") in use.
# Load $CONFIG1_NAME configuration.
varnishadm -t 1 -T $VARNISH_ADM vcl.load $CONFIG1_NAME $CONFIG_FILE >/dev/null 2>&1
if [ $? -eq 0 ]; then
varnishadm -t 1 -T $VARNISH_ADM vcl.use $CONFIG1_NAME >/dev/null 2>&1
echo "$_S : Varnishd reloaded ($CONFIG1_NAME)."
if [ $CURRCONFIG_NAME = $CONFIG2_NAME ]; then
varnishadm -t 1 -T $VARNISH_ADM vcl.discard $CONFIG2_NAME >/dev/null 2>&1
fi
else
echo "$_S : Cannot load $CONFIG_FILE."
fi
fi
fi
Autre fonctionnalité particulièrement appréciable : Varnish Cache n'est pas vulnérable aux attaques de type "slowloris". Ce qui le rend intéressant pour "protéger" un serveur Apache HTTPD.
Plus d'informations sur le site officiel.