Service de cache HTTP avec Varnish
Varnish est un service de reverse-proxy-cache (mandataire inversé avec cache) HTTP, autrement dit un accélérateur de sites web.
Varnish reçoit les requêtes HTTP des visiteurs :
-
s’il dispose de la réponse à la requête en cache, celle-ci est renvoyée directement au client depuis la mémoire du serveur,
-
s’il ne dispose pas de la réponse, Varnish s’adresse alors au serveur web. Il lui transmet la requête, récupère la réponse, la stocke dans son cache, et répond au client.
Fournir la réponse depuis le cache en mémoire permet d’améliorer les temps de réponse aux clients. En effet, dans ce cas, il n’y a pas d’accès aux disques physiques.
Par défaut, Varnish écoute sur le port 6081
et utilise le langage VCL (Varnish Configuration Language) pour sa configuration. Grâce au langage VCL, il est possible de décider ce qui doit ou ne doit pas être transmit au client, ce qui doit être stocké en cache, depuis quel site et comment la réponse peut être modifiée.
Varnish est extensible par l’utilisation de modules VMOD (Varnish Modules).
Principe de fonctionnement
Dans un fonctionnement basique d’un service Web, le client communique en TCP sur le port 80 directement avec le service.

Pour profiter du cache, le client doit communiquer avec le service web sur le port par défaut de Varnish 6081.

Pour rendre le service transparent au client, il faudra changer le port d’écoute par défaut de Varnish et des vhosts du service web.

Configuration du démon varnishd
Configuration du démon
La configuration du démon se fait dans le fichier /etc/varnish/varnish.params
sur RedHat et dans /etc/default/varnish
sous Debian :
-
Le fichier /etc/varnish/varnish.params sous RedHat
# Set this to 1 to make systemd reload try to switch VCL without restart. RELOAD_VCL=1 # Main configuration file. You probably want to change it. VARNISH_VCL_CONF=/etc/varnish/default.vcl # Default address and port to bind to. Blank address means all IPv4 # and IPv6 interfaces, otherwise specify a host name, an IPv4 dotted # quad, or an IPv6 address in brackets. # VARNISH_LISTEN_ADDRESS=192.168.1.5 VARNISH_LISTEN_PORT=6081 # Admin interface listen address and port VARNISH_ADMIN_LISTEN_ADDRESS=127.0.0.1 VARNISH_ADMIN_LISTEN_PORT=6082 # Shared secret file for admin interface VARNISH_SECRET_FILE=/etc/varnish/secret # Backend storage specification, see Storage Types in the varnishd(5) # man page for details. VARNISH_STORAGE="malloc,256M" # User and group for the varnishd worker processes VARNISH_USER=varnish VARNISH_GROUP=varnish # Other options, see the man page varnishd(1) #DAEMON_OPTS="-p thread_pool_min=5 -p thread_pool_max=500 -p thread_pool_timeout=300"
DAEMON_OPTS="-a :6081 \
-T localhost:6082 \
-f /etc/varnish/default.vcl \
-S /etc/varnish/secret \
-s default,256m"
Depuis systemctl
, changer les valeurs par défaut se fait en créant le fichier /etc/systemd/system/varnish.service.d/customexec.conf
:
/etc/systemd/system/varnish.service.d/customexec.conf
[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -a :80 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s default,256m
Cela aura pour effet de surcharger les valeurs par défaut dans la partie ExecStart
fournies avec Varnish.
Il faut ensuite relancer systemctl daemon-reload
pour s’assurer que systemd
prenne en compte les modifications avant de relancer Varnish.
Option | Observation |
---|---|
|
Ecoute les requêtes clientes sur les adresses IP et les ports spécifiés. Par défaut : toutes les adresses et sur le port |
|
Interface de gestion |
|
Fichier de configuration |
|
Fichier contenant le secret permettant l’authentification sur le port de gestion |
|
Spécifier un backend de stockage du cache. L’option peut être spécifiée plusieurs fois. Les types de stockage possibles sont |
|
Compile la VCL en langage C et l’affiche à l’écran. |
Test de la configuration et relance
Il est conseillé de vérifier la syntaxe de la VCL avant de relancer le démon varnishd.
Il s’agit de compiler en langage C le fichier de configuration VCL. Le service peut être redémarré si la compilation fonctionne et qu’aucune alarme n’est affichée.
varnishd -C -f /etc/varnish/default.vcl
ou utilisation du script init :
# /etc/init.d/varnish configtest
[...]
.hit_func = VGC_function_vcl_hit,
.init_func = VGC_function_vcl_init,
.miss_func = VGC_function_vcl_miss,
.pass_func = VGC_function_vcl_pass,
.pipe_func = VGC_function_vcl_pipe,
.purge_func = VGC_function_vcl_purge,
.recv_func = VGC_function_vcl_recv,
.synth_func = VGC_function_vcl_synth,
};
Puis purge du cache et rechargement de la configuration : (si RELOAD_VCL=1
) :
systemctl reload varnishd
ou
systemctl restart varnishd
Il est possible de vérifier qu’une page provient du cache varnish depuis les en-têtes de la réponse HTTP :

