--- title: "Varnish : le comprendre et le configurer pour WordPress" date: "2023-04-06T11:59:18" draft: false slug: "utiliser-configurer-varnish-wordpress" wordpress_id: 5588 excerpt: "Varnish est un logiciel de mise en cache Web, open source qui accélère la distribution de contenu Web.…\n" featured_image: "https://www.mistergeek.net/wp-content/uploads/2023/04/Varnish-cache.png" author: "Kevin" categories: ["Informatique"] tags: [] section: "informatique" ---
Varnish est un logiciel de mise en cache Web, open source qui accélère la distribution de contenu Web. Il fonctionne en tant que reverse proxy, interceptant les requêtes des utilisateurs et stockant en mémoire cache les réponses renvoyées par le serveur web d’origine. Cette mise en cache permet d’économiser des ressources sur le serveur et de réduire les temps de réponse pour les utilisateurs finaux. Varnish Cache peut également être configuré pour effectuer des actions spécifiques par le biais de son langage de configuration, comme par exemple la suppression de cookies ou la modification du header (en-tête) HTTP. Il est utilisé par de nombreux sites Web à fort trafic dans le monde, y compris des sites de médias sociaux, des sites d’e-commerce et des sites de contenu en ligne. Parmi les sites utilisant Varnish, nous pouvons par exemple citer askubuntu.com, getbootstrap.com ou encore asana.com. Cette liste n’est pas exhaustive, mais le but n’est de vous citer tous les sites qui utilisent Varnish. Si vous êtes en quête d’un guide pour vous aider à installer et configurer Varnish, vous êtes au bon endroit. Vous découvrirez comment faire pour l’installer et l’utiliser en tant que reverse proxy avec Caddy, un serveur web.Table of Contents









