Retour au cours

infra / nginx

Debugging, monitoring et checklist de production

Leçon 151 exercice

Explication

Ce que vous allez apprendre

  • Exposer des métriques basiques avec stub_status, protégées et prêtes pour un monitoring externe
  • Reconnaître les erreurs 502, 503, 504 et 499, et identifier leur cause la plus fréquente
  • Diagnostiquer méthodiquement un incident en isolant "problème Nginx" de "problème backend"
  • Appliquer une checklist de durcissement systématique avant toute mise en production
  • Valider une configuration en CI avant chaque déploiement, plutôt qu'en découvrant l'erreur en prod

Dans quel contexte ?

Un service en production renvoie soudainement des erreurs 502 à une partie des utilisateurs. L'équipe de garde doit déterminer en quelques minutes si le problème vient de Nginx, du réseau, ou de l'application elle-même — sans cette méthode, l'incident peut s'éterniser en hypothèses non vérifiées pendant que les utilisateurs restent bloqués.

D'abord, un premier réflexe simple : observer des métriques de base

stub_status, exposé sur une adresse locale protégée (jamais publiquement accessible), donne en un coup d'œil le nombre de connexions actives et leur répartition entre lecture, écriture et attente. C'est un point de départ minimal mais précieux pour un monitoring externe (Prometheus, par exemple), à mettre en place avant même qu'un incident ne survienne.

Une fois cette base de surveillance en place, il faut savoir lire les codes d'erreur

Chaque code d'erreur HTTP renvoyé par Nginx pointe vers une cause différente, et les confondre fait perdre un temps précieux en investigation.

CodeSignificationCause la plus fréquente
502 Bad GatewayNginx n'arrive pas à joindre le backendBackend down, ou proxy_pass mal configuré
503 Service UnavailableNginx refuse volontairement de traiterRate limiting déclenché, ou tous les backends down
504 Gateway TimeoutLe backend met trop de temps à répondreproxy_read_timeout dépassé
499 Client Closed RequestLe client a abandonné avant la réponseTimeout côté client ou navigateur fermé trop tôt

Ensuite, une méthode de diagnostic reproductible, plutôt qu'une intuition au cas par cas

Face à un 502 ou 504, la première question à trancher est toujours la même : le problème vient-il de Nginx ou du backend ? Un curl -v http://127.0.0.1:8000/health directement sur le backend, en contournant totalement Nginx, répond immédiatement à cette question et évite de perdre du temps à inspecter la mauvaise couche de l'infrastructure.

Prérequis

Cette leçon rassemble des notions vues dans tout le reste du cours (reverse proxy, timeouts, logs, rate limiting) : elle sert de synthèse pratique plutôt que d'introduction à un nouveau concept.

Il reste une dernière étape essentielle : transformer les bonnes pratiques en réflexe systématique

Une checklist de durcissement (server_tokens off, headers de sécurité, client_max_body_size explicite, blocage des fichiers cachés, rate limiting global, logs JSON) doit être appliquée à CHAQUE nouveau site, pas seulement retenue en théorie après avoir lu ce cours une fois.

Bonne pratique

Intègre nginx -t dans ton pipeline CI/CD, via l'image Docker officielle (docker run --rm -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro nginx:alpine nginx -t), pour qu'une erreur de syntaxe soit détectée automatiquement avant le déploiement, plutôt que découverte en production au moment du reload.

Piège fréquent

Activer un log de debug très verbeux (error_log ... debug;) sur l'ensemble du trafic en production, même temporairement pour investiguer un incident, peut lui-même dégrader les performances et remplir rapidement le disque. Cible toujours ce niveau de log sur une IP précise via une map, jamais sur tout le trafic.

Ce cours Nginx est maintenant complet : de la simple question "pourquoi Nginx ?" jusqu'à une checklist de production niveau expert, en passant par le reverse proxy, le load balancing, TLS, la sécurité et le tuning de performance. La suite logique consiste à appliquer cette checklist sur un projet réel, en partant d'une configuration minimale et en ajoutant chaque brique (TLS, rate limiting, cache) à mesure que le besoin se présente concrètement.

