Menu Fermer

Configurer le cache FastCGI de Nginx

En informatique, la mise en cache est un procédé courant pour améliorer les performances.
Nginx, un serveur WEB très populaire ne déroge pas à cette règle.
Grâce à une mise en cache efficace, vous pouvez grandement réduire le temps de chargement des sites WEB.
Avec des pages rapides, vous améliorez l’expérience utilisateur final et votre référencement sur les moteurs de recherche comme Google.

Dans ce tutoriel, je vous montre comment configurer le cache de Nginx pour obtenir de meilleures performances.
Il s’agit principalement de la configuration du cache Nginx avec FastCGI.
Pour vous y aider, vous trouverez plusieurs exemples de configuration de cache nginx.

Configurer le cache de Nginx

Configurer le cache statique de Nginx

Dans un site WEB, une partie des données sont des fichiers HTML, CSS, JavaScript et images.
C’est le contenu dit statique car il ne bouge pas ou très peu.
Ce contenu est facile à cacher puisqu’il ne bouge pas, on le place en mémoire et on vide le cache que quand il est modifié.
De ce fait, on peut aussi demander à le cacher du côté client, c’est à dire dans le navigateur WEB.
Cela évite de re-télécharger à chaque consultation du site internet, pris sur le disque, on gagne en temps de chargement de la page.

La configuration du cache statique de Nginx s’effectue dans les blocs http.
Voici un exemple pour cacher les images, polices et Javascript en visant des extensions de fichiers spécifique.
Cela nécessite d’envoyer un header Cache-Control pour que le navigateur WEB reçoit l’information de cacher le contenu.

location ~* \.(svg|gif|otf|jpg|jpeg|png|css|js|ttf)$ {
  add_header Cache-Control public; # En-tête de contrôle de cache pour les navigateurs
  add_header Pragma public; # En-tête de contrôle de cache pour les navigateurs
  add_header Vary Accept-Encoding; # En-tête de contrôle de cache pour les navigateurs
  expires max; # Stockez les fichiers statiques aussi longtemps que possible, cela prendra plus d'un an.
}

La directive expires permet d’indiquer combien de temps le navigateur doit garder le contenu en cache.
Par exemple pour 30d ou 24h :

OptionsDescription
offCette valeur désactive la logique des en-têtes de cache Nginx. Rien ne sera ajouté, et plus important encore, les en-têtes existants reçus des amonts ne seront pas modifiés.
epochIl s’agit d’une valeur artificielle utilisée pour purger une ressource stockée de tous les caches en définissant l’en-tête Expires sur “1 January, 1970 00:00:01 GMT”.
maxDemande cacher pour 10 ans. Cela signifie essentiellement que les réponses HTTP sont garanties de ne jamais changer, les clients sont donc libres de ne jamais demander deux fois la même chose et peuvent utiliser leurs propres valeurs stockées.
Specific timeUne valeur de temps spécifique réelle signifie un délai d’expiration à partir du moment de la demande respective. Par exemple, expire 10w ; Une valeur négative pour cette directive émettra un en-tête spécial Cache-Control : no-cache.
“modified” specific timeSi vous ajoutez le mot-clé modified avant la valeur de l’heure, alors le moment d’expiration sera calculé par rapport à l’heure de modification du fichier qui est servi.
“@” specific timeUne heure avec un préfixe @ spécifie une expiration absolue de l’heure du jour.
Cela devrait être inférieur à 24 heures. Par exemple, Expire @17h ;.
Les options de la directive expire

Pour désactiver le cache statique dans Nginx, réglez expires de cette manière :

expires -1;

Ou encore if_modified_since :

if_modified_since off; # Spécifie comment comparer l'heure de modification d'une réponse avec l'heure dans le champ d'en-tête de requête plutôt pour les moteurs de recherche
        expires off;
        etag off;

Configurer le fastcgi_cache ou proxy_cache de Nginx

Ce cache est utilisé lorsque Nginx agit comme proxy entre le client et le backend.
Ce backend peut-être une serveur PHP ou un autre serveur Nginx.
Les directives diffèrent alors.