# Installer les paquets nécessaires
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
# Récupèrer la clé GPG et l'ajoute à aptitude
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
# Ajouter les depots officiels
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
# Mettre à jour les dépôts
sudo apt update
# Installer Caddy
sudo apt install caddy
Selon votre pile technique actuelle, Caddy ne pourra (peut-être) pas démarrer car un serveur web écoute sur le port 80. Nous allons malgré tout le configurer en avance de phase.
Editer la configuration de Caddy pour votre site avec votre éditeur de texte :
sudo vim /etc/caddy/Caddyfile
Nous allons ajouter les lignes suivantes :
# Configuration à adapter selon votre site web
mistergeek.net,
www.mistergeek.net {
log {
output file /var/log/caddy/mistergeek.net.log
}
reverse_proxy localhost:8080 # Destination vers Varnish qui écoutera sur le port 8080
}
Une fois que c’est fait nous pouvons relancer Caddy avec systemctl restart caddy
# Met à jour les dépots Ubuntu
sudo apt-get update
# Installe Varnish
sudo apt-get install varnish
# Pour démarrer le serveur Varnish (mais non configuré pour le moment)
systemctl start varnish
/etc/default/varnish qui était le fichier de configuration qui regroupe les options de lancement de Varnish.
On peut toujours y lire le contenu ci-dessous, mais modifier ces lignes, ne changera rien au comportement de votre logiciel. En effet sur les dernières versions, la configuration se fait depuis systemd.
DAEMON_OPTS="-a :6081 \ # Port d'écoute externe
-T localhost:6082 \ # Port d'écoute pour l'administration Varnish
-f /etc/varnish/default.vcl \ # Fichier de configuration à utiliser
-S /etc/varnish/secret \ # Liste des secrets
-s malloc,256m" # Utilisation mémoire
Sur les versions de Debian (8+) et Ubuntu (15.04+), systemd se charge de lancer les services. Nous pouvons modifier directement le fichier de lancement de Varnish (/etc/systemd/system/multi-user.target.wants/varnish.service), cependant la meilleure façon est encore de faire un fichier qui viendra occulter la commande de démarrage par défaut.
Créer et éditer un nouveau fichier personnalisé de lancement :
mkdir /etc/systemd/system/varnish.service.d/
sudo vim /etc/systemd/system/varnish.service.d/varnish-custom.conf
Placer les lignes suivantes :
[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -a localhost:8080 -T localhost:6082 -F -f /etc/varnish/default.vcl -S /etc/varnish/secret -s default,256m
Varnish va écouter sur le port 8080 pour les requêtes des clients et le port 6082 pour son interface d’administrationsur. Le tout se fait sur l’interface réseau de loopback (boucle locale, c’es-à-dire le « localhost »).
Executer :
systemctl daemon-reload
Cela permet s’assurer que systemd va utiliser cette nouvelle configuration.
Relancer Varnish avec :
systemctl restart varnish

vim /etc/varnish/default.vcl
Modifier les lignes comme ci-dessous :
backend default {
.host = "127.0.0.1";
.port = "8081"; # Par défaut "8080" et dans notre cas "8081" pour rediriger les requêtes vers Nginx
}
Si la configuration votre web d’origine est différente de celle utilisée ici, il faut changer le backend pour coller à ce que vous avez mis pour Nginx. En suivant toutes les instructions de cet article, il faut donc modifier le port « 8080 » en « 8081 ».
Relancer Varnish avec :
systemctl restart varnish
/etc/nginx/sites-enabled/
Ici, il faut modifier le port d’écoute qui est « 80 » par « 8081 » sur une interface interne.
# Configuration du Serveur web d'origine
server {
listen 127.0.0.1:8081; # Modifier de ":80" à "127.0.0.1:8081"
server_name mistergeek.net www.mistergeek.net;
root /var/www/html;
index index.php index.html;
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Real-IP; # On utilise le header "X-Real-IP" transmis par Caddy et Varnish pour obtenir l'adresse IP de l'utilisateur
real_ip_recursive on;
client_max_body_size 20M;
access_log /var/log/nginx/mistergeek_access.log;
error_log /var/log/nginx/mistergeek_error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
# Ici la configuration vers PHP-FPM pour faire fonctionner WordPress
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
Notre pile technique est maintenant configurer pour fonctionner. Nous allons dans les lignes qui suivent voir comment ajuster plus finement les paramètres de Varnish.
# Arrêter tous les services
systemctl stop caddy
systemctl stop varnish
systemctl stop nginx
# Démarrer tous les services
systemctl start caddy
systemctl start varnish
systemctl start nginx
Si vous rencontrez une erreur du type « ERR_TOO_MANY_REDIRECTS », ajoutez les lignes suivantes au début du fichier wp-config.php de votre installation WordPress.
if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
$_SERVER['HTTPS']='on';
À cette étape, si vous vous rendez sur votre site vous devriez voir quelque chose de fonctionnelle. Il ne manque plus qu’à configurer Varnish finement pour gérer le cache.
vcl 4.1;
import std;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
# Add hostnames, IP addresses and subnets that are allowed to purge content
acl purge {
"localhost";
"127.0.0.1";
"::1";
}
sub vcl_recv {
# Remove empty query string parameters
# e.g.: www.example.com/index.html?
if (req.url ~ "\?$") {
set req.url = regsub(req.url, "\?$", "");
}
# Remove port number from host header
set req.http.Host = regsub(req.http.Host, ":[0-9]+", "");
# Sorts query string parameters alphabetically for cache normalization purposes
set req.url = std.querysort(req.url);
# Remove the proxy header to mitigate the httpoxy vulnerability
# See https://httpoxy.org/
unset req.http.proxy;
# Purge logic to remove objects from the cache.
# Tailored to the Proxy Cache Purge WordPress plugin
# See https://wordpress.org/plugins/varnish-http-purge/
if(req.method == "PURGE") {
if(!client.ip ~ purge) {
return(synth(405,"PURGE not allowed for this IP address"));
}
if (req.http.X-Purge-Method == "regex") {
ban("obj.http.x-url ~ " + req.url + " && obj.http.x-host == " + req.http.host);
return(synth(200, "Purged"));
}
ban("obj.http.x-url == " + req.url + " && obj.http.x-host == " + req.http.host);
return(synth(200, "Purged"));
}
# Only handle relevant HTTP request methods
if (
req.method != "GET" &&
req.method != "HEAD" &&
req.method != "PUT" &&
req.method != "POST" &&
req.method != "PATCH" &&
req.method != "TRACE" &&
req.method != "OPTIONS" &&
req.method != "DELETE"
) {
return (pipe);
}
# Remove tracking query string parameters used by analytics tools
if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=") {
set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "");
set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|utm_content|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?");
set req.url = regsub(req.url, "\?&", "?");
set req.url = regsub(req.url, "\?$", "");
}
# Only cache GET and HEAD requests
if (req.method != "GET" && req.method != "HEAD") {
set req.http.X-Cacheable = "NO:REQUEST-METHOD";
return(pass);
}
# Mark static files with the X-Static-File header, and remove any cookies
# X-Static-File is also used in vcl_backend_response to identify static files
if (req.url ~ "^[^?]*\.(7z|avi|bmp|bz2|css|csv|doc|docx|eot|flac|flv|gif|gz|ico|jpeg|jpg|js|less|mka|mkv|mov|mp3|mp4|mpeg|mpg|odt|ogg|ogm|opus|otf|pdf|png|ppt|pptx|rar|rtf|svg|svgz|swf|tar|tbz|tgz|ttf|txt|txz|wav|webm|webp|woff|woff2|xls|xlsx|xml|xz|zip)(\?.*)?$") {
set req.http.X-Static-File = "true";
unset req.http.Cookie;
return(hash);
}
# No caching of special URLs, logged in users and some plugins
if (
req.http.Cookie ~ "wordpress_(?!test_)[a-zA-Z0-9_]+|wp-postpass|comment_author_[a-zA-Z0-9_]+|woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_[a-zA-Z0-9]+|wordpress_logged_in_|comment_author|PHPSESSID" ||
req.http.Authorization ||
req.url ~ "add_to_cart" ||
req.url ~ "edd_action" ||
req.url ~ "nocache" ||
req.url ~ "^/addons" ||
req.url ~ "^/bb-admin" ||
req.url ~ "^/bb-login.php" ||
req.url ~ "^/bb-reset-password.php" ||
req.url ~ "^/cart" ||
req.url ~ "^/checkout" ||
req.url ~ "^/control.php" ||
req.url ~ "^/login" ||
req.url ~ "^/logout" ||
req.url ~ "^/lost-password" ||
req.url ~ "^/my-account" ||
req.url ~ "^/product" ||
req.url ~ "^/register" ||
req.url ~ "^/register.php" ||
req.url ~ "^/server-status" ||
req.url ~ "^/signin" ||
req.url ~ "^/signup" ||
req.url ~ "^/stats" ||
req.url ~ "^/wc-api" ||
req.url ~ "^/wp-admin" ||
req.url ~ "^/wp-comments-post.php" ||
req.url ~ "^/wp-cron.php" ||
req.url ~ "^/wp-login.php" ||
req.url ~ "^/wp-activate.php" ||
req.url ~ "^/wp-mail.php" ||
req.url ~ "^/wp-login.php" ||
req.url ~ "^\?add-to-cart=" ||
req.url ~ "^\?wc-api=" ||
req.url ~ "^/preview=" ||
req.url ~ "^/\.well-known/acme-challenge/"
) {
set req.http.X-Cacheable = "NO:Logged in/Got Sessions";
if(req.http.X-Requested-With == "XMLHttpRequest") {
set req.http.X-Cacheable = "NO:Ajax";
}
return(pass);
}
# Remove any cookies left
unset req.http.Cookie;
return(hash);
}
sub vcl_hash {
if(req.http.X-Forwarded-Proto) {
# Create cache variations depending on the request protocol
hash_data(req.http.X-Forwarded-Proto);
}
}
sub vcl_backend_response {
# Inject URL & Host header into the object for asynchronous banning purposes
set beresp.http.x-url = bereq.url;
set beresp.http.x-host = bereq.http.host;
# If we dont get a Cache-Control header from the backend
# we default to 1h cache for all objects
if (!beresp.http.Cache-Control) {
set beresp.ttl = 1h;
set beresp.http.X-Cacheable = "YES:Forced";
}
# If the file is marked as static we cache it for 1 day
if (bereq.http.X-Static-File == "true") {
unset beresp.http.Set-Cookie;
set beresp.http.X-Cacheable = "YES:Forced";
set beresp.ttl = 1d;
}
# Remove the Set-Cookie header when a specific Wordfence cookie is set
if (beresp.http.Set-Cookie ~ "wfvt_|wordfence_verifiedHuman") {
unset beresp.http.Set-Cookie;
}
if (beresp.http.Set-Cookie) {
set beresp.http.X-Cacheable = "NO:Got Cookies";
} elseif(beresp.http.Cache-Control ~ "private") {
set beresp.http.X-Cacheable = "NO:Cache-Control=private";
}
}
sub vcl_deliver {
# Debug header
if(req.http.X-Cacheable) {
set resp.http.X-Cacheable = req.http.X-Cacheable;
} elseif(obj.uncacheable) {
if(!resp.http.X-Cacheable) {
set resp.http.X-Cacheable = "NO:UNCACHEABLE";
}
} elseif(!resp.http.X-Cacheable) {
set resp.http.X-Cacheable = "YES";
}
# Cleanup of headers
unset resp.http.x-url;
unset resp.http.x-host;
}
Ce script de configuration va mettre en cache toutes les pages non dynamiques de WordPress. Les utilisateurs connectés et administrateurs, eux verront la version normale du site.
