Optimiser Nginx pour améliorer la vitesse des sites WEB

Nginx est un serveur Web très rapide, robuste, léger et très performant exécutant au moins 40 % des sites Web les plus fréquentés au monde. En raison de la polyvalence de Nginx, il est également utilisé comme équilibreur de charge, proxy inverse et serveur de cache HTTP.

La meilleure caractéristique de Nginx est sa vitesse qui lui permet de gérer facilement des milliers de connexions simultanées.

Dans ce tutoriel, nous allons illustrer les meilleures façons de régler et d'optimiser le serveur web Nginx.

Optimiser Nginx pour améliorer la vitesse des sites WEB

Optimiser Nginx pour améliorer la vitesse des sites WEB

Optimiser la couche réseau Linux

Linux regorge de réglages pour optimiser le réseau.
On trouve notamment des paramètres qui concernent les connexions et la façon dont elles sont mises en file d'attente.
Cela peut jouer sur les performances lorsque vous avez beaucoup de connexions.
Ces optimisations réseaux de la couche réseau de Linux s'effectue à travers l'utilitaire sysctl.
il faut modifier /etc/systctl.conf pour les rendre permanent.

net.core.somaxconn – Le nombre maximal de connexions pouvant être mises en file d'attente pour acceptation par NGINX. La valeur par défaut est souvent très faible et c'est généralement acceptable car NGINX accepte les connexions très rapidement, mais cela peut valoir la peine de l'augmenter si votre site Web connaît un trafic important. Si des messages d'erreur dans le journal du noyau indiquent que la valeur est trop petite, augmentez-la jusqu'à ce que les erreurs cessent.

Remarque : Si vous définissez cette valeur sur une valeur supérieure à 512, remplacez le paramètre backlog par la directive d'écoute NGINX pour qu'elle corresponde.

net.core.somaxconn = 4096

net.core.netdev_max_backlog – Le taux auquel les paquets sont mis en mémoire tampon par la carte réseau avant d'être transmis au CPU. L'augmentation de la valeur peut améliorer les performances sur les machines avec une grande quantité de bande passante. Vérifiez le journal du noyau pour les erreurs liées à ce paramètre et consultez la documentation de la carte réseau pour obtenir des conseils sur sa modification.

net.core.netdev_max_backlog = 262144
  • sys.fs.file-max – La limite à l'échelle du système pour les descripteurs de fichiers
  • nofile – La limite de descripteur de fichier utilisateur, définie dans le fichier /etc/security/limits.conf

Pour aller plus loin, vous pouvez appliquer ce fichier network-tuning.conf ou ce tutoriel Optimization of linux kernel parameters when using Nginx

Optimiser les réglages server

Les workers

Nginx comme toute application moderne fonctionne avec plusieurs processus.
Un processus maître et des sous processus dit processus de travail ou worker.
Ce sont les processus de travail impliqués dans la tâche de traitement des demandes des clients.
Le nombre de processus de travail se paramètre dans le fichier de configuration.
En général, on le fixe fonction des cœurs du CPU.

Cette directive détermine le nombre de processus à générer dans Nginx peu de temps après la connexion du serveur aux ports. Il est recommandé de définir un processus de travail par cœur de processeur. Élever les processus au-dessus du cœur du processeur ralentira les performances de votre système.

La valeur par défaut des processus de travail est généralement définie sur auto mais on peut le régler manuellement.

  • Vérifiez le nombre de coeur
grep processor /proc/cpuinfo |wc -l
  • Cela peut retourner 4, 8 ou 16.
  • Editez le fichier /etc/nginx/nginx.conf
  • Puis modifiez la directive worker_processes avec le nombre de coeur
worker_processes X;

Ensuite, toujours dans le fichier nginx.conf, vous pouvez optimiser les réglages suivants.

worker_connections : Définit le nombre maximal de connexions simultanées pouvant être ouvertes par un processus de travail.
Il convient de garder à l'esprit que ce nombre inclut toutes les connexions (par exemple, les connexions avec des serveurs proxy, entre autres), pas seulement les connexions avec les clients. Une autre considération est que le nombre réel de connexions simultanées ne peut pas dépasser la limite actuelle du nombre maximum de fichiers ouverts, qui peut être modifié par worker_rlimit_nofile.