Configuration générale

La déclaration de cache se scinde en deux parties.
Une directive proxy_cache_path pour créer la zone de cache.
Puis des directives pour appeler cette dernière ou modifier la configuration.

proxy_cache_path /path/to/cache levels=1:2 keys_zone=my_cache:10m max_size=10g 
                 inactive=60m use_temp_path=off;
proxy_cache_key "$host$request_uri$cookie_user";

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

En réalité, il existe plusieurs protocoles de cache dont la configuration est assez identique :

  • fastcgi_cache est lié au protocole backend FastCGI. Il met en cache la sortie des backends connectés FastCGI utilisées par des applications par exemple PHP-FPM.
  • proxy_cache est lié aux backends qui utilisent HTTP comme protocole backend, et il met en cache la sortie des backends connectés HTTP. On l’utilise pour du reverse-proxy ou load balancing

Notez que l’on peut mélanger sans problème ces protocoles.

La directive proxy_cache_path ou fastcgi_cache_path

Voici un exemple de configuration :

Les deux se déclarent de la même manière.
Voici les principales options :

  • level définit une hiérarchie de répertoires à deux niveaux sous /path/to/cache/. Le fait d’avoir un grand nombre de fichiers dans un seul répertoire peut ralentir l’accès aux fichiers, c’est pourquoi nous recommandons une hiérarchie de répertoires à deux niveaux pour la plupart des déploiements. Si le paramètre level n’est pas inclus, NGINX place tous les fichiers dans le même répertoire.
  • keys_zone configure une zone de mémoire partagée pour stocker les clés de cache et les métadonnées telles que les minuteurs d’utilisation. Avoir une copie des clés en mémoire permet à NGINX de déterminer rapidement si une demande est un HIT ou un MISS sans avoir à aller sur le disque, ce qui accélère considérablement la vérification. Une zone de 1 Mo peut stocker des données pour environ 8 000 clés, de sorte que la zone de 10 Mo configurée dans l’exemple peut stocker des données pour environ 80 000 clés.
  • max_size définit la limite supérieure de la taille du cache (à 10 gigaoctets dans cet exemple). C’est facultatif; ne pas spécifier de valeur permet au cache de croître pour utiliser tout l’espace disque disponible. Lorsque la taille du cache atteint la limite, un processus appelé gestionnaire de cache supprime les fichiers les moins récemment utilisés pour ramener la taille du cache sous la limite.
  • inactif spécifie combien de temps un élément peut rester dans le cache sans y accéder. Dans cet exemple, un fichier qui n’a pas été demandé depuis 60 minutes est automatiquement supprimé du cache par le processus du gestionnaire de cache, qu’il ait ou non expiré. La valeur par défaut est de 10 minutes (10 m). Le contenu inactif diffère du contenu expiré. NGINX ne supprime pas automatiquement le contenu qui a expiré tel que défini par un en-tête de contrôle de cache (Cache-Control:max-age=120 par exemple). Le contenu expiré (obsolète) est supprimé uniquement lorsqu’il n’a pas été consulté pendant la durée spécifiée par inactif. Lors de l’accès à un contenu expiré, NGINX l’actualise à partir du serveur d’origine et réinitialise le compteur d’inactivité.

proxy_cache_key définit une clé pour la mise en cache, par exemple pour forcer la prise en compte de paramètres dans l’URL.

proxy_cache_key "$host$request_uri $cookie_user";

Déclarer le cache dans la directive server

Ensuite, on appelle le cache à tout moment dans la directive server comme montré précédemment.

server {
    # ...
    location / {
        proxy_cache my_cache;
        proxy_pass http://my_upstream;
    }
}

Il est tout à fait possible de créer plusieurs zones de cache avec des paramètres différents.

proxy_cache_path /var/lib/nginx/http1 levels=1:2 keys_zone=php:10m max_size=5g 
                 inactive=60m use_temp_path=off;
proxy_cache_path /var/lib/nginx/http2 levels=1:2 keys_zone=php:10m max_size=10g 
                 inactive=10m use_temp_path=off;

