
Nginx est un serveur web et reverse proxy ultra-performant. Si vous devez servir un site statique, proxyfier une API, activer HTTPS ou diagnostiquer une erreur 502, ce guide vous donne les recettes essentielles en quelques minutes.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »Niveau : Débutant → Intermédiaire · Durée : 30-45 min
À la fin de ce guide, vous saurez :
- Servir un site statique en 5 minutes
- Configurer un reverse proxy vers une application
- Activer HTTPS avec Let’s Encrypt (TLS 1.2/1.3)
- Diagnostiquer les erreurs courantes (502, 504, 403)
- Sécuriser et optimiser votre configuration
Choisissez votre parcours
Section intitulée « Choisissez votre parcours »Nginx en 60 secondes
Section intitulée « Nginx en 60 secondes »Nginx (prononcé “engine-x”) est à la fois :
- Un serveur web pour fichiers statiques (HTML, CSS, JS, images)
- Un reverse proxy pour transmettre les requêtes à des applications backend
- Un load balancer pour répartir le trafic entre plusieurs serveurs
- Un cache pour accélérer les réponses
L’analogie du switch réseau Layer 7
Section intitulée « L’analogie du switch réseau Layer 7 »Imaginez Nginx comme un switch réseau intelligent (L7) :
| Concept Nginx | Analogie | Exemple concret |
|---|---|---|
server {} | Un port d’écoute du switch | server { listen 80; server_name api.example.com; } |
location {} | Les règles de routage sur ce port | location /api { } route vers le backend API |
proxy_pass | La règle de forwarding | La requête est forwardée vers votre app Node.js |
root | Servir depuis le cache local | Sert directement les fichiers HTML/CSS |
Nginx reçoit les paquets (requêtes), les route selon les règles (routing), et les forward vers le bon backend (upstream ou fichiers).
📜 Pour la culture : historique de Nginx
Nginx a été créé par Igor Sysoev en 2004 pour résoudre le problème des 10 000 connexions simultanées (C10K) que les serveurs de l’époque (Apache) géraient mal. Son architecture asynchrone et événementielle lui permet de gérer des milliers de connexions avec peu de ressources.
En 2019, F5 Networks a acquis Nginx Inc. pour 670 millions de dollars. Aujourd’hui, Nginx est l’un des serveurs web les plus utilisés au monde, propulsant des sites comme Netflix, Dropbox et WordPress.com.
Installation
Section intitulée « Installation »# Ajouter le dépôt officiel Nginx (version récente)sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyringcurl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \ | sudo tee /etc/apt/sources.list.d/nginx.list
# Installersudo apt update && sudo apt install nginx
# Démarrer et activer au bootsudo systemctl enable --now nginx# Ajouter le dépôt officiel Nginxsudo tee /etc/yum.repos.d/nginx.repo << 'EOF'[nginx-stable]name=nginx stable repobaseurl=http://nginx.org/packages/rhel/$releasever/$basearch/gpgcheck=1enabled=1gpgkey=https://nginx.org/keys/nginx_signing.keyEOF
# Installersudo dnf install nginx
# Démarrer et activer au bootsudo systemctl enable --now nginxVérification : ouvrez http://votre-ip dans un navigateur — vous devez voir la page “Welcome to nginx”.
# Vérifier que Nginx tournesystemctl status nginx# active (running) ✓
# Vérifier la versionnginx -v# nginx version: nginx/1.26.xServir un site statique
Section intitulée « Servir un site statique »C’est le cas d’usage le plus simple : afficher des fichiers HTML/CSS/JS.
-
Créer le répertoire et le fichier
Fenêtre de terminal sudo mkdir -p /var/www/monsiteecho '<h1>Hello Nginx!</h1>' | sudo tee /var/www/monsite/index.html -
Créer la configuration du site
Fenêtre de terminal sudo tee /etc/nginx/conf.d/monsite.conf << 'EOF'server {listen 80;server_name monsite.local;root /var/www/monsite;index index.html;location / {try_files $uri $uri/ =404;}}EOF -
Tester et recharger la configuration
Fenêtre de terminal # Toujours tester AVANT de rechargersudo nginx -t# nginx: configuration file /etc/nginx/nginx.conf test is successfulsudo systemctl reload nginx -
Vérifier
Fenêtre de terminal curl -I http://localhost# HTTP/1.1 200 OK
Configurer un reverse proxy
Section intitulée « Configurer un reverse proxy »Pourquoi utiliser un reverse proxy ?
Section intitulée « Pourquoi utiliser un reverse proxy ? »Un reverse proxy est un intermédiaire entre vos utilisateurs et votre application. Sans lui, votre app serait exposée directement sur Internet.
Scénario concret : Vous avez une API Node.js qui tourne sur localhost:3000. Vous voulez :
- Qu’elle soit accessible sur
api.example.com(pasexample.com:3000) - Qu’elle utilise HTTPS (votre app Node ne gère pas TLS)
- Que les logs HTTP soient centralisés
- Pouvoir ajouter du rate limiting, du cache, etc.
Le reverse proxy fait tout ça. Votre app reste simple, Nginx gère la complexité HTTP.
| Question | Réponse |
|---|---|
| ”Pourquoi pas exposer mon app directement ?” | Sécurité (TLS), flexibilité (plusieurs apps), performances (cache) |
| “Pourquoi Nginx et pas mon framework ?” | Nginx est optimisé pour ça (C10K), votre app pour la logique métier |
| ”Quand est-ce inutile ?” | Développement local, ou si vous utilisez un PaaS (Heroku, Vercel) |
Configuration de base
Section intitulée « Configuration de base »server { listen 80; server_name api.example.com;
location / { proxy_pass http://127.0.0.1:3000;
# Headers essentiels pour que le backend connaisse le client réel 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; }}Timeouts pour les backends lents
Section intitulée « Timeouts pour les backends lents »Si votre backend met du temps à répondre (traitement lourd, IA, etc.) :
location / { proxy_pass http://backend:3000;
# Augmenter les timeouts (défaut: 60s) proxy_connect_timeout 120s; proxy_send_timeout 120s; proxy_read_timeout 120s;
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr;}WebSockets
Section intitulée « WebSockets »Pour les applications temps réel (chat, notifications) :
location /ws/ { proxy_pass http://backend:3000;
# Upgrade de connexion pour WebSocket proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr;}Activer HTTPS avec Let’s Encrypt
Section intitulée « Activer HTTPS avec Let’s Encrypt »Pourquoi HTTPS est indispensable
Section intitulée « Pourquoi HTTPS est indispensable »HTTPS n’est plus une option, c’est une obligation :
| Sans HTTPS | Avec HTTPS |
|---|---|
| Les mots de passe transitent en clair | Tout est chiffré |
| Google pénalise votre SEO | Bonus de classement |
| Les navigateurs affichent “Non sécurisé” | Cadenas vert |
| Vulnérable aux attaques man-in-the-middle | Communication sécurisée |
Let’s Encrypt est une autorité de certification gratuite. Certbot est l’outil qui automatise l’obtention et le renouvellement des certificats.
-
Installer Certbot
Fenêtre de terminal sudo apt install certbot python3-certbot-nginxFenêtre de terminal sudo dnf install epel-releasesudo dnf install certbot python3-certbot-nginx -
Obtenir le certificat
Fenêtre de terminal sudo certbot --nginx -d example.com -d www.example.comCertbot modifie automatiquement votre configuration Nginx.
-
Vérifier la configuration générée
Certbot crée une configuration similaire à :
server {listen 443 ssl http2;server_name example.com www.example.com;ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;# Forcer TLS 1.2/1.3 (ne pas se fier aux défauts)ssl_protocols TLSv1.2 TLSv1.3;ssl_prefer_server_ciphers on;# HSTS : force HTTPS pendant 1 anadd_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;location / {root /var/www/html;index index.html;}}# Redirection HTTP → HTTPSserver {listen 80;server_name example.com www.example.com;return 301 https://$host$request_uri;} -
Configurer le renouvellement automatique
Fenêtre de terminal # Tester le renouvellementsudo certbot renew --dry-run# Le timer systemd gère le renouvellement automatiquesystemctl list-timers | grep certbot
Comprendre la structure des fichiers
Section intitulée « Comprendre la structure des fichiers »La configuration Nginx est organisée en plusieurs fichiers :
/etc/nginx/├── nginx.conf # Config principale (global)├── conf.d/ # Vos sites (1 fichier par site)│ ├── default.conf│ └── monsite.conf├── mime.types # Types MIME└── modules-enabled/ # Modules dynamiques (Debian)Le fichier principal nginx.conf
Section intitulée « Le fichier principal nginx.conf »user www-data; # Utilisateur des workersworker_processes auto; # 1 worker par CPUpid /run/nginx.pid;
events { worker_connections 1024; # Connexions simultanées par worker}
http { # Performances sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65;
# Types MIME include /etc/nginx/mime.types; default_type application/octet-stream;
# Logs access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log;
# Compression gzip on; gzip_types text/plain text/css application/json application/javascript;
# Masquer la version de Nginx server_tokens off;
# Inclure les configurations des sites include /etc/nginx/conf.d/*.conf;}Dépannage express
Section intitulée « Dépannage express »Le dépannage Nginx suit toujours le même schéma : est-ce que le problème vient de la config ? Du backend ? Des permissions ? Des logs ?
Avec les bonnes commandes, vous identifiez la cause en 30 secondes.
La commande magique : nginx -t
Section intitulée « La commande magique : nginx -t »Toujours tester la configuration avant de recharger :
sudo nginx -t# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok# nginx: configuration file /etc/nginx/nginx.conf test is successfulSi erreur, Nginx indique la ligne exacte du problème.
Diagnostic en 30 secondes
Section intitulée « Diagnostic en 30 secondes »# 1. Nginx tourne-t-il ?systemctl status nginx
# 2. La config est-elle valide ?sudo nginx -t
# 3. Dump complet de la config (includes résolus)sudo nginx -T | less
# 4. Logs récents (systemd)journalctl -u nginx --since "10 min ago"
# 5. Logs d'erreur Nginxsudo tail -20 /var/log/nginx/error.log
# 6. Le port est-il écouté ?ss -tlnp | grep :80Erreurs courantes et solutions
Section intitulée « Erreurs courantes et solutions »| Erreur | Cause probable | Solution |
|---|---|---|
| 403 Forbidden | Permissions fichiers | sudo chown -R www-data:www-data /var/www/ |
| 404 Not Found | Mauvais root ou fichier absent | Vérifier le chemin dans la config |
| 502 Bad Gateway | Backend ne répond pas | Vérifier que l’app backend tourne |
| 504 Gateway Timeout | Backend trop lent | Augmenter proxy_read_timeout |
| ”Address already in use” | Port déjà utilisé | ss -tlnp | grep :80 pour identifier |
Débugger une 502
Section intitulée « Débugger une 502 »# 1. Le backend tourne-t-il ?curl -I http://127.0.0.1:3000# Si "Connection refused" → le backend est down
# 2. Nginx peut-il joindre le backend ?sudo -u www-data curl http://127.0.0.1:3000# Parfois c'est un problème de permissions/SELinux
# 3. Logs détailléssudo tail -f /var/log/nginx/error.log# "connect() failed (111: Connection refused)"Optimisation et cache
Section intitulée « Optimisation et cache »Compression gzip
Section intitulée « Compression gzip »Réduit la taille des réponses de 60-80% :
http { gzip on; gzip_vary on; gzip_min_length 1024; gzip_types text/plain text/css text/javascript application/json application/javascript application/xml image/svg+xml;}Cache pour reverse proxy
Section intitulée « Cache pour reverse proxy »Stocke les réponses du backend pour réduire sa charge :
# Définir la zone de cache (dans http {})proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;
server { location / { proxy_pass http://backend:3000; proxy_cache my_cache; proxy_cache_valid 200 10m; # Cache les 200 pendant 10 min proxy_cache_valid 404 1m; # Cache les 404 pendant 1 min
# Header pour debug add_header X-Cache-Status $upstream_cache_status; }}Load balancing
Section intitulée « Load balancing »Répartir le trafic entre plusieurs backends :
upstream backend_pool { # Round-robin par défaut server backend1.example.com:3000; server backend2.example.com:3000; server backend3.example.com:3000 backup; # Utilisé si les autres sont down}
server { location / { proxy_pass http://backend_pool; proxy_set_header Host $host; }}Algorithmes disponibles :
upstream backend_pool { least_conn; # Envoie au serveur le moins chargé # ou ip_hash; # Même client → même serveur (sessions)
server backend1:3000; server backend2:3000;}Sécurisation
Section intitulée « Sécurisation »Headers de sécurité
Section intitulée « Headers de sécurité »server { # Empêche le clickjacking add_header X-Frame-Options "SAMEORIGIN" always;
# Empêche le sniffing MIME add_header X-Content-Type-Options "nosniff" always;
# Politique de référent add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# HSTS (après avoir vérifié que HTTPS fonctionne) add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# CSP basique (à adapter selon votre app) add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;}Rate limiting
Section intitulée « Rate limiting »Protéger contre les abus et attaques DDoS légères :
# Définir la zone de limite (dans http {})limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server { location /api/ { # Max 10 req/s, burst de 20 avec délai limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend:3000; }}Restreindre l’accès à /admin
Section intitulée « Restreindre l’accès à /admin »location /admin/ { # Autoriser uniquement certaines IP allow 192.168.1.0/24; allow 10.0.0.0/8; deny all;
proxy_pass http://backend:3000;}Limiter les méthodes HTTP
Section intitulée « Limiter les méthodes HTTP »location / { # Autoriser seulement GET, POST, HEAD limit_except GET POST HEAD { deny all; }
root /var/www/html;}Monitoring
Section intitulée « Monitoring »Activer le module status
Section intitulée « Activer le module status »server { location /nginx_status { stub_status on; allow 127.0.0.1; deny all; }}curl http://127.0.0.1/nginx_status# Active connections: 42# server accepts handled requests# 1234567 1234567 9876543# Reading: 0 Writing: 1 Waiting: 41Prometheus + nginx-exporter
Section intitulée « Prometheus + nginx-exporter »Pour un monitoring complet, utilisez nginx-prometheus-exporter :
# Option 1 : --network host (Linux)docker run --network host nginx/nginx-prometheus-exporter:latest \ -nginx.scrape-uri=http://127.0.0.1/nginx_status
# Option 2 : IP explicite du hostdocker run -p 9113:9113 nginx/nginx-prometheus-exporter:latest \ -nginx.scrape-uri=http://192.168.1.10/nginx_statusPuis configurez Prometheus pour scraper localhost:9113/metrics et visualisez dans Grafana.
Pourquoi ma location regex ne matche pas ?
Nginx évalue les location dans un ordre précis :
=(exact) → priorité absolue^~(préfixe prioritaire) → stoppe la recherche regex~/~*(regex) → première regex qui matche- préfixe simple → le plus long gagne
location = /api { } # Seulement /api exactlocation ^~ /static/ { } # /static/* sans chercher regexlocation ~ \.php$ { } # Regex : fichiers .phplocation / { } # Catch-allPiège courant : une location préfixe / capture tout avant que votre regex ne soit évaluée. Utilisez ^~ si vous voulez bloquer les regex sur un chemin.
Quelle est la différence entre root et alias ?
root: le chemin de l’URI est ajouté au rootalias: le chemin de l’URI est remplacé par l’alias
# Avec root : /images/photo.jpg → /var/www/images/photo.jpglocation /images/ { root /var/www;}
# Avec alias : /images/photo.jpg → /data/photos/photo.jpglocation /images/ { alias /data/photos/;}Règle simple : utilisez root par défaut, alias seulement si vous voulez mapper une URL vers un chemin complètement différent.
Pourquoi mon proxy_pass ne fonctionne pas ?
Vérifiez dans l’ordre :
- Le backend tourne-t-il ? →
curl http://127.0.0.1:3000 - Le slash final → avec ou sans
/change le comportement - SELinux (RHEL) →
setsebool -P httpd_can_network_connect 1 - Firewall → le port est-il ouvert ?
- Logs →
tail /var/log/nginx/error.log
Comment recharger Nginx sans interruption ?
# Tester d'abordsudo nginx -t
# Recharger (pas de downtime)sudo systemctl reload nginx
# OUsudo nginx -s reloadNe jamais utiliser restart en production si reload suffit.
Comment servir plusieurs sites sur le même serveur ?
Créez un fichier par site dans /etc/nginx/conf.d/ :
server { listen 80; server_name site1.com; root /var/www/site1;}
# /etc/nginx/conf.d/site2.confserver { listen 80; server_name site2.com; root /var/www/site2;}Nginx utilise le server_name pour router les requêtes.
Recettes Nginx
Section intitulée « Recettes Nginx »Site statique
Section intitulée « Site statique »server { listen 80; server_name example.com; root /var/www/html; index index.html; location / { try_files $uri $uri/ =404; }}SPA (React/Vue/Angular)
Section intitulée « SPA (React/Vue/Angular) »location / { root /var/www/app; try_files $uri $uri/ /index.html;}Reverse proxy
Section intitulée « Reverse proxy »location / { proxy_pass http://127.0.0.1:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}WebSocket
Section intitulée « WebSocket »location /ws/ { proxy_pass http://backend:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";}Cache proxy
Section intitulée « Cache proxy »proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g;
location / { proxy_pass http://backend; proxy_cache my_cache; proxy_cache_valid 200 10m;}Rate limiting
Section intitulée « Rate limiting »limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
location /api/ { limit_req zone=api burst=20 nodelay; proxy_pass http://backend;}Basic Auth
Section intitulée « Basic Auth »location /admin/ { auth_basic "Zone Admin"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://backend;}IP allowlist
Section intitulée « IP allowlist »location /admin/ { allow 192.168.1.0/24; allow 10.0.0.0/8; deny all; proxy_pass http://backend;}Redirection HTTPS
Section intitulée « Redirection HTTPS »server { listen 80; server_name example.com; return 301 https://$host$request_uri;}Page maintenance
Section intitulée « Page maintenance »location / { if (-f /var/www/maintenance.html) { return 503; } proxy_pass http://backend;}error_page 503 /maintenance.html;location = /maintenance.html { root /var/www;}Upload lourd
Section intitulée « Upload lourd »location /upload/ { client_max_body_size 100M; proxy_pass http://backend; proxy_read_timeout 300s;}Load balancing
Section intitulée « Load balancing »upstream backend_pool { least_conn; server backend1:3000; server backend2:3000; server backend3:3000 backup;}
location / { proxy_pass http://backend_pool;}Pièges à éviter
Section intitulée « Pièges à éviter »| Erreur | Conséquence | Solution |
|---|---|---|
| Slash final dans proxy_pass | /api/users → backend reçoit /users au lieu de /api/users | Sans slash = URI conservée. Testez avec curl -v |
| Confondre root et alias | 404 car le chemin n’existe pas | alias /data/photos/; avec slash final |
| Ordre des locations | Une location préfixe capture avant la regex | = (exact) > ^~ (préfixe prio) > regex > préfixe |
| DNS statique en Docker/K8s | Nginx garde l’ancienne IP après redéploiement | resolver 127.0.0.11; set $backend "http://app:3000"; proxy_pass $backend; |
| SELinux bloque le proxy | 502 Bad Gateway sur RHEL/Rocky | setsebool -P httpd_can_network_connect 1 |
| Permissions fichiers | 403 Forbidden sur les fichiers statiques | chown -R www-data:www-data /var/www && chmod -R 755 /var/www |
| try_files sans fallback SPA | 404 sur les routes frontend | try_files $uri $uri/ /index.html; |
| Logs dans le mauvais fichier | Debug impossible | access_log /var/log/nginx/monsite-access.log; |
Aide-mémoire
Section intitulée « Aide-mémoire »Structure
Section intitulée « Structure »| Directive | Description |
|---|---|
server { } | Bloc de configuration d’un site |
location /path { } | Bloc pour un chemin spécifique |
upstream name { } | Groupe de backends |
include /path/*.conf; | Inclure d’autres fichiers |
| Directive | Description |
|---|---|
listen 80; | Écouter sur port 80 |
listen 443 ssl http2; | HTTPS + HTTP/2 |
server_name example.com; | Nom de domaine du site |
server_name _; | Catch-all (default server) |
Fichiers
Section intitulée « Fichiers »| Directive | Description |
|---|---|
root /var/www/html; | Racine des fichiers |
index index.html; | Fichier par défaut |
try_files $uri $uri/ =404; | Chercher fichier/dossier ou 404 |
alias /autre/chemin/; | Remplacer le chemin (avec slash) |
| Directive | Description |
|---|---|
proxy_pass http://backend:3000; | Transmettre au backend |
proxy_set_header Host $host; | Transmettre le Host original |
proxy_set_header X-Real-IP $remote_addr; | Transmettre l’IP client |
proxy_read_timeout 120s; | Timeout lecture backend |
| Directive | Description |
|---|---|
ssl_certificate /path/fullchain.pem; | Certificat + chaîne |
ssl_certificate_key /path/privkey.pem; | Clé privée |
ssl_protocols TLSv1.2 TLSv1.3; | Forcer TLS moderne |
add_header Strict-Transport-Security "max-age=31536000"; | HSTS |
| Commande | Description |
|---|---|
nginx -t | Tester la configuration |
nginx -T | Dump config complète (includes résolus) |
nginx -s reload | Recharger sans interruption |
nginx -s stop | Arrêter immédiatement |
À retenir
Section intitulée « À retenir »nginx -t: toujours tester avant de rechargerserver {}+location {}: les 2 blocs fondamentaux- TLS 1.2/1.3 uniquement : jamais TLS 1.0/1.1
proxy_set_header: transmettre les infos client au backend- Slash dans
proxy_pass: avec ou sans change tout reload≠restart: reload = sans interruption- Logs :
/var/log/nginx/error.logest votre ami
Prochaines étapes
Section intitulée « Prochaines étapes »Ressources
Section intitulée « Ressources »- Documentation officielle : nginx.org/en/docs
- NGINX (F5) Docs : docs.nginx.com — version commerciale
- Mozilla SSL Config Generator : ssl-config.mozilla.org — générer une config TLS sécurisée
- GitHub : github.com/nginx/nginx
FAQ - Questions Fréquemment Posées
Section intitulée « FAQ - Questions Fréquemment Posées »Définition
Nginx (prononcé "engine-x") est un serveur web et reverse proxy haute performance créé par Igor Sysoev en 2004.Fonctions principales
| Fonction | Description |
|---|---|
| Serveur web | Sert fichiers statiques (HTML, CSS, JS, images) |
| Reverse proxy | Transmet les requêtes à des backends (Node.js, Python) |
| Load balancer | Répartit le trafic entre plusieurs serveurs |
| Cache | Stocke les réponses pour accélérer les requêtes |
Pourquoi Nginx ?
Son architecture asynchrone et événementielle résout le problème C10K (10 000 connexions simultanées) que les serveurs traditionnels géraient mal.Sites utilisant Nginx
Netflix, Dropbox, WordPress.com, Airbnb et des millions d'autres sites.Installation rapide (version des dépôts)
sudo apt update && sudo apt install nginx
sudo systemctl enable --now nginx
Installation version récente (dépôt officiel)
# Ajouter la clé et le dépôt
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
# Installer
sudo apt update && sudo apt install nginx
sudo systemctl enable --now nginx
Vérification
systemctl status nginx # Doit être active (running)
nginx -v # Affiche la version
curl -I http://localhost # Doit retourner HTTP 200
Installation
# Ajouter le dépôt officiel Nginx
sudo tee /etc/yum.repos.d/nginx.repo << 'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/rhel/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
EOF
# Installer et démarrer
sudo dnf install nginx
sudo systemctl enable --now nginx
Configuration SELinux
Si vous utilisez Nginx comme reverse proxy :# Autoriser les connexions réseau sortantes
sudo setsebool -P httpd_can_network_connect 1
Vérification
systemctl status nginx
curl http://localhost
Structure de base
# /etc/nginx/conf.d/monsite.conf
server {
listen 80;
server_name monsite.com www.monsite.com;
root /var/www/monsite;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Directives principales
| Directive | Rôle |
|---|---|
listen |
Port d'écoute (80, 443, etc.) |
server_name |
Domaines acceptés |
root |
Dossier racine des fichiers |
location |
Règles pour une URL |
Déploiement
# Toujours tester AVANT de recharger
sudo nginx -t
sudo systemctl reload nginx
try_files expliqué
try_files $uri $uri/ =404; signifie :- Chercher le fichier demandé
- Sinon chercher un répertoire
- Sinon retourner 404
Configuration de base
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
# Headers essentiels
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;
}
}
Attention au slash final
# Sans slash : URI complète transmise
location /api/ {
proxy_pass http://backend:3000;
}
# /api/users → http://backend:3000/api/users
# Avec slash : URI réécrite
location /api/ {
proxy_pass http://backend:3000/;
}
# /api/users → http://backend:3000/users
Timeouts pour backends lents
proxy_connect_timeout 120s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
Installation de Certbot
# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx
# RHEL/Rocky
sudo dnf install epel-release
sudo dnf install certbot python3-certbot-nginx
Obtenir le certificat
sudo certbot --nginx -d example.com -d www.example.com
Certbot modifie automatiquement votre configuration.Configuration générée
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
Renouvellement automatique
sudo certbot renew --dry-run # Tester
systemctl list-timers | grep certbot # Vérifier le timer
Comparaison
| Critère | Nginx | Apache |
|---|---|---|
| Architecture | Asynchrone événementielle | Processus/threads (MPM) |
| Connexions simultanées | Excellent (C10K+) | Bon avec event MPM |
| Contenu statique | Très rapide | Rapide |
| Configuration dynamique | Non (.htaccess inexistant) | Oui (.htaccess) |
| Modules | Compilés à la construction | Chargement dynamique |
| Reverse proxy | Natif, performant | Possible (mod_proxy) |
| Consommation RAM | Faible | Modérée à élevée |
Quand choisir Nginx ?
- Reverse proxy devant apps Node/Python/Go
- Sites à fort trafic
- Servir du contenu statique
- Load balancing
Quand choisir Apache ?
- Hébergement mutualisé (besoin de .htaccess)
- Applications PHP traditionnelles
- Besoin de modules dynamiques spécifiques
Configuration de base
upstream backend_pool {
server backend1.example.com:3000;
server backend2.example.com:3000;
server backend3.example.com:3000 backup; # Serveur de secours
}
server {
location / {
proxy_pass http://backend_pool;
proxy_set_header Host $host;
}
}
Algorithmes disponibles
| Algorithme | Usage |
|---|---|
| round-robin | Défaut, alternance simple |
| least_conn | Envoie au serveur le moins chargé |
| ip_hash | Même client → même serveur (sessions) |
| hash | Hash personnalisé (ex: URI) |
Exemple least_conn
upstream backend_pool {
least_conn;
server backend1:3000;
server backend2:3000 weight=2; # Reçoit 2× plus
}
Causes fréquentes
| Cause | Diagnostic |
|---|---|
| Backend down | curl http://127.0.0.1:3000 → Connection refused |
| Mauvaise IP/port | Vérifier proxy_pass |
| SELinux bloque | Logs + setsebool |
| Timeout | Backend trop lent |
Diagnostic pas à pas
# 1. Le backend tourne-t-il ?
curl -I http://127.0.0.1:3000
# Si "Connection refused" → le backend est down
# 2. Nginx peut-il joindre le backend ?
sudo -u www-data curl http://127.0.0.1:3000
# 3. Logs détaillés
sudo tail -f /var/log/nginx/error.log
# Chercher: "connect() failed (111: Connection refused)"
Solution SELinux (RHEL/Rocky)
sudo setsebool -P httpd_can_network_connect 1
Solution timeout
proxy_read_timeout 120s;
Causes fréquentes
| Cause | Solution |
|---|---|
| Permissions fichiers | chown -R www-data:www-data /var/www/ |
| Permissions dossiers | Dossiers en 755, fichiers en 644 |
| Index manquant | Ajouter index index.html; |
| autoindex off | Activer autoindex on; si voulu |
| deny all actif | Vérifier les règles allow/deny |
Diagnostic
# Vérifier les permissions
ls -la /var/www/monsite/
# Corriger les permissions
sudo chown -R www-data:www-data /var/www/monsite/
sudo find /var/www/monsite/ -type d -exec chmod 755 {} \;
sudo find /var/www/monsite/ -type f -exec chmod 644 {} \;
# Vérifier que index.html existe
ls -la /var/www/monsite/index.html
Logs
sudo tail -f /var/log/nginx/error.log
# Chercher: "directory index of \"/var/www/...\" is forbidden"
Commandes de validation
# Tester la syntaxe (OBLIGATOIRE avant reload)
sudo nginx -t
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful
# Afficher la config complète (includes résolus)
sudo nginx -T | less
En cas d'erreur
Nginx indique la ligne exacte du problème :nginx: [emerg] unknown directive "proxypass" in /etc/nginx/conf.d/api.conf:12
→ Corriger ligne 12 (proxypass → proxy_pass)Workflow sécurisé
# 1. Éditer la config
sudo nano /etc/nginx/conf.d/monsite.conf
# 2. Tester
sudo nginx -t
# 3. Recharger seulement si OK
sudo systemctl reload nginx
Règle d'or : Jamais de reload sans nginx -t réussi.Configuration
# Dans http {} : définir la zone
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
# Appliquer la limite
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend:3000;
}
}
Paramètres expliqués
| Paramètre | Rôle |
|---|---|
$binary_remote_addr |
Limite par IP client |
zone=api_limit:10m |
Zone de 10MB en mémoire |
rate=10r/s |
10 requêtes par seconde max |
burst=20 |
20 requêtes en rafale autorisées |
nodelay |
Refuse immédiatement si dépassé |
Autres clés possibles
# Par URI
limit_req_zone $request_uri zone=uri_limit:10m rate=5r/s;
# Par serveur (global)
limit_req_zone $server_name zone=server_limit:10m rate=100r/s;