Table des matières :
- Varnish Cache en 2026 : le reverse proxy qui encaisse pendant que l’origin transpire
- Cache HTTP : TTL, validation, directives… le socle que Varnish exploite (ou que vous contournez)
- VCL : le vrai super-pouvoir (et la source de vos futurs bugs)
- Patterns e-commerce : catalogue cacheable, panier intouchable, et cookies qui doivent mourir
- Invalidation : PURGE, BAN, soft purge… et l’art d’éviter les prix faux
- Sécurité, observabilité et déploiement : parce qu’un cache peut aussi vous trahir
Varnish Cache en 2026 : le reverse proxy qui encaisse pendant que l’origin transpire
Mettre Varnish Cache devant un site web, c’est accepter une vérité un peu vexante : une bonne partie de vos requêtes HTTP n’a absolument aucune raison d’atteindre votre applicatif. Varnish s’intercale en reverse proxy (et cache HTTP) entre clients et backends, répond à partir de la mémoire quand c’est possible, et ne “dérange” l’origin que quand il le faut. Résultat : baisse de la charge CPU/DB, baisse du temps de réponse, et surtout une prod qui arrête de s’effondrer à chaque pic de trafic « imprévu » (comprendre : chaque semaine).
La définition officielle est d’ailleurs assez directe : « Varnish Cache is an HTTP accelerator designed for content-heavy dynamic web sites » (documentation Varnish, documentation Varnish). Traduction : c’est fait pour les sites dynamiques, pas uniquement pour servir trois images et un index.html. En e-commerce, on le voit vite : pages catégorie/produit, contenu CMS, pages d’aide, résultats de recherche (selon la stratégie), tout ça peut être massivement cacheable, avec des TTL raisonnables et une invalidation propre.
Varnish n’est pas un CDN, et n’a pas vocation à remplacer un CDN. Il est plutôt l’outil qui évite que votre origin se transforme en radiateur. Le couple “CDN en edge + Varnish en shield/edge interne” est souvent la combinaison la plus rentable : CDN pour l’Anycast, le TLS, le WAF, le DDoS ; Varnish pour un contrôle chirurgical du cache HTTP et une latence minimale côté origin. Si vous voulez un rappel sur le rôle d’un CDN, voyez l’article interne Le CDN pour les nuls : Le CDN pour les nuls — et pour la couche sécurité côté edge, la partie WAF est bien résumée dans Cloudflare Custom Rules : Cloudflare Custom Rules.
Dans la vraie vie (notamment sur des stacks fréquentes en France : PrestaShop, WooCommerce, Magento, Symfony/Laravel “maison”), Varnish devient pertinent dès que vous cochez au moins deux cases :
- vous avez des pages publiques qui changent “souvent, mais pas à chaque requête” (prix, stock, contenu éditorial) ;
- vous subissez des pics réguliers (soldes, Black Friday, drops, campagnes TV/radio, influence…) ;
- votre applicatif a un TTFB élevé parce que la page déclenche 50 requêtes SQL et 12 appels API ;
- vos ressources sont servies depuis une infra régionale (un ou deux DC), et vous voulez absorber les pointes sans doubler le parc.
Petit repère mental : un Varnish bien réglé transforme une grosse partie de vos requêtes “coûteuses” en simples lectures mémoire. Et en e-commerce, ce n’est pas un détail : c’est la différence entre “on scale en urgence” et “le site reste stable”.
Cache HTTP : TTL, validation, directives… le socle que Varnish exploite (ou que vous contournez)
Optimiser le cache HTTP, ce n’est pas “mettre un cache” et prier. C’est comprendre comment HTTP décrit la fraîcheur (TTL), la revalidation (ETag / Last-Modified), et les contraintes de stockage (private, no-store, etc.). La base est la RFC 9111 (HTTP Caching) : RFC 9111 (HTTP Caching). Varnish sait très bien respecter les en-têtes standards… jusqu’au moment où vous décidez (à juste titre, parfois) de les surcharger avec de la logique métier en VCL.
Concrètement, les en-têtes qui pilotent votre destin sont :
Cache-Control:max-age,s-maxage,public,private,no-cache,no-store.Vary: la liste des headers qui font varier la clé de cache (et donc exploser le hit ratio si vous faites n’importe quoi).ETag/Last-Modified: pour les réponses revalidables viaIf-None-Match/If-Modified-Since.- Les extensions modernes :
stale-while-revalidateetstale-if-error(très utiles en combinaison avec le grace mode de Varnish).
Ce qui manque souvent côté origin, ce n’est pas “un cache”, c’est une intention claire. Une façon simple d’éviter les accidents : décider (et documenter) des politiques par type de contenu. Exemple (à adapter) :
| Type de ressource | Objectif | En-têtes (idée) | Remarques Varnish |
|---|---|---|---|
| HTML catalogue (catégorie/produit) | Rapide + cohérent | Cache-Control: public, s-maxage=300 |
Purge/ban sur tags produit/catégorie |
| Pages éditoriales (blog, FAQ) | Hit ratio très élevé | public, s-maxage=3600 |
Purge sur publication/dépublication |
Assets versionnés (app.8c1f.js) |
Cache long | public, max-age=31536000, immutable |
Plutôt CDN, mais Varnish peut aider en shield |
| Recherche interne | Réduire le coût | micro-cache s-maxage=5..30 |
Attention aux paramètres (tri, page, filtres) |
| Tunnel/panier/compte | Zéro fuite | private, no-store |
pass côté Varnish, aucune ambiguïté |
Deux pièges très fréquents :
Set-Cookiesur des pages publiques : beaucoup d’apps posent un cookie (tracking, consentement, A/B test) sur tout le site. Résultat : la réponse devient implicitement “personnelle” dans l’esprit des caches… et vous perdez votre hit ratio.Varytrop large :Vary: User-Agentest un classique destructeur (milliers de variantes pour une même URL). En général, on préfère normaliser côté application (responsive) ou faire un découpage plus propre (par exemple, un seulVarycontrôlé pour une variante mobile/desktop si c’est réellement nécessaire).
Sur la performance perçue, le cache influence directement le TTFB, et donc vos Core Web Vitals (même si certains aiment encore prétendre que « la perf c’est pour plus tard »). Web.dev rappelle : « Core Web Vitals are a set of real-world, user-centered metrics that quantify key aspects of the user experience. » (web.dev Core Web Vitals). Si votre HTML passe de 600 ms à 40 ms parce que Varnish sert en mémoire, vous venez de gagner des points sans toucher à votre framework “full-typing-quantique” du moment. Pour relier ça à une démarche SEO/perf globale, vous pouvez croiser avec Optimisation performance web : 5 astuces pour réduire le temps de chargement et l’approche plus “score” dans Sortir un site 100/100 au Page Speed Insights.
Checklist rapide (utile avant même d’écrire une ligne de VCL) :
- vos pages publiques renvoient-elles un
Cache-Controlexplicite (pas juste “par défaut”) ? - l’HTML public évite-t-il
Set-Cookie(ou le limite-t-il à des cas réellement nécessaires) ? - avez-vous un
Varyminimal et justifié (Accept-Encodingest normal ; le reste se discute) ? - les réponses “sensibles” sont-elles sans ambiguïté (
private, no-store) ?
VCL : le vrai super-pouvoir (et la source de vos futurs bugs)
La raison pour laquelle Varnish Cache reste pertinent face à des caches plus “automatiques”, c’est la VCL (Varnish Configuration Language). Là où d’autres caches se limitent à des règles statiques, Varnish vous donne un pipeline programmable : vcl_recv (entrée), lookup, vcl_backend_response (réponse backend), vcl_deliver (sortie), plus les hooks de purge, synthèse d’erreurs, etc. C’est puissant, et comme toute chose puissante, ça permet de faire des bêtises très rapidement.
Un point “architecture” à garder en tête : la VCL ne sert pas juste à décider cache ou pas cache. Elle sert aussi à :
- stabiliser la clé de cache (normaliser URL, query string, host, headers),
- protéger le backend contre les comportements clients (retries, thundering herd),
- et imposer des garde-fous (ne jamais cacher si
Authorization, si cookie de session, si méthode non idempotente, etc.).
Un exemple minimaliste (volontairement) pour illustrer les points clés : normaliser, couper les cookies inutiles, et définir une stratégie de cache prudente.
vcl 4.1;
import std;
backend default {
.host = "127.0.0.1";
.port = "8080";
}
sub vcl_recv {
# Ne cachez pas ce qui ne devrait pas l’être : POST/PUT, sessions, etc.
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# Auth = pass (sinon risque majeur de fuite)
if (req.http.Authorization) {
return (pass);
}
# Normalisation : évite des clés différentes pour la même ressource.
set req.url = std.querysort(req.url);
# Cookies : tuer le bruit (tracking) pour sauver le hit ratio.
if (req.http.Cookie) {
set req.http.Cookie = regsuball(req.http.Cookie,
"(^|;\\s*)(_ga|_gid|_gcl_au|fbp|utm_[^=]+)=[^;]*", "");
set req.http.Cookie = regsuball(req.http.Cookie, ";\\s*;", ";");
if (req.http.Cookie ~ "^\\s*$") { unset req.http.Cookie; }
}
}
sub vcl_backend_response {
# TTL par défaut si l’origin ne sait pas parler cache (ça arrive, oui).
if (beresp.ttl <= 0s) {
set beresp.ttl = 5m;
}
# Grace : servir un objet légèrement périmé pendant que l’origin se met à jour.
set beresp.grace = 30s;
}
Deux mécanismes sont souvent mal compris : hit-for-pass et grace. Le hit-for-pass est une “mise en mémoire du fait qu’on ne cache pas”, pour éviter de re-tenter un cache sur des URL qui sont systématiquement non-cacheables (et donc éviter de marteler le backend). Le grace, lui, permet de répondre avec un objet expiré pendant une fenêtre, le temps que Varnish revalide ou régénère en arrière-plan : typiquement ce qui empêche un effet “thundering herd” quand un TTL arrive à expiration sur une page très demandée.
Exemple concret (mini-scénario) : vous avez une page catégorie à TTL 5 minutes, servie 200 fois/seconde pendant une campagne. Sans grace, à T+300s, vous pouvez déclencher une rafale de requêtes simultanées vers l’origin (toutes les premières requêtes “après expiration” sont des misses). Avec grace + une stratégie de revalidation, vous servez temporairement la version stale et vous laissez Varnish “réchauffer” l’objet sans provoquer un pic destructeur côté applicatif.
Enfin, gardez une discipline d’édition : une VCL devient vite un “programme” de prod. Versionnez-la, testez-la, et observez l’impact (hit ratio, variations, erreurs 5xx). Une optimisation de cache qui gagne 20% de hit ratio mais introduit une fuite de données n’est pas une optimisation : c’est un incident en attente.
Patterns e-commerce : catalogue cacheable, panier intouchable, et cookies qui doivent mourir
En e-commerce, la règle simple est : le catalogue est un excellent candidat, le tunnel et l’espace client sont des nids à sessions. Catégories, fiches produit, pages marque, contenus éditoriaux : vous pouvez viser un TTL de 1 à 10 minutes (voire plus) avec invalidation sur événement (mise à jour stock/prix). À l’inverse, checkout, cart, /mon-compte, endpoints API authentifiés : pass immédiat, sinon vous inventez une nouvelle discipline sportive : le “bug intermittent impossible à reproduire”.
Le principal sabotage vient des cookies. Beaucoup d’applications posent 12 cookies de tracking sur toutes les pages, et ensuite s’étonnent que le cache ne hit jamais. La logique VCL consiste à ne conserver que les cookies réellement discriminants (session, panier, consentement si ça change le contenu), et à purger le reste. Si votre stack est WordPress/WooCommerce, c’est une bataille quotidienne : voir au besoin le guide interne WooCommerce pour recadrer la partie “comportement standard” : WooCommerce guide.
Une nuance “terrain” (souvent visible sur des boutiques françaises/UE à cause du RGPD et des CMP) : le cookie de consentement ne devrait pas forcément faire varier tout le HTML. Si votre bannière/cmp est injectée côté client, vous pouvez garder le HTML cacheable et laisser la CMP gérer l’état en front. Si, au contraire, votre serveur génère une page complètement différente selon consentement, vous risquez de multiplier les variantes et de casser le cache. Le bon compromis est presque toujours : page publique identique, scripts marketing conditionnels.
La personnalisation ne doit pas forcément tuer le cache ; elle doit être découpée. Historiquement, Varnish supporte ESI (Edge Side Includes) pour assembler une page cacheable avec des fragments dynamiques (ex : mini-panier, statut connecté). Dans les stacks modernes, on préfère souvent : page HTML cacheable + appels XHR/GraphQL non cacheés (ou micro-cache) pour les blocs personnalisés.
Un repère simple pour décider :
- si le bloc “dynamique” est petit et coûteux à générer côté serveur, ESI peut rester très efficace ;
- si le bloc est déjà fourni par une API, un appel front (avec un TTL court, voire aucun) est souvent plus facile à maintenir ;
- si vous avez plusieurs pays/langues (très fréquent), évitez de faire varier sur trop de headers : préférez des URLs explicites (
/fr/,/en/) plutôt queVary: Accept-Languagepartout.
Si vous hésitez entre “AJAX partout” et “HTML serveur”, l’article L’AJAX en e-commerce : oui ou non ? remet quelques idées d’aplomb : L’AJAX en e-commerce.
Invalidation : PURGE, BAN, soft purge… et l’art d’éviter les prix faux
Le cache sans invalidation, c’est juste une façon polie de servir de vieilles données. Avec Varnish, vous avez plusieurs outils :
- PURGE : supprime un objet précis (URL exacte). Simple, mais pas scalable si vous avez des variations.
- BAN : invalide par expression (header, URL regex, tag), efficace pour les purges par “famille” de contenus.
- Soft purge / grace : vous “déclassez” l’objet, mais vous pouvez continuer à servir une version stale le temps de régénérer.
Une purge propre commence par une ACL (sinon tout Internet vous purge votre cache “pour rigoler”). Exemple très classique :
acl purge {
"127.0.0.1";
"10.0.0.0"/8;
}
sub vcl_recv {
if (req.method == "PURGE") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed"));
}
return (purge);
}
}
Le vrai sujet en e-commerce, c’est la purge “métier” : quand un prix ou un stock change, quelles pages doivent être invalidées ? La bonne pratique est d’ajouter des tags côté origin (ex : X-Cache-Tags: product:123 category:9) et de faire un BAN basé sur ces tags.
Mini-scénario réaliste : vous mettez -20% sur une marque pendant 48h. Un simple PURGE de la page produit ne suffit pas : il faut aussi invalider la catégorie, la page marque, les pages “meilleures ventes”, parfois la home, et éventuellement des pages éditoriales qui mettent en avant la sélection. Les tags permettent d’invalider “par relation” (produit → catégorie → marque) sans lister 200 URLs.
Exemple d’idée de BAN (le détail dépend de votre version/config) : vous poussez X-Cache-Tags depuis l’origin, puis vous bannissez tout ce qui contient product:123 :
sub vcl_recv {
if (req.method == "BAN") {
if (!client.ip ~ purge) {
return (synth(405, "Not allowed"));
}
if (req.http.X-Ban-Tag) {
ban("obj.http.X-Cache-Tags ~ " + req.http.X-Ban-Tag);
return (synth(200, "Ban added"));
}
return (synth(400, "Missing X-Ban-Tag"));
}
}
Sur des CMS type PrestaShop, ce point devient critique pendant une migration ou une refonte ; si vous travaillez sur le plan d’URL et les changements de pages, l’article Migration PrestaShop 8 : stratégie SEO et plan d’URL cross‑site donne un cadre utile : Migration PrestaShop 8.
Enfin, l’invalidation doit vivre avec votre delivery. Une purge à la main via curl -X PURGE en prod, c’est mignon la première fois ; la dixième, c’est un incident. Le bon endroit, c’est un pipeline : hook de déploiement, webhook d’admin produit, job planifié, etc. Si vous êtes déjà sur une stack GitOps, vous pouvez raccrocher la purge à vos workflows, exactement comme vous structurez votre delivery Kubernetes dans Pipeline CI/CD Kubernetes : GitHub Actions et Argo CD étape par étape : Pipeline CI/CD Kubernetes.
Sécurité, observabilité et déploiement : parce qu’un cache peut aussi vous trahir
Varnish est au milieu du trafic, donc il amplifie aussi vos erreurs de sécurité. Les classiques : cache poisoning (injecter une réponse cacheée mal variée), confusion de Host, normalisation d’URL insuffisante, oubli de Vary sur des réponses dépendantes de Accept-Encoding ou de la locale, et surtout cache de pages qui contiennent des données utilisateurs. Ajoutez à ça des intégrations tierces qui injectent des headers “créatifs”, et vous obtenez un incident qui ressemble étrangement à un pentest… mais gratuit.
Pour comprendre le risque (et les scénarios typiques d’attaque), une ressource technique solide est la page PortSwigger sur le sujet : PortSwigger — web cache poisoning.
Quelques garde-fous concrets (ceux qui évitent les “leaks” les plus coûteux) :
passsiAuthorization(déjà montré) et, selon votre app,passsi cookie de session est présent.- ne jamais mettre en cache une réponse qui contient des données utilisateur (emails, nom, prix personnalisés, avantages fidélité).
- maîtriser vos variations : si vous variez par devise, par langue, par device… faites-le explicitement et testez chaque combinaison.
- normaliser
Host/X-Forwarded-Hostsi vous avez plusieurs domaines ou si vous êtes derrière un CDN/LB. - vérifier les pages “intermédiaires” : erreurs 302, 404, pages de maintenance… peuvent aussi être cachées (parfois à tort).
Pour la couche edge, un WAF (Cloudflare, etc.) aide, mais ne compense pas une logique cache incohérente ; l’article Protection DDoS cloud 2026 est un bon rappel que la résilience ne se limite pas à “mettre un firewall” : Protection DDoS cloud 2026.
Côté observabilité, vous ne “tunez” pas Varnish au feeling. Vous mesurez : hit ratio, cache_hit vs cache_miss, latence p95/p99, backend_fail, saturation des threads, allocation storage, et surtout la différence entre hit et hit-for-pass. Les outils natifs (varnishstat, varnishlog, varnishadm) sont indispensables, et l’export vers Prometheus est devenu un standard (exporter les métriques, alerter sur baisse de hit ratio, hausse de backend_busy).
Deux signaux simples à surveiller en continu (et qui parlent immédiatement à une équipe infra/produit) :
- hit ratio sur les pages “money pages” (catégorie/produit) : s’il chute, c’est rarement “la faute de Varnish”, souvent un cookie ou un
Varyqui a explosé. - backend requests/sec vs trafic total : c’est votre économie réelle. Une hausse de trafic qui ne s’accompagne pas d’une hausse du backend est le signe que votre stratégie de cache fait le job.
Pour mettre ça proprement en place, les articles internes Prometheus monitoring : quickstart (Prometheus monitoring : quickstart) et OpenTelemetry : unifier métriques, traces et logs (OpenTelemetry) donnent une base solide — et pour corréler avec le vécu utilisateur, le volet Real User Monitoring (RUM) est à lire : Real User Monitoring (RUM).
Enfin, déploiement : Varnish ne termine pas TLS nativement, donc il faut un frontal (HAProxy/Nginx/Envoy) ou un CDN devant. En conteneur/Kubernetes, ça se fait très bien, mais il faut traiter les détails qui piquent : persistence du storage (ou choix assumé d’un cache “jetable”), healthchecks réalistes, rolling update sans drop, et sécurisation réseau (ACL de purge, mTLS interne si besoin).
Quelques décisions de déploiement qui évitent des surprises :
- storage :
malloc(RAM) est très rapide mais limité ;file(disque) peut aider si vous cachez gros (attention à la latence). En e-commerce, on cache souvent surtout du HTML/JSON : la RAM est généralement rentable. - IP client : si vous êtes derrière CDN/LB, assurez-vous que l’origin (et Varnish) reçoivent une chaîne fiable (
X-Forwarded-For) pour l’anti-fraude/rate-limit. - cache “jetable” assumé : sur Kubernetes, reconstruire un cache après redéploiement est acceptable si vous avez un CDN devant et des TTL raisonnables ; sinon, prévoyez une stratégie de warmup (ou au moins un grace bien réglé).
Si vous êtes déjà dans Kubernetes, vous connaissez la chanson : hardening, RBAC, network policies — l’article Sécurisation Kubernetes : plan d’action 30 jours pour PME est une checklist pratique : Sécurisation Kubernetes.
Pour ceux qui aiment les “quick wins”, la meilleure optimisation reste la plus ancienne du monde de la perf : « The fastest HTTP request is the one not made. » (Steve Souders, High Performance Web Sites, O’Reilly). Varnish Cache ne remplace pas une architecture saine, mais c’est l’un des rares outils qui transforme cette phrase en métriques (hit ratio, backend RPS) et en économies concrètes.
Si l’objectif est d’absorber de la charge e-commerce de manière durable, la brique hébergement a évidemment son mot à dire : Hébergement spécial e‑commerce.