Guide complet Docker Nginx : montage des configs, HTTPS et reverse proxy

Septième docker restart nginx, rafraîchissement du navigateur — toujours une page 502. Vous avez pourtant modifié nginx.conf, mais la config dans le conteneur ne change pas.
Les pièges du déploiement Nginx sous Docker, presque tout le monde les a rencontrés : montage des fichiers, certificats HTTPS, communication entre conteneurs. Cet article couvre le montage correct, le renouvellement automatique Let’s Encrypt et le réseau du reverse proxy pour un déploiement Docker Nginx utilisable de bout en bout.
Vous apprendrez :
- Pourquoi la config ne s’applique pas et 5 façons correctes de monter les fichiers
- Du certificat auto-signé à Let’s Encrypt pour HTTPS
- Réseau et reverse proxy vers d’autres conteneurs Docker
- Durcissement sécurité et tuning performance en production
Configuration de base Docker Nginx et montage des fichiers
Pourquoi monter les fichiers de configuration ?
Intégrer la config Nginx dans l’image ? Possible, mais peu pratique : chaque changement impose rebuild, push, pull, restart — des minutes perdues. En incident à 2 h du matin, attendre un build d’image pour un rollback de config, on évite.
Le montage résout cela : modifier sur l’hôte, effet immédiat dans le conteneur. Tests, rollback et travail d’équipe deviennent simples.
Structure des répertoires clés dans le conteneur
/etc/nginx/
├── nginx.conf # Configuration principale
├── conf.d/ # Sous-configurations par site
│ └── default.conf # Site par défaut
/usr/share/nginx/html # Racine des fichiers statiques
/var/log/nginx/ # Journaux
├── access.log
└── error.log
Point crucial : include /etc/nginx/conf.d/*.conf; dans nginx.conf charge tous les .conf de conf.d. Monter uniquement nginx.conf sans conf.d — premier piège classique.
Montage correct : étape par étape
Étape 1 : copier la config par défaut du conteneur comme modèle
La config officielle est testée ; partir de là vaut mieux qu’écrire de zéro.
# Conteneur temporaire
docker run --name nginx-temp -d nginx
# Copier la config par défaut
docker cp nginx-temp:/etc/nginx/nginx.conf ./nginx/nginx.conf
docker cp nginx-temp:/etc/nginx/conf.d ./nginx/conf.d
# Nettoyer
docker stop nginx-temp && docker rm nginx-temp
Étape 2 : arborescence standard sur l’hôte
Habituellement sous /opt (à adapter) :
mkdir -p /opt/nginx/{conf,conf.d,html,logs,ssl}
Couvre config, statiques, logs et certificats SSL.
Étape 3 : démarrer le conteneur avec tous les montages
docker run -d --name my-nginx \
-p 80:80 -p 443:443 \
-v /opt/nginx/conf/nginx.conf:/etc/nginx/nginx.conf:ro \
-v /opt/nginx/conf.d:/etc/nginx/conf.d \
-v /opt/nginx/html:/usr/share/nginx/html \
-v /opt/nginx/logs:/var/log/nginx \
-v /opt/nginx/ssl:/etc/nginx/ssl \
nginx
Points importants :
-p 80:80 -p 443:443: HTTP et HTTPS (pour la suite):rosur nginx.conf : lecture seule, pas de modification accidentelle dans le conteneur- Monter tout le répertoire
conf.d, pas un seul fichier
Quatre pièges fréquents
Piège 1 : vim et désynchronisation
Après édition de nginx.conf sur l’hôte, restart — rien ne change. vim modifie l’inode ; Docker lie par inode, le conteneur voit l’ancien fichier.
Solutions :
- nano (ne change pas l’inode de la même façon)
- monter un répertoire entier plutôt qu’un fichier
On privilégie le montage de répertoire : inode variable, ajout/suppression de fichiers libre.
Piège 2 : chemin include incorrect
docker exec -it my-nginx bash
cat /etc/nginx/nginx.conf | grep include
Il faut :
include /etc/nginx/conf.d/*.conf;
/opt/nginx/conf.d/*.conf (chemin hôte) dans le conteneur — erreur.
Piège 3 : oublier conf.d
nginx.conf seul ne suffit pas : les nouveaux sites dans conf.d sur l’hôte n’apparaissent pas dans le conteneur.
Vérification :
docker exec my-nginx ls /etc/nginx/conf.d
Piège 4 : permissions
Sur Linux, permissions trop strictes : le processus nginx ne lit pas la config.
chmod 644 /opt/nginx/conf/nginx.conf
chmod 644 /opt/nginx/conf.d/*.conf
Après modification :
docker exec my-nginx nginx -t
syntax is ok — vous pouvez recharger.
Fichier unique vs répertoire ?
nginx.conf : fichier unique + :ro si peu de changements.
conf.d : répertoire entier pour ajouter des sites facilement.
html, logs : répertoires.
Règle : plusieurs fichiers à gérer → répertoire ; config centrale versionnée → fichier + :ro.
HTTPS et renouvellement automatique Let’s Encrypt
Certificat auto-signé : validation rapide en dev
En production, certificat reconnu ; en dev, auto-signé suffit :
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /opt/nginx/ssl/nginx.key \
-out /opt/nginx/ssl/nginx.crt \
-subj "/C=CN/ST=Beijing/L=Beijing/O=Dev/CN=localhost"
Fichiers :
nginx.key: clé privée, à protégernginx.crt: certificat
Créer /opt/nginx/conf.d/ssl.conf :
server {
listen 443 ssl;
server_name localhost;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
- Chemins SSL = chemins dans le conteneur (
/etc/nginx/ssl) - TLS 1.2/1.3 uniquement
-p 443:443obligatoire
Rechargement :
docker exec my-nginx nginx -s reload
https://localhost : avertissement navigateur normal pour l’auto-signé.
Let’s Encrypt : certificats gratuits en production
Gratuit, automatisé, reconnu mondialement. Validité 90 jours — renouvellement auto et c’est réglé.
Recommandation : docker-compose + conteneur certbot.
docker-compose.yml :
version: '3'
services:
nginx:
image: nginx:latest
container_name: my-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/html:/usr/share/nginx/html
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
networks:
- web
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./certbot/conf:/etc/letsencrypt
- ./certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
networks:
- web
networks:
web:
driver: bridge
1. Volumes partagés
./certbot/conf: génération (certbot) et lecture (nginx)./certbot/www: validation HTTP webroot
2. Reload Nginx toutes les 6 h
Boucle en arrière-plan pour prendre en compte les certs renouvelés.
3. Certbot toutes les 12 h
Plus prudent qu’une fois par jour.
Première demande de certificat
temp.conf dans /opt/nginx/conf.d/ pour la validation HTTP :
server {
listen 80;
server_name your-domain.com; # Votre domaine
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
docker-compose up -d
Demande (adapter domaine et e-mail) :
docker-compose run --rm certbot certonly --webroot \
-w /var/www/certbot \
-d your-domain.com \
--email [email protected] \
--agree-tos \
--no-eff-email
Succès → « Congratulations! ». Certs dans ./certbot/conf/live/your-domain.com/.
Config HTTPS définitive :
server {
listen 80;
server_name your-domain.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
docker-compose exec nginx nginx -s reload
Vérifier le renouvellement automatique
docker-compose run --rm certbot renew --dry-run
« The dry run was successful » — OK.
docker-compose logs certbot
Renforts sécurité SSL
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/your-domain.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
Test sur SSL Labs — note A+ accessible.
Reverse proxy et communication entre conteneurs
Réseaux Docker
Proxy vers d’autres conteneurs : l’IP du conteneur change au restart — config à refaire.
Modes courants :
- bridge : défaut, communication via pont virtuel
- host : pile réseau de l’hôte, performance mais moins d’isolation
Pour Nginx en reverse proxy : réseau bridge personnalisé recommandé.
- Communication par nom de service, pas par IP
- Isolation par projet
- DNS intégré Docker
Créer le réseau et lancer les conteneurs
docker network create my-app-network
Backend (ex. API Node.js) :
docker run -d \
--name backend-api \
--network my-app-network \
-e NODE_ENV=production \
my-backend:latest
Nginx sur le même réseau :
docker run -d \
--name my-nginx \
--network my-app-network \
-p 80:80 -p 443:443 \
-v /opt/nginx/conf.d:/etc/nginx/conf.d \
nginx
Dans la config Nginx : backend-api comme hostname.
Configuration reverse proxy
api-proxy.conf dans /opt/nginx/conf.d/ :
upstream backend {
server backend-api:3000;
keepalive 32;
}
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://backend/;
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;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
}
}
1. upstream et proxy_pass
proxy_pass http://backend/; (slash final) : /api/users → http://backend/users.
Sans slash : chemin complet conservé.
2. X-Forwarded-For
IP client réelle pour le backend.
3. keepalive
Réutilisation TCP, utile en charge.
docker-compose pour plusieurs services
version: '3.8'
services:
backend:
image: my-backend:latest
container_name: backend-api
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://db:5432/mydb
networks:
- app-network
depends_on:
- db
nginx:
image: nginx:latest
container_name: my-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/html:/usr/share/nginx/html
- ./nginx/logs:/var/log/nginx
networks:
- app-network
depends_on:
- backend
db:
image: postgres:14
container_name: postgres-db
environment:
- POSTGRES_PASSWORD=secret
- POSTGRES_DB=mydb
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-network
networks:
app-network:
driver: bridge
volumes:
db-data:
docker-compose up -d
Réseau app-network, ordre depends_on, DNS : utilisez backend et db dans nginx.conf.
Dépannage du proxy
502 Bad Gateway
Causes : backend arrêté, réseaux différents, mauvais port.
docker ps | grep backend
docker network inspect my-app-network
docker exec -it my-nginx sh
ping backend-api
curl http://backend-api:3000/health
Timeouts
Augmenter pour APIs longues :
location /api/long-running/ {
proxy_pass http://backend/;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
Corps POST perdu
location /api/ {
proxy_pass http://backend/;
proxy_request_buffering off;
client_max_body_size 100M;
}
Équilibrage de charge
upstream backend_cluster {
least_conn;
server backend-1:3000 weight=3;
server backend-2:3000 weight=1;
server backend-3:3000 backup;
keepalive 32;
}
server {
listen 80;
location /api/ {
proxy_pass http://backend_cluster/;
}
}
Algorithmes : round-robin (défaut), least_conn, ip_hash. Nœud down → trafic vers les instances saines.
Bonnes pratiques production et performance
Gestion des configurations
Git
Dépôt dédié aux configs Nginx, dossiers par environnement : historique, rollback git checkout, revue en PR, CI/CD.
Templates
envsubst au déploiement pour variables par environnement.
Journaux
Trafic élevé : plusieurs Go par jour. Sans rotation, disque plein → conteneur down.
logrotate sur l’hôte, conservation 14 jours, compression ; après rotation nginx -s reopen.
Centralisation : ELK, Loki, cloud — driver Docker ou Promtail.
Rechargement gracieux
Évitez docker restart après changement de config — connexions coupées.
docker exec my-nginx nginx -t
docker exec my-nginx nginx -s reload
reload : nouveaux workers avec la nouvelle config, anciens finissent les requêtes en cours.
Checklist sécurité
1. Masquer la version Nginx
server_tokens off; dans le bloc http.
2. Limitation de débit
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
}
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
limit_conn conn_limit 10;
proxy_pass http://backend/;
}
}
3. Montage :ro sur la config principale.
4. Utilisateur nginx
user nginx; — pas root.
Tuning performance
Workers
worker_processes auto;
worker_cpu_affinity auto;
Connexions
events {
worker_connections 2048;
use epoll;
}
Concurrence max ≈ worker_processes * worker_connections ; vérifier ulimit -n.
gzip
http {
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types
text/plain
text/css
text/xml
application/json
application/javascript
application/xml+rss
application/atom+xml
image/svg+xml;
gzip_min_length 1000;
}
Cache statiques
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
HTTP/2
server {
listen 443 ssl http2;
}
Nécessite HTTPS (HTTP/2 sur TLS).
Monitoring
Prometheus + Grafana + nginx-prometheus-exporter ; stub_status limité au réseau interne Docker.
Conclusion
En résumé :
Montage : répertoire plutôt que fichier unique, :ro sur la config principale, conf.d et ssl, piège inode vim.
HTTPS : auto-signé en dev, Let’s Encrypt + Certbot en prod ; docker-compose simplifie le renouvellement.
Reverse proxy : réseau bridge personnalisé, noms de conteneurs, keepalive dans upstream.
Production : Git pour les configs, rotation des logs, reload pas restart, sécurité et limites.
Docker Nginx paraît simple ; les détails comptent. Maîtrisés, vous obtenez une architecture Web fiable du développement à la production.
Conservez les modèles de cet article pour les réutiliser — pas besoin de tout refaire à chaque projet.
Déploiement Docker Nginx de bout en bout
Montage des configs, HTTPS et reverse proxy — résoudre configs ignorées et interconnexion des conteneurs
⏱️ Estimated time: 1 hr
- 1
Step 1: Montage des fichiers de config : 5 bonnes pratiques
5 montages corrects :
• Fichier principal : -v ./nginx.conf:/etc/nginx/nginx.conf
• Répertoire conf.d : -v ./conf.d:/etc/nginx/conf.d
• Volume Docker
• docker-compose
• ConfigMap (environnement K8s)
Problèmes courants :
• Config modifiée sans effet dans le conteneur
• Utiliser -v sur le bon répertoire
• Vérifier le format des fichiers
Bonnes pratiques :
• Préférer le montage de répertoire au fichier unique
• Config principale en lecture seule
• Ne pas oublier conf.d et ssl
• Éviter le piège inode de vim - 2
Step 2: HTTPS et renouvellement automatique Let's Encrypt
HTTPS :
• Certificats gratuits Let's Encrypt
• Renouvellement auto : certbot renew
• Montage des certs : -v ./certs:/etc/nginx/certs
• Chemins SSL dans nginx.conf
• HTTP/2 et TLS 1.3
Let's Encrypt :
• Obtenir : certbot certonly --standalone
• Test renouvellement : certbot renew --dry-run
• Montage : -v ./letsencrypt:/etc/letsencrypt
• Référencer les certs dans nginx.conf - 3
Step 3: Reverse proxy et bonnes pratiques de production
Reverse proxy :
• upstream vers les conteneurs backend
• Nom de conteneur ou de service : proxy_pass http://backend:8080
• Health checks
• CORS
• Équilibrage de charge
Production :
• docker-compose pour plusieurs conteneurs
• Health checks
• Limites de ressources
• Rotation des logs
• Variables d'environnement
• Mises à jour régulières des images
Maîtriser ces détails permet une architecture Web fiable du dev à la prod.
FAQ
Pourquoi la configuration Docker Nginx ne s'applique-t-elle pas après modification ?
5 montages corrects :
1) -v ./nginx.conf:/etc/nginx/nginx.conf
2) -v ./conf.d:/etc/nginx/conf.d
3) Volume Docker
4) docker-compose
5) ConfigMap (K8s)
Bonnes pratiques :
• Répertoire plutôt que fichier unique
• Config principale en :ro
• Inclure conf.d et ssl
• Éviter le piège inode de vim
Comment configurer HTTPS pour Docker Nginx ?
• Let's Encrypt gratuit
• Renouvellement : certbot renew
• -v ./certs:/etc/nginx/certs
• Chemins SSL
• HTTP/2 et TLS 1.3
Let's Encrypt :
• certbot certonly --standalone
• certbot renew --dry-run
• -v ./letsencrypt:/etc/letsencrypt
• nginx.conf pointant vers les certs
Comment configurer le reverse proxy Docker Nginx ?
• upstream vers le backend
• proxy_pass http://backend:8080 (nom de service)
• Health checks
• CORS
• Load balancing
Réseau :
• Réseau bridge personnalisé via docker-compose
• Conteneurs sur le même réseau
• Accès par nom de service
• upstream vers le backend
Quelles sont les bonnes pratiques Docker Nginx en production ?
• docker-compose multi-conteneurs
• Health checks
• Limites de ressources
• Rotation des logs
• Variables d'environnement
• Images à jour
Conseil : conservez les modèles de config de cet article pour les réutiliser.
8 min de lecture · Publié le: 18 déc. 2025 · Mis à jour le: 27 juil. 2026
Guide pratique Docker
Si vous arrivez depuis la recherche, le plus rapide est de passer à l’article précédent ou suivant de cette série.
Précédent
Guide complet Docker MySQL : persistance et réplication maître-esclave
De la persistance des données Docker MySQL à la réplication maître-esclave : résoudre la perte de données au redémarrage, le montage de configuration et les échecs de connexion avec un déploiement prêt pour la production.
Partie 27 sur 38
Suivant
Analyse de sécurité et correction des images Docker : tutoriel Trivy et intégration CI/CD
76 % des images sur Docker Hub présentent des vulnérabilités. Ce guide détaille Trivy, les méthodes de correction systématique et l'intégration CI/CD automatisée, avec des exemples de commandes complets.
Partie 29 sur 38



Commentaires
Connectez-vous avec GitHub pour laisser un commentaire