Lorsque Nginx effectue un travail gourmand en ressources processeur tel que SSL ou gzipping et que vous disposez de 2 processeurs/cœurs ou plus, vous pouvez définir que worker_processes soit égal au nombre de processeurs ou de cœurs. Appliquez ce calcul : worker_processes*worker_connections = max. no. of clients
Mais si vous servez beaucoup de fichiers statiques et que la taille totale des fichiers est supérieure à la mémoire disponible, vous pouvez augmenter worker_processes pour utiliser pleinement la bande passante du disque.

Si vous servez beaucoup de fichiers statiques et que la taille totale des fichiers est supérieure à la mémoire disponible, vous pouvez augmenter worker_processes pour utiliser pleinement la bande passante du disque.

Enfin deux autres directives worker à personnaliser :

  • worker_rlimit_core : Modifie la limite de la plus grande taille d'un fichier core (RLIMIT_CORE) pour les processus de travail. Utilisé pour augmenter la limite sans redémarrer le processus principal.
  • worker_rlimit_nofile : Modifie la limite du nombre maximal de fichiers ouverts (RLIMIT_NOFILE) pour les processus de travail. Utilisé pour augmenter la limite sans redémarrer le processus principal.
worker_rlimit_nofile 262144;
worker_connections 16384;

sendfile, tcp_nopush et open_file_cache

Puis voici quelques directives à optimiser pour servir du contenu statique.
Ils jouent surtout sur l'ouverture de fichiers.

tcp_nopush : Utilisez la directive tcp_nopush avec la directive sendfile on;. Cela permet à NGINX d'envoyer des en-têtes de réponse HTTP dans un paquet juste après que le bloc de données ait été obtenu par sendfile().

tcp_nopush on;

Par défaut, NGINX gère lui-même la transmission du fichier et copie le fichier dans le tampon avant de l'envoyer. L'activation de la directive sendfile élimine l'étape de copie des données dans le tampon et permet la copie directe des données d'un descripteur de fichier à un autre.
Alternativement, pour éviter qu'une connexion rapide n'occupe entièrement le processus de travail, vous pouvez utiliser la directive sendfile_max_chunk pour limiter la quantité de données transférées en un seul appel sendfile() (dans cet exemple, à 1 Mo) :

sendfile on;
sendfile_max_chunk 1m;

keepalive_requests : Définit le nombre maximal de requêtes pouvant être traitées via une connexion persistante. Une fois le nombre maximal de demandes effectué, la connexion est fermée.
La fermeture périodique des connexions est nécessaire pour libérer les allocations de mémoire par connexion. Par conséquent, l'utilisation d'un nombre maximal de requêtes trop élevé peut entraîner une utilisation excessive de la mémoire et n'est pas recommandée.

open_file_cache : définit un cache sur les informations de fichiers.

keepalive_requests 100;
open_file_cache max=100;

Les directives du module core sont disponible depuis ce lien : Core functionality

Optimiser le cache de Nginx

Le cache de Nginx vous permet d'améliorer la vitesse de chargement des pages de manière significative.
Le serveur WEB va piocher des données dans la RAM ce qui réduit les I/O.
Il existe énormément de tampons (buffer) pour régler le cache et proxy cache.
Cela peut fortement baisser le Time To First Byte (TTFB) de votre site WEB.
Suivez ce tutoriel très complet :

Optimiser les timeouts

Dans l'étape suivant, on peut jouer sur les timeouts pour gagner en performances.

client_body_timeout :
Le temps d'attente du serveur Nginx pour que le corps du client soit envoyé après une requête. Si client_body n'est pas envoyé, le serveur finira par afficher 408 Error (ou Request Time Out).

client_header_timeout :
Le temps d'attente du serveur Nginx pour que l'en-tête client soit envoyé après une requête. Si le client_header n'a pas été envoyé, le serveur finira par afficher 408 Error (ou Request Time Out).

