Introduction
Nginx est bien plus qu'un simple serveur de fichiers statiques ou un proxy inverse basique. En production, ses fonctionnalités avancées déterminent si un service survit aux pics de trafic, aux erreurs de configuration ou aux défaillances partielles de l'infrastructure. Cet article est une plongée pratique dans les concepts les plus importants pour les opérateurs, les ingénieurs DevOps et les équipes techniques de startups qui connaissent déjà les bases et doivent passer d'un problème vague à un résultat vérifié.
Nous aborderons quatre domaines : comment inventorier votre environnement Nginx en toute sécurité, comment apporter des modifications de configuration sans provoquer d'interruption, comment vérifier le comportement et diagnostiquer les problèmes, et comment planifier la reprise en cas de problème. Chaque section comprend des commandes concrètes, des extraits de configuration, les sorties attendues et les signaux d'échec. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets, vérifier le résultat et documenter la procédure de reprise si l'état attendu n'est pas atteint.
Inventaire de la version et de l'environnement
Avant de modifier quoi que ce soit, vous devez savoir exactement ce que vous exécutez. Commencez par la version installée de Nginx et la manière dont il a été compilé. La commande nginx -V (V majuscule) affiche la version, les options de compilation et tous les modules inclus. Elle est en lecture seule et sûre à exécuter. Exemple de sortie sur une installation Ubuntu 22.04 typique :
nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 3.0.2 15 Mar 2022
TLS SNI support enabled
configure arguments: --with-http_ssl_module --with-http_v2_module ...
Notez la version et la liste des modules. De nombreuses directives avancées dépendent de modules qui peuvent ne pas être présents. Par exemple, limit_req_zone nécessite ngx_http_limit_req_module, qui est généralement compilé par défaut, mais geoip2 nécessite un module tiers. Si vous prévoyez d'utiliser une directive et qu'elle est manquante, vous devrez recompiler ou installer un autre paquet.
Ensuite, identifiez la topologie de déploiement. Nginx s'exécute-t-il directement sur un hôte, dans un conteneur Docker, ou fait-il partie d'un contrôleur Ingress Kubernetes ? Les commandes diffèrent légèrement. Sur un hôte, vérifiez les processus en cours et le fichier de configuration principal :
ps aux | grep nginx
nginx -t
La commande nginx -t teste la syntaxe de la configuration et affiche les chemins des fichiers de configuration. Sortie attendue :
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Cela vous indique où se trouve la configuration et si elle est actuellement valide. Dans un conteneur, vous devrez peut-être d'abord exécuter docker exec -it <nom_du_conteneur> nginx -T (T majuscule) pour afficher toute la configuration effective, y compris les fichiers inclus. Ceci est extrêmement utile pour comprendre ce qui est réellement appliqué, surtout lorsque de nombreuses inclusions sont impliquées.
Capturez l'état observable actuel avant tout changement. Les commandes en lecture seule utiles incluent :
nginx -Tpour vider la configuration complète.curl -I https://votre-domaine.compour voir les en-têtes de réponse et le statut.systemctl status nginx(ouservice nginx status) pour voir si le service est actif et depuis combien de temps.ss -tlnp | grep nginxpour lister les sockets en écoute et les processus associés.
Enregistrez les sorties avec des horodatages. Par exemple, enregistrez nginx -T dans un fichier :
nginx -T > nginx_config_$(date +%Y%m%d_%H%M%S).txt
Cela vous donne un point de restauration et une base de comparaison. N'exposez jamais ce fichier publiquement ; il peut contenir des informations sensibles comme des noms de serveur, des IP internes, voire des secrets codés en dur si l'opérateur précédent a été négligent.
Enfin, définissez le résultat attendu et le signal d'échec avant de modifier quoi que ce soit. Par exemple, si vous prévoyez d'ajouter un nouveau bloc serveur, le résultat attendu est que nginx -t retourne un succès et qu'un curl vers le nouveau nom de serveur renvoie le bon contenu. Le signal d'échec est une erreur de syntaxe ou un 404. Écrivez-les. Cette simple habitude prévient de nombreux incidents.
Chemin de configuration sûr
Modifier la configuration de Nginx est risqué car une seule directive incorrecte peut faire tomber tous les hôtes virtuels. Le chemin sûr est : observer, tester, appliquer, vérifier et avoir un plan de restauration.
Parcourons un exemple concret : ajouter une limitation de débit à un point de terminaison API pour se protéger contre les attaques par force brute. Supposons que vous ayez un bloc serveur existant pour api.exemple.com qui proxyfie vers un backend sur le port 3000. Vous voulez limiter les requêtes à 10 par seconde par IP client.
D'abord, sauvegardez la configuration actuelle :
cp /etc/nginx/conf.d/api.conf /etc/nginx/conf.d/api.conf.bak.$(date +%Y%m%d)
Ensuite, modifiez le fichier de configuration avec un éditeur de texte. Ajoutez une directive limit_req_zone dans le contexte http (généralement dans nginx.conf ou un fichier dédié inclus à ce niveau) et une directive limit_req dans le bloc location.
Exemple d'ajout dans nginx.conf :
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# ... autres directives
}
Et dans api.conf :
server {
listen 80;
server_name api.exemple.com;
location / {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend;
}
}
Ici, rate=10r/s autorise en moyenne 10 requêtes par seconde par IP. Le paramètre burst=20 permet à jusqu'à 20 requêtes supplémentaires d'être mises en file d'attente si le débit est dépassé, mais nodelay fait que ces requêtes en rafale s'exécutent immédiatement sans délai. Si un client envoie plus de 30 requêtes en rafale, les requêtes excédentaires reçoivent une réponse 503 Service Indisponible. C'est un modèle courant et efficace.
Après l'édition, testez toujours la configuration :
nginx -t
Si le test réussit, rechargez Nginx pour appliquer le changement en douceur :
systemctl reload nginx
Ou, si vous utilisez un conteneur :
docker exec <nom_du_conteneur> nginx -s reload
La commande reload envoie un signal au processus maître pour recharger la configuration. Les processus workers existants finissent de traiter les requêtes en cours, puis de nouveaux workers démarrent avec la nouvelle configuration. Cela se fait sans interruption pour la plupart des configurations.
Vérifiez le changement avec un outil comme ab (ApacheBench) ou wrk. Pour un test rapide, utilisez curl dans une boucle :
for i in $(seq 1 40); do curl -o /dev/null -s -w "%{http_code}\n" https://api.exemple.com/; done
Vous devriez voir principalement des réponses 200, mais après le dépassement de la rafale, certaines requêtes devraient renvoyer 503. Si vous voyez tous des 200, votre limite ne fonctionne pas comme prévu. Consultez le journal d'erreurs (généralement /var/log/nginx/error.log) pour des messages comme limiting requests, excess: .... Si vous voyez tous des 503, votre rafale est trop petite ou votre test est trop agressif.
La restauration est simple : restaurez le fichier de sauvegarde et rechargez à nouveau :
cp /etc/nginx/conf.d/api.conf.bak.20250315 /etc/nginx/conf.d/api.conf
nginx -t && systemctl reload nginx
Combinez toujours la copie, le test et le rechargement avec && pour qu'un test échoué interrompe le rechargement. Cela réduit le risque qu'une configuration cassée atteigne la production.
Vérification et diagnostic
La vérification signifie plus que vérifier qu'une page se charge. Vous devez confirmer que le changement que vous avez prévu a réellement pris effet et n'a rien cassé d'autre. Le diagnostic est le processus pour découvrir pourquoi quelque chose ne fonctionne pas comme prévu.
Le premier endroit à regarder est le journal d'erreurs de Nginx. Son emplacement est défini par la directive error_log. Les emplacements courants sont /var/log/nginx/error.log pour les installations Linux sur hôte. Pour obtenir plus de détails, augmentez temporairement le niveau de journalisation à debug (attention : cela génère beaucoup de données). Exemple :
error_log /var/log/nginx/error.log debug;
Rechargez après avoir changé le niveau de journalisation. Reproduisez ensuite le problème et examinez le journal. Vous verrez le traitement détaillé des connexions, la négociation SSL et la communication avec l'amont.
Pour vérifier comment Nginx interprète votre configuration, utilisez nginx -T. Cela affiche toute la configuration effective. Comparez-la avec ce que vous pensez avoir écrit. Une erreur courante est de placer une directive dans le mauvais contexte (par exemple, limit_req dans server au lieu de location). Le vidage montrera exactement où tout se trouve.
Un autre diagnostic puissant est le module stub status. S'il est activé (ajoutez stub_status; dans un bloc location), vous pouvez accéder à des métriques en direct :
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
Ensuite, curl http://127.0.0.1/nginx_status renvoie :
Active connections: 2
server accepts handled requests
100 100 200
Reading: 0 Writing: 1 Waiting: 1
Ces nombres indiquent les connexions actives actuelles, le total accepté, traité et les requêtes. Si accepts et handled divergent significativement, le serveur abandonne des connexions. Reading, Writing et Waiting indiquent comment les workers passent leur temps. Un Writing élevé avec un Reading faible suggère que l'amont est lent à répondre.
Pour des métriques plus détaillées, envisagez le module open source nginx-module-vts ou le NGINX Plus commercial avec son tableau de bord de surveillance en direct. Cependant, le stub status est suffisant pour de nombreuses vérifications de base.
Tester la santé de l'amont est une autre vérification importante. Utilisez curl avec une sortie verbeuse pour inspecter les en-têtes :
curl -Iv https://api.exemple.com/ 2>&1 | grep -E "^(<|>) (HTTP|Server|X-)"
Recherchez la version de Nginx dans l'en-tête Server, les en-têtes personnalisés comme X-Request-ID, et si HTTP/2 est utilisé (l'option -I avec HTTPS négocie souvent HTTP/2 si le serveur le supporte). Le temps de réponse est également utile : curl -w "%{time_total}\n" donne le temps total de la requête. S'il est anormalement élevé, le goulot d'étranglement peut être l'amont ou la poignée de main SSL.
Modes de défaillance et reprise
Nginx peut échouer de plusieurs manières : erreurs de configuration, épuisement des ressources, pannes de l'amont et problèmes de sécurité. Connaître les modes de défaillance vous aide à réagir rapidement.
Les erreurs de configuration sont les plus courantes. Elles sont détectées par nginx -t avant le rechargement, mais si vous contournez le test (par exemple, en utilisant nginx -s reload directement), une mauvaise configuration peut arrêter le serveur. Dans ce cas, le processus maître peut encore fonctionner mais les workers peuvent ne pas redémarrer, ou le serveur peut ne pas accepter de nouvelles connexions. La solution est de restaurer la configuration précédente et de recharger. Gardez toujours une sauvegarde de configuration connue comme bonne et testez avant de recharger.
L'épuisement des ressources se produit lorsque Nginx manque de descripteurs de fichiers ou de mémoire. Le journal d'erreurs affichera des messages comme socket() failed (24: Too many open files) ou Cannot allocate memory. Pour éviter cela, augmentez les limites du système. Sur Linux, modifiez /etc/security/limits.conf pour l'utilisateur exécutant Nginx (généralement www-data ou nginx) :
nginx soft nofile 65536
nginx hard nofile 65536
Ensuite, définissez worker_rlimit_nofile dans nginx.conf :
worker_rlimit_nofile 65536;
Ajustez également worker_connections dans le bloc events. Le nombre total de connexions simultanées qu'un worker peut gérer est worker_connections * worker_processes. Calculez cela en fonction de votre trafic. Un point de départ courant est 1024 connexions par worker, mais pour les sites à fort trafic, 4096 ou plus peuvent être nécessaires.
Les pannes de l'amont sont gérées par le module proxy. Si un serveur backend tombe en panne, Nginx renvoie une 502 Bad Gateway ou 504 Gateway Timeout. Pour éviter une panne complète, définissez plusieurs serveurs amont et activez les vérifications de santé. Exemple :
upstream backend {
server backend1.exemple.com max_fails=3 fail_timeout=30s;
server backend2.exemple.com max_fails=3 fail_timeout=30s;
}
Avec ces paramètres, Nginx considère un serveur comme hors service après 3 échecs dans les 30 secondes et cesse de lui envoyer du trafic pendant 30 secondes. Vous pouvez également définir un secours avec backup :
server backend3.exemple.com backup;
Ensuite, si tous les serveurs primaires sont en panne, le secours reçoit le trafic. Surveillez le journal d'erreurs pour des messages comme upstream timed out ou connect() failed pour détecter les problèmes tôt.
Les problèmes de sécurité proviennent souvent d'une mauvaise configuration TLS ou de points de terminaison sensibles exposés. Utilisez des outils comme sslscan ou testssl.sh pour vérifier votre configuration SSL. Par exemple, pour tester les chiffrements faibles :
testssl.sh https://votre-domaine.com
Si des protocoles faibles comme TLSv1.0 sont activés, désactivez-les dans nginx.conf :
ssl_protocols TLSv1.2 TLSv1.3;
Assurez-vous également de ne pas divulguer les jetons de serveur dans les pages d'erreur. Définissez server_tokens off; pour masquer la version de Nginx. Ce durcissement mineur réduit les informations disponibles pour les attaquants.
La reprise après toute défaillance commence par identifier la cause racine à partir des journaux et des métriques, puis appliquer le correctif minimal et vérifier. Ayez toujours un plan de restauration. Pour les changements de configuration, le fichier de sauvegarde est votre restauration. Pour les mises à niveau binaires, gardez le paquet précédent. Pour les changements d'infrastructure, ayez un runbook.
Pièges courants et comment les éviter
De nombreux problèmes Nginx proviennent de quelques erreurs récurrentes. Voici les plus courantes et comment les éviter.
1. Placer des directives dans le mauvais contexte.
Les directives comme limit_req, proxy_pass et rewrite ne sont valides que dans des contextes spécifiques. Par exemple, proxy_pass appartient à location, if in location, ou limit_except, mais pas directement dans server. Si vous le placez dans server, Nginx renverra une erreur comme "proxy_pass" directive is not allowed here. Vérifiez toujours la documentation officielle pour le contexte autorisé, ou utilisez nginx -t pour détecter l'erreur avant le rechargement.
2. Oublier d'échapper les caractères spéciaux dans les expressions régulières.
Nginx utilise PCRE pour la correspondance location et les règles rewrite. Une erreur courante est d'oublier d'échapper un point dans une regex, donc location ~ \.php$ devient location ~ .php$, ce qui correspond à n'importe quel caractère suivi de php. Cela peut provoquer des correspondances non intentionnelles. Testez toujours votre regex avec un outil ou avec les journaux de débogage de Nginx.
3. Utiliser excessivement les directives if.
La directive if dans Nginx est puissante mais peut conduire à un comportement imprévisible car elle est évaluée de manière non standard. De nombreux experts Nginx recommandent d'éviter if autant que possible en utilisant des motifs alternatifs comme try_files, map, ou plusieurs blocs location. Par exemple, au lieu de vérifier un cookie avec if, utilisez un map :
map $cookie_theme $theme {
default light;
dark dark;
}
Utilisez ensuite $theme dans votre proxy_pass ou root.
4. Ne pas définir correctement proxy_set_header.
Lors du proxy vers un backend, vous devez transmettre l'IP client d'origine et l'hôte. Sans proxy_set_header, le backend voit l'IP du serveur Nginx et l'hôte de la configuration Nginx, pas la requête d'origine. Cela casse la journalisation, la géolocalisation et les applications qui dépendent de l'IP réelle du client. L'ensemble standard est :
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
L'absence de ces en-têtes entraîne souvent des journaux vides ou des redirections incorrectes dans l'application backend.
5. Ignorer les tailles de tampon pour les grandes requêtes ou réponses.
Si votre backend envoie de grandes réponses ou si vos clients téléchargent de gros fichiers, les tailles de tampon proxy par défaut peuvent provoquer des erreurs 502 ou des réponses tronquées. Ajustez proxy_buffer_size et proxy_buffers :
proxy_buffer_size 16k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
Ces paramètres allouent plus de mémoire par requête, surveillez donc l'utilisation de la mémoire. Le journal d'erreurs affiche souvent upstream sent too big header while reading response header from upstream lorsque les tampons sont trop petits.
6. Ne pas configurer correctement les délais d'attente.
Les délais d'attente par défaut peuvent être trop courts pour des amonts lents ou des requêtes de longue durée. proxy_read_timeout (par défaut 60s) peut provoquer des erreurs 504 si votre backend met plus de temps à répondre. Augmentez-le si nécessaire :
proxy_read_timeout 300s;
proxy_send_timeout 300s;
Mais attention à ne pas les définir trop haut, car cela immobilise les connexions des workers et peut épuiser les ressources.
7. Exposer des informations sensibles.
Les jetons de serveur, les pages d'erreur et les points de terminaison de statut localhost peuvent divulguer des détails de version ou des informations internes. Définissez toujours server_tokens off; et restreignez l'accès aux pages de statut avec allow/deny. Pour les pages d'erreur, utilisez des pages personnalisées qui ne révèlent pas les traces de pile ou la version de Nginx. Par exemple :
error_page 502 /custom_502.html;
location = /custom_502.html {
internal;
}
La directive internal empêche l'accès direct à la page d'erreur.
Évitez ces pièges en testant chaque changement, en vous référant à la documentation officielle et en gardant vos configurations modulaires et commentées.
Liste de contrôle des opérations
Cette liste de contrôle résume les étapes opérationnelles pour une gestion sûre de Nginx. Chaque élément inclut le propriétaire et la fréquence de revue à titre d'exemple concret, mais vous devez l'adapter à votre équipe et à votre environnement.
- Base de configuration (Propriétaire : Ingénieur DevOps, Revue : mensuelle ou lors d'un changement d'infrastructure) : Exécutez
nginx -T > nginx_config_baseline_YYYYMMDD.txtet stockez-le dans un emplacement sécurisé et versionné. Comparez les changements après chaque déploiement. - Test de syntaxe (Propriétaire : celui qui fait le changement, Revue : avant chaque rechargement) : Exécutez
nginx -tet ne procédez que s'il renvoiesyntax is ok. - Sauvegarde avant changement (Propriétaire : celui qui fait le changement, Revue : avant chaque édition) : Copiez le fichier de configuration pertinent avec un suffixe d'horodatage.
- Rechargement avec vérification (Propriétaire : celui qui fait le changement, Revue : pendant le déploiement) : Utilisez
systemctl reload nginxaprès un test réussi. Vérifiez immédiatementcurl -Isur les vhosts affectés et surveillez le journal d'erreurs pour de nouvelles erreurs. - Surveillance (Propriétaire : Administrateur système, Revue : hebdomadaire) : Vérifiez le stub status ou un tableau de bord de surveillance pour des anomalies dans les connexions actives, le taux de requêtes et les erreurs 5xx.
- Revue du journal d'erreurs (Propriétaire : Administrateur système, Revue : quotidienne ou avec agrégation de journaux) : Analysez les journaux d'erreurs pour des motifs récurrents comme
upstream timed out,SSL handshake failed, oulimiting requests. - Audit de sécurité (Propriétaire : Ingénieur sécurité, Revue : trimestrielle) : Exécutez
testssl.shsur tous les points de terminaison publics, vérifiez les protocoles et chiffrements TLS, vérifiezserver_tokens off, et examinez les contrôles d'accès sur les points de terminaison de statut. - Planification de capacité (Propriétaire : Responsable infrastructure, Revue : trimestrielle) : Analysez les tendances de trafic et ajustez
worker_processes,worker_connections, et les paramètres de délai/tampon en conséquence.
Suivre cette liste de contrôle de manière cohérente réduira le risque d'interruptions et accélérera le dépannage lorsque des problèmes surviennent.
Conclusion
Les concepts avancés de Nginx deviennent gérables lorsque vous les abordez avec un état d'esprit systématique et axé sur la sécurité. Cet article a montré comment inventorier votre environnement, apporter des modifications de configuration en toute sécurité, vérifier les résultats, diagnostiquer les échecs et récupérer rapidement. Les pratiques clés sont : toujours tester avec nginx -t, sauvegarder avant les changements, recharger en douceur, surveiller les journaux et les métriques, et éviter les pièges courants comme les directives mal placées et les en-têtes proxy manquants.
Comme prochaine étape, choisissez une vérification à faible risque de cet article, comme activer le stub status ou tester un changement de configuration dans un environnement de préproduction. Enregistrez l'état actuel, effectuez le changement, vérifiez le résultat et documentez la restauration. Avec le temps, ces habitudes renforceront la confiance et l'expertise dans l'exécution de Nginx en production.
Un flux de travail technique fiable rend les échecs visibles, protège les valeurs sensibles, limite les changements à la ressource prévue et définit la vérification de la reprise avant qu'un incident ne force la décision.