Commandes & code

Debugging, monitoring et checklist de production

nginx
# stub_status : endpoint natif de métriques basiques, à protéger et scraper (Prometheus, monitoring)
server {
    listen 127.0.0.1:8080;    # écoute seulement en local, jamais exposé publiquement

    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny all;
    }
}
bash
curl http://127.0.0.1:8080/nginx_status
# Active connections: 291
# server accepts handled requests
#  16630948 16630948 31070465
# Reading: 6 Writing: 179 Waiting: 106
# -> Reading/Writing/Waiting élevés en continu = signal de saturation à investiguer
text
Erreurs classiques et leur cause la plus fréquente :

502 Bad Gateway     -> le backend est down, ou proxy_pass pointe vers un port/IP incorrect
503 Service Unavailable -> rate limiting déclenché, ou tous les backends d'un upstream sont "down"/"max_fails"
504 Gateway Timeout -> le backend met trop de temps à répondre (proxy_read_timeout dépassé)
499 Client Closed Request -> le CLIENT a fermé la connexion avant que Nginx ait fini de répondre (souvent un timeout front-end)
413 Request Entity Too Large -> client_max_body_size trop petit pour l'upload envoyé
bash
# Diagnostiquer un 502/504 méthodiquement
sudo tail -50 /var/log/nginx/error.log
sudo nginx -t                                   # élimine d'abord une erreur de config
curl -v http://127.0.0.1:8000/health            # teste le backend directement, en contournant Nginx
sudo ss -tlnp | grep 8000                       # le backend écoute-t-il vraiment sur ce port ?

# Activer un log de debug ciblé (TRÈS verbeux, à limiter à une IP en prod)
# nginx.conf : error_log /var/log/nginx/debug.log debug;
events { }
http {
    map $remote_addr $loggable {
        1.2.3.4  1;      # seule cette IP génère des logs debug
        default  0;
    }
}
nginx
# Checklist de durcissement avant mise en production
server {
    server_tokens off;                                   # ne pas exposer la version Nginx
    client_max_body_size 10m;                             # taille explicite, pas le défaut
    add_header Strict-Transport-Security "max-age=63072000" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;

    location ~ /\. { deny all; return 404; }               # fichiers cachés (.git, .env...)

    limit_req_zone $binary_remote_addr zone=global:10m rate=50r/s;
    limit_req zone=global burst=100 nodelay;

    access_log /var/log/nginx/access.log json_combined;
    error_log  /var/log/nginx/error.log warn;
}
bash
# Config-as-code : valider automatiquement en CI avant chaque déploiement
docker run --rm -v $(pwd)/nginx.conf:/etc/nginx/nginx.conf:ro nginx:alpine nginx -t

Résumé

  • stub_status (protégé en local) donne les métriques de base à scraper pour un monitoring externe.
  • 502 = backend injoignable, 503 = rate limit/backend down, 504 = backend trop lent, 499 = client parti avant la réponse.
  • Toujours tester le backend directement (curl 127.0.0.1:port) pour isoler "problème Nginx" vs "problème app".
  • Une checklist de prod (server_tokens off, headers de sécurité, limites explicites, logs JSON) doit être appliquée systématiquement, pas ad hoc.
  • Valider nginx -t en CI (via l'image Docker officielle) avant tout déploiement évite les erreurs de syntaxe en production.

Exercices pratiques

1 disponible
1

Mission : diagnostiquer un pic de 502 en production sous pression

Objectif : Appliquer une méthode de diagnostic reproductible pour isoler un problème Nginx d'un problème backend, puis sécuriser le déploiement suivant avec une checklist et une validation CI.

Contexte

Un service en production renvoie soudainement des erreurs 502 à une partie des utilisateurs. L'équipe de garde doit déterminer en quelques minutes si le problème vient de Nginx, du réseau ou de l'application, sans multiplier les hypothèses non vérifiées.

Résoudre l’exercice →