Keepalive_timeout :
C'est le temps pris pour la connexion keep-alive avec les clients, après quoi le serveur met fin à la connexion.

send_timeout :
C'est le temps d'envoi de la réponse au client concerné. En cas d'échec de ce processus, le serveur Nginx met fin à la connexion.

client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;

Activer le support HTTP/2 ou QUIC+HTTP/3

server {
    listen 443 ssl;              # TCP listener for HTTP/1.1
    listen 443 http3 reuseport;  # UDP listener for QUIC+HTTP/3

    ssl_protocols       TLSv1.3; # QUIC requires TLS 1.3
    ssl_certificate     ssl/www.example.com.crt;
    ssl_certificate_key ssl/www.example.com.key;

    add_header Alt-Svc 'h3=":443"';   # Advertise that HTTP/3 is available
    add_header QUIC-Status $quic;     # Sent when QUIC was used
}

Introducing a Technology Preview of NGINX Support for QUIC and HTTP/3

Optimiser le SSL

Votre site WEB est probablement en HTTPS avec un certificat SSL.
Là aussi on peut aussi appliquer quelques configurations pour améliorer les temps de réponses.

  • SSL : utilisez sur TLS et désactivez SSL (SSL est assez ancien et obsolète et présente de nombreuses vulnérabilités). Optimisez les suites de chiffrement avec ssl_ciphers, car elles sont au cœur de TLS.
  • Cache de session : la création d'un cache de paramètres de connexion TLS réduit le nombre d'établissements de liaison et peut ainsi améliorer les performances de votre application. La mise en cache est configurée à l'aide de la directive ssl_session_cache.
  • Tickets de session : les tickets de session sont une alternative au cache de session. En cas de cache de session, les informations sur la session sont stockées sur le serveur.
  • OSCP : Pour avoir une connexion sécurisée à un serveur, le client doit vérifier le certificat que le serveur a présenté. Afin de vérifier que le certificat n'est pas révoqué, le client (navigateur) contactera l'émetteur du certificat. Cela ajoute un peu plus de temps à l'initialisation de la connexion (et donc au temps de chargement de notre page).

Utilisez ces directives dans votre configuration NGINX et vous êtes prêt pour l'optimisation SSL.

http {

...  
   # SSL Settings
   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
   ssl_prefer_server_ciphers on;
   ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GC$
   
   # Optimize session cache
   ssl_session_cache shared:SSL:50m;
   ssl_session_timeout 1d;
   
   # Enable session tickets
   ssl_session_tickets on;
   
   # OCSP Stapling
   ssl_stapling on;
   ssl_stapling_verify on;
   resolver 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 valid=60s;
   resolver_timeout 2s;
...
}

L'option de configuration Nginx ssl_buffer_size définit la taille du tampon utilisé pour l'envoi de données via HTTPS
Par défaut, la mémoire tampon est définie sur 16 Ko, ce qui est une approche unique axée sur les grandes réponses. Cependant, pour minimiser le TTFB (Time To First Byte), il est souvent préférable d'utiliser une valeur plus petite, par exemple :

ssl_buffer_size 4k;

Optimiser les journaux et logs

L'écriture des journaux sur le disque est important pour suivre l'activité du serveur WEB.
Toutefois là aussi cela génère des accès disques.
Pour limiter ces derniers et libérer des ressources, vous pouvez appliquer ces recommandations.

Désactiver les journaux avec access_log off; pour les types de fichiers statiques.
Par exemple :

location ~* ^.+\.(xml|ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf|woff2|webp)$ {
                access_log off;
                log_not_found off;
                add_header Cache-Control "public, no-transform";
                expires 365d;
        }

Toujours pour minimiser les accès disques vous pouvez activez la mise en mémoire tampon des journaux d'accès. Cela permet à Nginx de mettre en mémoire tampon une série d'entrées de journal et de les écrire simultanément dans le fichier journal au lieu d'effectuer une opération d'écriture différente pour chaque entrée de journal.

access_log /var/log/nginx/access.log main buffer=16k