server {
    # ...
    location / {
        proxy_cache http1;
        proxy_pass http://my_upstream;
    }


location /private {
        proxy_cache http2;
        proxy_pass http://my_upstream;
    }
}

fastcgi_cache

fastcgi_cache fonctionne de la même manière que proxy_cache.
Voici un exemple de configuration.

fastcgi_cache_path /var/lib/nginx/php levels=1:2 keys_zone=php:500m inactive=60m max_size=10G;

server {
   # ...

   location ~ \.php {
      fastcgi_cache php;
      fastcgi_cache_revalidate on;
      fastcgi_pass unix:/run/php/php7.3-fpm.sock;
      fastcgi_index index.php;
   }
}

Notez ici que le proxy se fait avec un socket unix mais on peut très bien passer une URL pour attaquer, par exemple pour attaquer PHP-FPM.

fastcgi_pass http://127.0.0.1:9000;

fastcgi_cache_key

La directive fastcgi_cache_key définit la structure à mettre en cache.
Par exemple ci-dessous, on met les pages en cache.

location ~ \.php {
      fastcgi_cache php;
      fastcgi_cache_revalidate on;
      fastcgi_cache_key "$scheme$request_method$host$request_uri";
      fastcgi_pass unix:/run/php/php7.3-fpm.sock;
      fastcgi_index index.php;
   }

Mais il est aussi possible de jouer sur les cookies pour mettre en cache des pages pour un cookies spécifiques, par exemple lorsque l’on a des sessions PHP.
Par exemple pour prendre en compte le cookie PHPbb :

fastcgi_cache_key "$cookie_phpbb3_malekal_u$scheme$request_method$host$request_uri";

fastcgi_cache_valid

Cette directive permet de conditionner le délai de cache d’une page selon la réponse HTTP.
Par exemple ci-dessous, les pages en HTTP 200 et 302 seront mis en cache pour 60 minutes alors que les pages en HTTP 301 le seront pendant une journée.

            fastcgi_cache php;
            fastcgi_cache_valid 200 302 60m;
            fastcgi_cache_valid 301 1d;

fastcgi_cache_bypass et fastcgi_no_cache : Ignorer le cache sur des pages spécifiques

Lors d’une session, sur des pages d’administrations, on peut vouloir ignorer le cache car cela peut fausser le contenu.
Il est alors possible d’ajouter des excentrions de cache dans des blocs HTTP de nginx.
Pour cela, on définit variable $skip_cache :

  • à 1 : le cache est ignoré
  • à 0 : le cache est actif

Deux directives sont utilisées :

  • La directive fastcgi_cache_bypass demande à ce que la réponse ne soit pas extraite d’un cache
  • fastcgi_no_cache La réponse ne sera pas enregistrée dans un cache

Par exemple pour ignorer les pages admin de WordPress ou lorsque l’on est authentifié (un cookie est créé dans ce cas) :

set $skip_cache 0;

if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
	set $skip_cache 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
	set $skip_cache 1;
}

location ~ \.php$ {
    # Mettre la configuration fastfastcgi_cache
    fastcgi_cache php;
    fastcgi_cache_valid 200 302 5m;
    fastcgi_cache_valid 301 1d;
    fastcgi_cache_bypass $skip_cache;
    fastcgi_no_cache $skip_cache;
}


On peut aussi conditionner le cache selon le cookie pour jouer sur les sessions PHP.
Par exemple dans le cas d’un forum phpBB, on ne cache que pour un cookies à 1 qui correspond aux utilisateurs anonymes.
Ainsi les utilisateurs authentifiés ne seront pas affectés par le cache.

set $skip_cache 0;

location ~ \.php$ {
      if ($cookie_phpbb3_malekal_u != 1) { set $skip_cache 1; }
      fastcgi_cache php;
      fastcgi_cache_valid 200 302 5m;
      fastcgi_cache_valid 301 1d;
      fastcgi_cache_bypass $skip_cache;
      fastcgi_no_cache $skip_cache;
}

