La documentation officielle du protocole HTTP est claire sur ce point : l’en-tête Vary indique à un cache selon quels autres en-têtes de la requête une réponse peut varier, afin qu’il ne serve jamais à un client une réponse générée pour un contexte différent du sien.
Ce tutoriel montre comment configurer correctement Vary: Accept-Encoding sur une infrastructure WordPress qui partage un cache entre plusieurs serveurs applicatifs, un cas fréquent dès qu’un cache mutualisé de type reverse proxy se trouve devant plusieurs backends. Il ne traite pas de la validation par ETag, un mécanisme de cache distinct qui répond à un autre problème.
Le problème concret que cet en-tête résout
Un serveur web moderne peut compresser sa réponse selon l’algorithme que le client indique supporter dans son en-tête de requête Accept-Encoding, typiquement gzip ou br pour Brotli. Sans indication contraire, un cache partagé placé devant plusieurs serveurs applicatifs peut mémoriser une seule version de la réponse pour une URL donnée, indépendamment de l’encodage utilisé pour la générer.
Si cette réponse a été compressée en Brotli pour un premier client, et que le cache la sert telle quelle à un second client dont le navigateur ne supporte que gzip, ce second client reçoit un contenu binaire qu’il ne sait pas décompresser. Le résultat visible côté navigateur va du texte totalement illisible à une page blanche, selon la façon dont le navigateur gère cette incohérence entre en-tête annoncé et contenu réel.
Configurer nginx pour propager correctement l’en-tête
Sur un serveur nginx qui compresse ses réponses avec le module gzip natif, l’en-tête Vary: Accept-Encoding est ajouté automatiquement dès que la directive gzip_vary on; est activée dans la configuration du serveur ou du bloc de site concerné.
server {
listen 443 ssl;
server_name exemple-client.fr;
gzip on;
gzip_vary on;
gzip_types text/html text/css application/javascript application/json;
location / {
proxy_pass http://backend_wordpress;
proxy_set_header Accept-Encoding $http_accept_encoding;
}
}
Le point souvent oublié se situe au niveau du cache lui-même, qu’il s’agisse d’un module proxy_cache nginx ou d’une brique de cache partagée séparée. La clé de cache doit intégrer la valeur d’Accept-Encoding du client, faute de quoi l’en-tête Vary renvoyé au navigateur devient purement déclaratif, sans effet réel sur ce que le cache mémorise en interne.

Configurer la clé de cache pour respecter réellement Vary
Sur un proxy_cache nginx, la clé de cache par défaut n’intègre pas systématiquement l’encodage accepté par le client. Il est nécessaire de l’ajouter explicitement à la directive proxy_cache_key pour que le cache stocke des entrées distinctes selon l’encodage.
proxy_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=wp_cache:64m;
proxy_cache_key "$scheme$request_method$host$request_uri$http_accept_encoding";
Cette clé de cache enrichie garantit que deux clients demandant la même URL, mais avec des en-têtes Accept-Encoding différents, obtiennent chacun une entrée de cache distincte, correctement compressée pour leur propre capacité de décompression.
Vérifier le comportement une fois la configuration en place
- Envoyer une requête sans en-tête
Accept-Encodinget vérifier que la réponse n’est pas compressée. - Envoyer une requête avec
Accept-Encoding: bret vérifier, via l’en-têteContent-Encoding: brde la réponse, que la compression Brotli a bien été appliquée. - Vérifier, dans les deux cas, la présence de l’en-tête
Vary: Accept-Encodingdans la réponse, quel que soit l’encodage utilisé.
Un en-tête Vary correctement réglé ne se contente pas d’informer le navigateur : il doit aussi être respecté par le cache lui-même, sans quoi la déclaration reste sans effet sur ce que sert réellement l’infrastructure.
En résumé
La configuration correcte de Vary: Accept-Encoding sur un cache partagé entre plusieurs serveurs applicatifs demande deux réglages distincts et complémentaires : l’ajout de l’en-tête lui-même côté serveur web, et l’intégration de la valeur d’Accept-Encoding dans la clé de cache utilisée par la brique de mise en cache. Omettre le second réglage laisse le problème intact, malgré une configuration en apparence conforme à la documentation.