## 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_time depuis 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_active

- nginx_connections_reading

- nginx_connections_writing

- nginx_connections_waiting

- nginx_connections_accepted

- nginx_connections_handled

- nginx_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_time vs request_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), revoir keepalive_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_status et un log d'accès émettant statut et latence

- nginx-prometheus-exporter pour 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:3000 et ajoutez Prometheus à http://prometheus:9090 comme 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.