La langage VCL
Les sous-routines
Varnish utilise des fichiers VCL, segmentés en sous-routines comportant les actions a exécuter. Ces sous-routines sont exécutées uniquement dans les cas spécifiques qu’elles définissent. Dans le fichier par défaut /etc/varnish/default.vcl
, nous trouvons les routines vcl_recv
, vcl_backend_response
et vcl_deliver
.
# vim /etc/varnish/default.vcl
cat /etc/varnish/default.vcl
#
# This is an example VCL file for Varnish.
#
# It does not do anything by default, delegating control to the
# builtin VCL. The builtin VCL is called when there is no explicit
# return statement.
#
# See the VCL chapters in the Users Guide at https://www.varnish-cache.org/docs/
# and http://varnish-cache.org/trac/wiki/VCLExamples for more examples.
# Marker to tell the VCL compiler that this VCL has been adapted to the
# new 4.0 format.
vcl 4.0;
# Default backend definition. Set this to point to your content server.
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
}
sub vcl_backend_response {
}
sub vcl_deliver {
}
Sous-routine | Action |
---|---|
|
Cette routine est appelée avant l’envoi de la requête vers le backend. Dans cette routine, il est possible de modifier les en-têtes HTTP, cookies, choisir le backend, etc. Voir actions |
|
Cette routine est appelée après la réception de la réponse du backend ( |
|
Cette routine est utile pour modifier la sortie de Varnish. Si besoin de modifier l’objet final (ajouter ou supprimer un en-tête, …), il est possible de le faire dans |
Les opérateurs VCL
Opérateur | Action |
---|---|
|
assignation |
|
comparaison |
|
comparaison en association avec une expression régulière et des ACL |
|
négation |
|
et logique |
|
ou logique |
Les objets Varnish
|
Objet | Observation |
---|---|
|
l’objet requête. Quand Varnish reçoit la requête, |
|
l’objet requête à destination du serveur web. Varnish créé cet objet à partir de |
|
l’objet réponse du serveur web. Il contient les entêtes de l’objet en provenance de l’application. Il est possible de modifier la réponse du serveur dans la sous-routine |
|
la réponse HTTP qui va être envoyée au client. Cet objet est modifié dans la sous-routine |
|
l’objet tel que sauvegardé en cache. En lecture seule. |
Les actions varnish
Action | Observation |
---|---|
|
Quand |
|
Quand |
|
Cette action sert à gérer les flux. Varnish dans ce cas n’inspectera plus chaque requête mais laisse passer tous les bytes au serveur. |
|
Sert l’objet au client. En général depuis la sous-routine |
|
Recommence le processus de traitement de la requête. Les modifications de l’objet req sont conservées. |
|
La requête est de nouveau transférée au serveur d’application. Utilisé depuis |
En résumé, les interactions possibles entre les sous-routines et les actions sont illustrées dans le schéma ci-dessous :

Configuration des backends
Varnish utilise le terme backend
pour les vhosts qu’il doit mandater.
Plusieurs backend peuvent être défini sur le même serveur Varnish.
La configuration des backends se fait dans le fichier /etc/varnish/default.vcl
.
Gestion des ACL
# ACL de deny
acl deny {
"10.10.0.10"/32;
"192.168.1.0"/24;
}
Appliquer l’ACL :
# Bloquer les IP de l'ACL deny
if (client.ip ~ forbidden) {
error 403 "Acces interdit";
}
Ne pas cacher certaines pages :
# Ne pas mettre en cache les pages login et admin
if (req.url ~ "/(login|admin)") {
return (pass);
}
Paramètres POST et cookies
Varnish ne met jamais en cache les requêtes HTTP de type POST ou celle contenant des cookies (qu’ils proviennent du client ou du backend).
Si le backend utilise des cookies, alors aucun contenu ne sera mis en cache.
Pour corriger ce comportement, il est possible de déréferrencer les cookies de nos requêtes :
sub vcl_recv {
unset req.http.cookie;
}
sub vcl_backend_response {
unset beresp.http.set-cookie;
}
Répartir les requêtes sur différents backend
Dans le cas de l’hébergement de plusieurs sites, comme par exemple un serveur de document (doc.formatux.fr) et un blog (blog.formatux.fr), il est possible de répartir les requêtes vers le bon backend.
backend docs {
.host = "127.0.0.1";
.port = "8080";
}
backend blog {
.host = "127.0.0.1";
.port = "8081";
}
L’objet req.backend
est modifié en fonction de l’hôte appelé dans la requête HTTP dans la sous-routine vcl_recv
:
sub vcl_recv {
if (req.http.host ~ "^doc.formatux.fr$") {
set req.backend = nginx;
}
if (req.http.host ~ "^blog.formatux.fr$") {
set req.backend = ghost;
}
}
Répartir la charge
Varnish est capable de gérer la répartition de charge via des backends spécifiques appelés directors.
-
Le director
round-robin
distribue les requêtes aux backends en round-robin (alternativement). Il est possible d’affecter une pondération à chaque backend. -
Le director
client
distribue les requêtes en fonction d’une affinité de session (sticky session) sur n’importe quel élément de l’en-tête (par exemple avec un cookie de session). Un client est dans ce cas toujours renvoyé vers le même backend.
backend docs1 {
.host = "10.10.11.10";
.port = "8080";
}
backend docs2 {
.host = "10.10.11.11";
.port = "8080";
}
Le director
permet d’associer les 2 backends définis :
director docs_director round-robin {
{ .backend = docs1; }
{ .backend = docs2; }
}
Reste à définir le director
comme backend aux requêtes :
sub vcl_recv {
set req.backend = docs_director;
}
Configuration du système
Configuration du port 80 et 443
Modifier, sous debian le fichier /etc/default/varnish
:
DAEMON_OPTS="-a :80
-T localhost:6082
-f /etc/varnish/default.vcl
-S /etc/varnish/secret
...
Configuration d’un cache
Configuration d’un cache sur disque d'1G.
Modifier, sous debian le fichier /etc/default/varnish
:
DAEMON_OPTS="-a :80
-T localhost:6082
-f /etc/varnish/default.vcl
-S /etc/varnish/secret
...
-s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"
Adaptation d’Apache
Changement de ports réseau
Si le service Varnish est localisé sur le même serveur que le service Web (Apache ou Nginx), les deux services ne pourront plus écouter en même temps les ports par défaut 80 et 443.
Dans ce cas, il est d’usage de faire écouter le service web sur un port 8080, 8081, 8082 etc. et de laisser le port par défaut à Varnish.
#Listen 80
Listen 8080
Modification du LogFormat
Le service http étant reverse proxifié, le serveur web n’aura plus accès aux adresses IP du client mais à celui du service Varnish.
Pour prendre en compte le reverse proxy dans les logs Apache, modifier dans le fichier de configuration du serveur le format du journal d’évènement :
LogFormat "%{X-Forwarded-For}i %l %u %t "%r" %>s %b "%{Referer}i" "%{User-Agent}i"" varnishcombined
et prendre en compte ce nouveau format dans le vhost du site web :
CustomLog /var/log/httpd/www-access.log.formatux.fr varnishcombined
et rendre Varnish compatible :
# Compatibility with Apache format log
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;
}
}
Purge du cache
Le cache peut être purgé :
-
en ligne de commande :
# varnishadm 'ban req.url ~ .'
-
en utilisant un secret et un port différent du port par défaut :
# varnishadm -S /etc/varnish/secret -T 127.0.0.1:6082 'ban req.url ~ .'
-
avec l’interface CLI:
# varnishadm
varnish> ban req.url ~ ".css$"
200
varnish> ban req.http.host == docs.formatux.fr
200
varnish> ban req.http.host ~ .
200
-
via une requête HTTP PURGE :
$ curl -X PURGE http://www.example.org/foo.txt
Varnish doit être configuré pour accepter cette requête :
acl local {
"localhost";
"10.10.1.50";
}
sub vcl_recv {
# directive a placer en premier,
# sinon une autre directive risque de matcher avant
# et la purge ne sera jamais effectuée
if (req.method == "PURGE") {
if (client.ip ~ local) {
return(purge);
}
}
}
Gérer les backends par CLI
Les backends peuvent être marqués comme sick
ou healthy
en fonction des besoins d’administration ou de maintenance.
Cette action permet de sortir un noeud du pool sans avoir à modifier la configuration du serveur Varnish (et donc sans le relancer) ou sans stopper le service du backend.
Visualiser le status du backend
La commande backend.list
affiche l’ensemble des backends, même les backends qui ne disposent pas de healthcheck
(probe
).
$ varnishadm backend.list
Backend name Admin Probe
site.default probe Healthy (no probe)
site.front01 probe Healthy 5/5
site.front02 probe Healthy 5/5
Basculer un backend en status sick
La commande backend.set_health va permettre de basculer un backend d’un état à l’autre :
$ varnishadm backend.set_health site.front01 sick
Le backend est sorti du pool et ne reçoit plus de trafic :
$ varnishadm backend.list
Backend name Admin Probe
site.default probe Healthy (no probe)
site.front01 sick Sick 0/5
site.front02 probe Healthy 5/5
Notez que dans la colonne Admin
, le backend a été marqué explicitement comme sick
.
Rebasculer un backend en status healthy
De la même manière, le status peut être rebasculé en healthy
, ce qui n’est toutefois pas encore le même status qu' auto
(voir paragraphe suivant).
$ varnishadm backend.set_health site.front01 healthy
Le backend est de retour dans le pool, il reçoit à nouveau du trafic.
La gestion des journaux
Varnish écrit ses journaux en mémoire et en binaire afin de ne pas pénaliser ses performances. Lorsqu’il ne dispose plus d’espace en mémoire, il réécrit les nouveaux enregistrements par dessus les anciens, en repartant du début de son espace mémoire.
Les journaux peuvent être consultés avec les outils varnishstat (statistiques), varnishtop (top pour Varnish), varnishlog (journalisation verbeuse) ou varnishnsca (journaux au format NCSA comme Apache) :
# varnishstat
# varnishtop -i ReqURL
# varnishlog
# varnishnsca
Filtrer les journaux
L’option -q
permet d’appliquer des filtres sur les journaux via les commandes précédentes :
# varnishlog -q 'TxHeader eq MISS' -q "ReqHeader ~ '^Host: formatux\.fr$'"
# varnishncsa -q "ReqHeader eq 'X-Cache: MISS'"
Enregistrer les journaux sur disques
L’enregistrement des journaux sur disque est effectué par les démons varnishlog
et varnishnsca
en toute indépendance du démon varnishd.
Le démon varnishd continue a renseigner ses journaux en mémoire sans pénaliser ses performances vers les clients, puis les autres démons se charge de copier les enregistrements sur disque.