Changer le thème

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

Easton editorial illustration: fault-isolation scanner

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)
  • :ro sur 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éger
  • nginx.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:443 obligatoire

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é.

  1. Communication par nom de service, pas par IP
  2. Isolation par projet
  3. 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/usershttp://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. 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. 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. 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 ?
Cause fréquente : montage incorrect. Utilisez -v sur le répertoire de configuration et vérifiez le format.

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 ?
HTTPS :
• 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 ?
Reverse proxy :
• 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 ?
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

Commentaires

Connectez-vous avec GitHub pour laisser un commentaire

Easton BlogEaston Blog