Ajouter un en-tête HTTP X-Cache-Status

Vous pouvez configurer un statut du cache dans la réponse de l’en-tête HTTP.
Pour cela, ajoutez cette directive pour ajouter l’en-tête X-Cache-Status :

add_header X-Cache-Status $upstream_cache_status;

Voici les valeurs possibles pour $upstream_cache_status :

  • MISS – La réponse n’a pas été trouvée dans le cache et a donc été récupérée à partir d’un serveur d’origine. La réponse peut alors avoir été mise en cache.
  • BYPASS – La réponse a été récupérée depuis le serveur d’origine au lieu d’être servie depuis le cache car la requête correspondait à une directive proxy_cache_bypass. La réponse peut alors avoir été mise en cache.
  • EXPIRED – L’entrée dans le cache a expiré. La réponse contient du contenu récent du serveur d’origine.
  • STALE – Le contenu est périmé car le serveur d’origine ne répond pas correctement et proxy_cache_use_stale a été configuré.
  • UPDATING – Le contenu est périmé car l’entrée est actuellement mise à jour en réponse à une demande précédente et la mise à jour proxy_cache_use_stale est configurée.
  • REVALIDATED – La directive proxy_cache_revalidate a été activée et NGINX a vérifié que le contenu mis en cache actuel était toujours valide (If-Modified-Since ou If-None-Match).
  • HIT – La réponse contient du contenu valide et frais directement à partir du cache.
Ajouter un en-tête HTTP X-Cache-Status dans Nginx

Les directives cache à connaître

Voici quelques directives de caches supplémentaires utiles à connaître.

proxy_cache_methods permet de définir les méthodes HTTP à mettre en cache.

proxy_cache_methods GET HEAD POST;

proxy_ignore_headers désactive le traitement de certains champs d’en-tête de réponse à partir du serveur proxy.
Cache-Control est un en-tête HTTP utilisé pour spécifier les politiques de mise en cache du navigateur dans les demandes des clients et les réponses du serveur. Les politiques incluent la façon dont une ressource est mise en cache, où elle est mise en cache et son âge maximum avant d’expirer (c’est-à-dire la durée de vie).
Si vous utilisez un CDN, proxy-reverse, le Cache-Control peut-être imposé, vous pouvez alors désirer l’ignorer pour forcer la mise en cache.

proxy_ignore_headers Cache-Control Expires Set-Cookie;

proxy_cache_bypass définit les conditions dans lesquelles la réponse ne sera pas extraite d’un cache. Si au moins une valeur des paramètres de chaîne n’est pas vide et n’est pas égale à « 0 », la réponse ne sera pas extraite du cache :

proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
proxy_cache_bypass $http_pragma    $http_authorization;

La liste des directives de ngx_http_proxy_module

Comment vider le cache Nginx

Il peut arriver que l’on ait besoin de vider le cache Nginx.
Vous pouvez tout simplement vider le dossier sans arrêter le serveur WEB.
Par exemple pour un cache se trouvant dans /var/lib/nginx/http1 :

rm -rf /var/lib/nginx/http1/*

Pour faciliter le vidage du cache, on peut aussi créer une fonction de purge de cache grâce à la directive proxy_cache_purge.

proxy_cache_path /tmp/cache keys_zone=mycache:10m levels=1:2 inactive=60s;

map $request_method $purge_method {
    PURGE 1;
    default 0;
}

server {
    listen 80;
    server_name www.example.com;

    location / {
        proxy_pass http://localhost:8002;
        proxy_cache mycache;

        proxy_cache_purge $purge_method;
    }
}

Ensuite, on envoie une requête contenant un en-tête ou une méthode HTTP personnalisée.
Par exemple avec curl :

curl -X PURGE -D – "http://www.example.com/*"

Optimiser la mise en cache de Nginx

Nous venons de voir la configuration générale de mise en cache sur Nginx.
Mais il existe de nombreuses directives de buffer pour optimiser le cache et ainsi améliorer les performances de vos sites WEB.
Retrouvez ces réglages dans le tutoriel suivant :