Introduction
Nginx est souvent la porte d'entrée de votre application. Lorsqu'il ralentit ou tombe en panne, tout semble indisponible. Ce guide montre quoi surveiller, les métriques et signaux de logs qui comptent, des règles d'alerte concrètes, des tableaux de bord qui répondent vite aux questions d'astreinte, et un workflow d'incident utilisable sous pression. Il se termine par un pilote local étroit et mesurable que vous pouvez exécuter de bout en bout avant tout déploiement.
Vue d'ensemble du workflow
Un workflow clair et reproductible garde les changements de surveillance sûrs et ciblés :
- Objectifs et périmètre
- Définir les questions principales à résoudre en quelques minutes : Nginx est-il up ? Les clients échouent-ils (4xx/5xx) ? Une défaillance amont cause-t-elle des 502/504 ? La latence ou la capacité est-elle le problème ?
- Choisir un petit ensemble de signaux par question : métriques pour la disponibilité/la capacité, logs pour les codes de statut et la latence.
- Instrumentation
- Activer le statut Nginx pour les métriques de connexions (
stub_status). - Exporter les métriques vers Prometheus via
nginx-prometheus-exporter. - Collecter et parser les logs d'accès pour les codes de statut et la latence.
- Visualisation
- Construire un tableau de bord Vue d'ensemble pour l'astreinte : santé, connexions, taux de requêtes, taux d'erreurs, latence, et principaux contrevenants.
- Alerting
- Pager sur les symptômes qui affectent les utilisateurs (taux 5xx, Nginx down).
- Créer un ticket sur les tendances de capacité (connexions actives en hausse, approchant les limites).
- Router vers les propriétaires avec contexte et lien vers le runbook.
- Réponse aux incidents
- Utiliser un arbre de décision simple : erreurs côté client vs erreurs serveur vs erreurs amont vs problèmes TLS.
- Documenter et tester les étapes de rollback et de rechargement sécurisé.
Ce qu'il faut surveiller dans Nginx
Santé et capacité de base
- Disponibilité : processus up, exporter up.
- Connexions : actives, en lecture, en écriture, en attente.
- Débit : requêtes par seconde (approximé via les deltas accepted/handled).
- Succès du rechargement de configuration et continuité de l'uptime.
Qualité du trafic
- Taux d'erreurs : 5xx et 4xx depuis les logs d'accès.
- Erreurs amont : 502, 503, 504.
- Déconnexions client : 499.
- Latence :
request_time,upstream_response_timedepuis les logs.
Hygiène sécurité et TLS
- Expiration des certificats TLS pour les endpoints publics (sonde via Blackbox exporter).
Contexte plateforme
- Saturation hôte : CPU, mémoire, descripteurs de fichiers, réseau.
Métriques à collecter (Nginx standard)
Depuis nginx-prometheus-exporter (scrapant stub_status) :
nginx_connections_activenginx_connections_readingnginx_connections_writingnginx_connections_waitingnginx_connections_acceptednginx_connections_handlednginx_up
Métriques hôte (node exporter ou équivalent) :
node_filesystem_avail_bytes,node_network_receive_bytes_total,node_load1,node_cpu_seconds_total, utilisation des descripteurs de fichiers.
Note Kubernetes Ingress Si vous utilisez le Nginx Ingress Controller, privilégiez ses métriques natives telles que : nginx_ingress_controller_requests, nginx_ingress_controller_nginx_process_connections, et les buckets d'histogramme pour la latence quand disponibles.
Logs à collecter et parser
Utilisez un format de log qui émet le statut, request_time et upstream_response_time. Exemple :
log_format main 'remote=$remote_addr host=$host method=$request_method uri=$request_uri '
'status=$status bytes=$body_bytes_sent referer=$http_referer '
'ua=$http_user_agent rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log main;
Parsez en labels et champs numériques pour :
- status (ex. 200, 499, 502, 504)
- request_time (secondes)
- upstream_response_time (secondes ; peut être
-si pas d'amont) - host, préfixe d'uri, méthode (pour les vues top-N)
Exemples d'alertes qui comptent
Exemples Prometheus (exporter Nginx standard) :
# Processus Nginx ou exporter down
- alert: NginxDown
expr: up{job="nginx"} == 0
for: 1m
labels:
severity: page
annotations:
summary: Nginx down sur {{ $labels.instance }}
- alert: NginxExporterDown
expr: up{job="nginx-exporter"} == 0
for: 2m
labels:
severity: ticket
annotations:
summary: Exporter Nginx down sur {{ $labels.instance }}
# Connexions actives au-dessus du seuil de base pour une période soutenue
# Calibrez ce seuil par hôte : observez nginx_connections_active une semaine, alertez à ~80 % du pic observé
- alert: NginxHighActiveConnections
expr: nginx_connections_active > 500
for: 5m
labels:
severity: ticket
annotations:
summary: Connexions actives élevées sur {{ $labels.instance }}
# Accepted moins handled indique des connexions perdues
- alert: NginxConnectionDrops
expr: rate(nginx_connections_accepted[5m]) - rate(nginx_connections_handled[5m]) > 0
for: 2m
labels:
severity: page
annotations:
summary: Perte de connexions sur {{ $labels.instance }} en augmentation
Si vous utilisez le Nginx Ingress Controller, vous pouvez aussi alerter sur les codes HTTP directement depuis les métriques :
- alert: IngressHigh5xxRate
expr: sum by (ingress) (rate(nginx_ingress_controller_requests{status=~"5.."}[5m])) > 5
for: 5m
labels:
severity: page
annotations:
summary: Taux 5xx élevé sur l'ingress {{ $labels.ingress }}
Exemple Loki Ruler (5xx basé sur les logs pour Nginx standard) :
# En supposant que promtail extrait un label 'status' depuis les logs d'accès
- alert: NginxHigh5xxFromLogs
expr: sum(rate({job="nginx_access", status=~"5.."}[5m])) > 5
for: 5m
labels:
severity: page
annotations:
summary: Taux 5xx élevé dans les logs Nginx
Expiration TLS avec Blackbox exporter :
- alert: TLSSoonToExpire
expr: (probe_ssl_earliest_cert_expiry - time()) < 14 * 24 * 3600
for: 0m
labels:
severity: ticket
annotations:
summary: Certificat TLS expire bientôt sur {{ $labels.instance }}
Tableaux de bord qui répondent aux questions d'astreinte
Vue d'ensemble (premier écran)
- Nginx up, exporter up
- Connexions actives avec états : lecture, écriture, attente
- Requêtes par seconde (dérivé des deltas accepted/handled)
- Taux d'erreurs : 5xx, 4xx depuis les logs
- Latence p50, p95 depuis les logs (
request_time) - Top URIs ou hôtes par 5xx et latence (exemple requête Loki :
topk(10, sum by (uri) (rate({job="nginx_access", status=~"5.."}[5m]))))
Capacité et santé
- Tendance connexions actives vs en attente
- CPU, mémoire, saturation réseau du nœud
- Perte de connexions dans le temps
Qualité du trafic
- 499, 502, 504 au fil du temps
- Latence amont vs latence totale (
upstream_response_timevsrequest_time)
Chaque panneau doit comporter une description avec : unité, requête, et pourquoi c'est important. Gardez les raccourcis de plage temporelle à 5 min, 1 h, 24 h pour le triage.
Workflow de réponse aux incidents
Triage rapide
- Nginx est-il up ? Sinon, vérifiez le gestionnaire de service, les changements récents de config, et rechargez proprement.
- Le 5xx a-t-il explosé ? Si oui, regardez 502/504 pour décider si l'amont échoue ou si Nginx sature.
- La latence est-elle haute avec un faible taux d'erreur ? Étudiez la lenteur amont ou la saturation réseau.
- Le 499 est-il haut ? Les clients ferment tôt ; vérifiez les timeouts, le comportement CDN, et les endpoints à queue longue.
Patterns de correction
- Nginx down : valider la config, puis recharger.
nginx -t
systemctl reload nginx
# ou : nginx -s reload
- Connexions actives élevées : augmenter
worker_connections(ex. de 1024 à 4096), revoirkeepalive_timeout(défaut 75 s, envisager 30 s pour fort trafic), et vérifier la capacité amont. - 502/504 : contrôler la santé amont, la résolution DNS,
proxy_connect_timeout/proxy_read_timeout/proxy_send_timeout, et les keepalive entre Nginx et les upstreams (proxy_http_version 1.1; proxy_set_header Connection "\);). - 5xx élevé depuis l'appli : router l'erreur vers les propriétaires d'appli avec les top endpoints depuis les logs.
- Expiration TLS : renouveler, déployer, et vérifier avec la sonde blackbox.
Suivi post-incident
- Documenter le déclencheur, le signal le plus fort, et le changement unique qui a résolu.
- Ajouter ou ajuster une alerte ou un tableau de bord pour éviter la récurrence.
Plan de pilote local
Objectif : prouver qu'on peut voir la santé, les erreurs et la capacité en local. Restez étroit et mesurable.
Ce que vous allez lancer
- Nginx avec
stub_statuset un log d'accès émettant statut et latence nginx-prometheus-exporterpour les métriques- Prometheus pour scraper l'exporter (et blackbox optionnel)
- Grafana pour les tableaux de bord
- Optionnel : Loki + Promtail pour 5xx et latence basés sur les logs
Config Nginx (Locale)
events { worker_connections 1024; }
http {
log_format main 'remote=$remote_addr host=$host method=$request_method uri=$request_uri '
'status=$status bytes=$body_bytes_sent rt=$request_time urt=$upstream_response_time';
access_log /var/log/nginx/access.log main;
server {
listen 80;
location / {
return 200 'ok';
}
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
}
Docker Compose (Labo local)
services:
nginx:
image: nginx:1.25
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./logs:/var/log/nginx
ports:
- '8080:80'
exporter:
image: nginxinc/nginx-prometheus-exporter:0.11.0
command: ['-nginx.scrape-uri', 'http://nginx/nginx_status']
ports:
- '9113:9113'
depends_on: [nginx]
prometheus:
image: prom/prometheus:v2.54.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alerts.yml:/etc/prometheus/alerts.yml:ro
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.enable-lifecycle'
ports:
- '9090:9090'
depends_on: [exporter]
grafana:
image: grafana/grafana:11.0.0
ports:
- '3000:3000'
depends_on: [prometheus]
loki:
image: grafana/loki:2.9.0
command: ['-config.file=/etc/loki/local-config.yaml']
volumes:
- ./loki.yaml:/etc/loki/local-config.yaml:ro
ports:
- '3100:3100'
promtail:
image: grafana/promtail:2.9.0
volumes:
- ./promtail.yaml:/etc/promtail/config.yml:ro
- ./logs:/var/log/nginx:ro
command: ['--config.file=/etc/promtail/config.yml']
depends_on: [loki]
prometheus.yml
scrape_configs:
- job_name: nginx
static_configs:
- targets: ['exporter:9113']
rule_files:
- /etc/prometheus/alerts.yml
alerts.yml
groups:
- name: nginx-basic
rules:
- alert: NginxDown
expr: up{job="nginx"} == 0
for: 1m
labels: {severity: "page"}
annotations: {summary: "Nginx down"}
- alert: NginxHighActiveConnections
expr: nginx_connections_active > 50
for: 2m
labels: {severity: "ticket"}
annotations: {summary: "Connexions actives élevées"}
- alert: NginxConnectionDrops
expr: rate(nginx_connections_accepted[5m]) - rate(nginx_connections_handled[5m]) > 0
for: 2m
labels: {severity: "page"}
annotations: {summary: "Perte de connexions en augmentation"}
promtail.yaml (extraire statut et latence en labels/champs)
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: nginx_access
static_configs:
- targets: ['localhost']
labels:
job: nginx_access
__path__: /var/log/nginx/access.log
pipeline_stages:
- regex:
expression: '.*status=(?P<status>\d{3}).*rt=(?P<rt>[0-9.]+).*urt=(?P<urt>[0-9.\-]+)'
- labels:
status:
Test de fumée
- Ouvrez Grafana à
http://localhost:3000et ajoutez Prometheus àhttp://prometheus:9090comme source de données. - Créez un panneau rapide avec
nginx_connections_active. - Générez de la charge :
for i in {1..100}; do curl -s http://localhost:8080/; done - Confirmez que les alertes se déclenchent dans Prometheus pour les connexions actives élevées si vous augmentez la charge.
- Si vous utilisez Loki, construisez un panneau avec la requête :
{job="nginx_access"}et ajoutez un panneau stat affichant le taux 5xx :sum(rate({job="nginx_access", status=~"5.."}[5m])).
Critères de sortie du pilote
- Vous voyez Nginx up, les connexions, et une tendance claire des requêtes.
- Une hausse de 5xx depuis les logs est visible en quelques minutes.
- Trois alertes se déclenchent dans des conditions contrôlées et s'arrêtent quand la condition disparaît.
Conclusion
Commencez par un pilote local qui prouve que vous pouvez observer la disponibilité, la capacité et les signaux d'erreur. Gardez les seuils proches de votre ligne de base et ne promouvez que ce que vous avez testé. Étendez ensuite à la santé amont, les percentiles de latence, et les vérifications TLS comme prochaines étapes. Documentez comment trier Nginx vs amont, et gardez les commandes de rechargement et de rollback prêtes.