Configurer un reverse proxy avec Nginx ou Traefik
Guide complet pour configurer un reverse proxy : Nginx vs Traefik, HTTPS avec Let's Encrypt, load balancing, exemples pratiques pour héberger plusieurs applications.
Sommaire
- Introduction
- Qu’est-ce qu’un reverse proxy ?
- Nginx vs Traefik : lequel choisir ?
- Configuration avec Nginx
- Configuration avec Traefik
- Sécurité et optimisations
- Troubleshooting
- FAQ
Introduction
Vous développez plusieurs applications et vous voulez les héberger sur le même serveur ? Vous en avez marre de retenir les ports 3000, 8080, 4000 ? Un reverse proxy est la solution !
Dans ce guide, nous allons voir comment configurer Nginx ou Traefik pour héberger plusieurs services derrière un seul domaine, avec HTTPS automatique et une configuration propre.
Qu’est-ce qu’un reverse proxy ?
Le principe de base
Un reverse proxy agit comme un intermédiaire entre vos utilisateurs et vos applications :
Utilisateur → Internet → Reverse Proxy → Applications
↓
monsite.com
↓
App1:3000 App2:4000 API:8080
Différence avec un proxy classique
Proxy classique (forward proxy) :
Client → Proxy → Internet → Serveur
(cache, anonymat, filtrage)
Reverse proxy :
Client → Internet → Reverse Proxy → Serveurs internes
(load balancing, SSL termination, routing)
Cas d’usage courants
1. Hébergement multi-applications :
blog.monsite.com → App blog (port 3000)
api.monsite.com → API REST (port 8080)
app.monsite.com → SPA React (port 4000)
2. Load balancing :
monsite.com → [Serveur 1, Serveur 2, Serveur 3]
3. SSL Termination :
HTTPS → Reverse Proxy → HTTP (interne)
Nginx vs Traefik : lequel choisir ?
| Critère | Nginx | Traefik |
|---|---|---|
| Complexité | Configuration manuelle | Auto-découverte |
| Performance | Excellent | Très bon |
| HTTPS | Certbot requis | Let’s Encrypt intégré |
| Docker | Config externe | Labels sur conteneurs |
| Monitoring | Modules tiers | Dashboard intégré |
| Flexibilité | Maximum | Bonne |
| Courbe d’apprentissage | Raide | Douce |
Choisir Nginx si :
- Performance critique
- Configuration très spécifique
- équipe expérimentée
- Infrastructure statique
Choisir Traefik si :
- Environnement Docker
- Configuration dynamique
- HTTPS automatique important
- équipe débutante
Configuration avec Nginx
Installation et setup de base
Sur Ubuntu/Debian :
# Installation
sudo apt update
sudo apt install nginx
# Démarrage et activation
sudo systemctl start nginx
sudo systemctl enable nginx
# Vérification
sudo nginx -t
curl http://localhost
Structure des fichiers :
/etc/nginx/
nginx.conf # Configuration principale
sites-available/ # Configurations de sites
default
monsite.com
sites-enabled/ # Liens symboliques actifs
conf.d/ # Configurations modulaires
Configuration multi-services
Scénario : 3 applications sur le même serveur
- Frontend React (port 3000)
- API Node.js (port 8080)
- Admin Panel (port 4000)
Configuration /etc/nginx/sites-available/monsite.com :
server {
listen 80;
server_name monsite.com www.monsite.com;
# Logs
access_log /var/log/nginx/monsite_access.log;
error_log /var/log/nginx/monsite_error.log;
# Frontend principal
location / {
proxy_pass http://localhost:3000;
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;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
# API
location /api/ {
proxy_pass http://localhost:8080/;
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;
# Headers CORS si nécessaire
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Authorization, Content-Type";
# Gestion preflight OPTIONS
if ($request_method = OPTIONS) {
return 204;
}
}
# Panel admin
location /admin/ {
proxy_pass http://localhost:4000/;
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;
# Protection basique
# auth_basic "Zone Restreinte";
# auth_basic_user_file /etc/nginx/.htpasswd;
}
# Assets statiques avec cache
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
expires 1M;
add_header Cache-Control "public, immutable";
}
# Gestion des erreurs
error_page 502 503 504 /50x.html;
location = /50x.html {
root /var/www/html;
}
}
Activation du site :
# Créer le lien symbolique
sudo ln -s /etc/nginx/sites-available/monsite.com /etc/nginx/sites-enabled/
# Tester la configuration
sudo nginx -t
# Recharger Nginx
sudo systemctl reload nginx
HTTPS avec Let’s Encrypt
Installation de Certbot :
sudo apt install certbot python3-certbot-nginx
Obtenir et configurer le certificat :
# Obtenir le certificat SSL
sudo certbot --nginx -d monsite.com -d www.monsite.com
# Renouvellement automatique
sudo crontab -e
# Ajouter :
0 12 * * * /usr/bin/certbot renew --quiet
Configuration HTTPS générée par Certbot :
server {
listen 443 ssl http2;
server_name monsite.com www.monsite.com;
ssl_certificate /etc/letsencrypt/live/monsite.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/monsite.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Configuration proxy identique...
}
# Redirection HTTP → HTTPS
server {
listen 80;
server_name monsite.com www.monsite.com;
return 301 https://$server_name$request_uri;
}
Load balancing
Configuration upstream :
# Définir le groupe de serveurs
upstream app_backend {
# Stratégies de répartition
# ip_hash; # Session sticky
# least_conn; # Moins de connexions
# random; # Aléatoire
server localhost:3000 weight=3 max_fails=3 fail_timeout=30s;
server localhost:3001 weight=2 max_fails=3 fail_timeout=30s;
server localhost:3002 weight=1 backup; # Serveur de secours
}
server {
listen 443 ssl http2;
server_name monsite.com;
location / {
proxy_pass http://app_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;
# Health check
proxy_next_upstream error timeout http_500 http_502 http_503;
proxy_connect_timeout 5s;
proxy_send_timeout 10s;
proxy_read_timeout 10s;
}
}
Configuration avec Traefik
Installation Docker
Structure des fichiers :
traefik/
docker-compose.yml
traefik.yml
acme.json
docker-compose.yml :
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080" # Dashboard (à sécuriser en prod)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
networks:
- proxy
labels:
# Dashboard
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.monsite.com`)"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.service=api@internal"
# Protection dashboard
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$..."
- "traefik.http.routers.dashboard.middlewares=auth"
# Application exemple
frontend:
image: node:18-alpine
container_name: frontend
working_dir: /app
volumes:
- ./frontend:/app
command: npm start
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`monsite.com`, `www.monsite.com`)"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
- "traefik.http.services.frontend.loadbalancer.server.port=3000"
api:
image: node:18-alpine
container_name: api
working_dir: /app
volumes:
- ./api:/app
command: npm start
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.monsite.com`)"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.services.api.loadbalancer.server.port=8080"
networks:
proxy:
external: true
Configuration automatique
traefik.yml :
# Points d'entrée
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
# Providers
providers:
docker:
watch: true
exposedByDefault: false
network: proxy
# Let's Encrypt automatique
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
# API et Dashboard
api:
dashboard: true
insecure: false # HTTPS uniquement
# Logs
log:
level: INFO
accessLog: {}
# Métriques (optionnel)
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
HTTPS automatique
Préparation du fichier acme.json :
# Créer le fichier avec les bonnes permissions
touch acme.json
chmod 600 acme.json
Traefik s’occupe automatiquement :
- Demande des certificats Let’s Encrypt
- Renouvellement automatique
- Redirection HTTP → HTTPS
- HSTS headers
Dashboard et monitoring
Accès sécurisé au dashboard :
# Générer un hash pour le mot de passe
htpasswd -nb admin monmotdepasse
# admin:$2y$10$...
# Ou avec Python
python3 -c "import bcrypt; print(bcrypt.hashpw(b'motdepasse', bcrypt.gensalt()).decode())"
Middleware de sécurité :
# Dans docker-compose.yml ou fichier de config
labels:
- "traefik.http.middlewares.secure-headers.headers.SSLRedirect=true"
- "traefik.http.middlewares.secure-headers.headers.STSSeconds=31536000"
- "traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.secure-headers.headers.browserXSSFilter=true"
Sécurité et optimisations
Sécurité Nginx
Configuration SSL durcie :
# /etc/nginx/conf.d/ssl.conf
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/monsite.com/chain.pem;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# Headers de sécurité
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
Rate limiting :
# Dans http {}
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
# Dans server {}
location /api/ {
limit_req zone=api burst=20 nodelay;
proxy_pass http://localhost:8080/;
}
location /login {
limit_req zone=login burst=3;
proxy_pass http://localhost:3000/login;
}
Optimisations performances
Compression Nginx :
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_proxied expired no-cache no-store private auth;
gzip_types
text/plain
text/css
text/xml
text/javascript
application/x-javascript
application/xml+rss
application/javascript
application/json;
Cache Nginx :
# Définir zone de cache
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m;
# Utiliser le cache
location /api/public/ {
proxy_cache my_cache;
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_pass http://localhost:8080/;
}
Troubleshooting
Problèmes courants Nginx
1. Erreur 502 Bad Gateway
# Vérifier que l'application tourne
curl http://localhost:3000
# Vérifier les logs Nginx
sudo tail -f /var/log/nginx/error.log
# Vérifier la config
sudo nginx -t
2. Certificat SSL invalide
# Vérifier le certificat
sudo certbot certificates
# Renouveler si expiré
sudo certbot renew
# Vérifier la config SSL
openssl s_client -connect monsite.com:443 -servername monsite.com
3. Configuration non prise en compte
# Recharger la config
sudo nginx -s reload
# Ou redémarrer complètement
sudo systemctl restart nginx
Problèmes courants Traefik
1. Service non accessible
# Vérifier les logs Traefik
docker logs traefik
# Vérifier le dashboard
http://traefik.monsite.com
# Vérifier le réseau Docker
docker network ls
docker network inspect proxy
2. Certificat Let’s Encrypt non obtenu
# Vérifier les permissions acme.json
ls -la acme.json # Doit être 600
# Vérifier les logs
docker logs traefik | grep -i certificate
# Vérifier la config ACME
cat traefik.yml | grep -A 10 certificatesResolvers
FAQ
Peut-on utiliser Nginx ET Traefik ensemble ?
Oui, mais c’est généralement inutile. Cas d’usage possible :
- Nginx pour les sites statiques/PHP
- Traefik pour les applications Docker
- Nginx en upstream de Traefik pour la performance
Comment migrer de Nginx vers Traefik ?
Plan de migration :
- Installer Traefik en parallèle (port 8080)
- Migrer service par service
- Basculer le DNS
- Désactiver Nginx
Traefik avec labels équivalents :
# Nginx: location /api/ { proxy_pass http://localhost:8080/; }
labels:
- "traefik.http.routers.api.rule=Host(`monsite.com`) && PathPrefix(`/api/`)"
- "traefik.http.middlewares.api-strip.stripprefix.prefixes=/api"
- "traefik.http.routers.api.middlewares=api-strip"
Comment gérer plusieurs domaines avec Traefik ?
labels:
- "traefik.http.routers.frontend.rule=Host(`monsite.com`, `www.monsite.com`, `monsite.fr`)"
- "traefik.http.routers.frontend.tls.certresolver=letsencrypt"
# Certificat SAN automatique pour tous les domaines
Performance : Nginx vs Traefik ?
Benchmarks typiques :
- Nginx : ~50,000 req/s (statique), ~10,000 req/s (proxy)
- Traefik : ~30,000 req/s (statique), ~8,000 req/s (proxy)
Mais Traefik compense par :
- Configuration zéro
- Auto-discovery
- Métriques intégrées
Comment gérer les WebSockets ?
Nginx :
location /socket.io/ {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
Traefik :
# Traefik gère automatiquement les WebSockets
labels:
- "traefik.enable=true"
- "traefik.http.routers.socketio.rule=Host(`monsite.com`)"
# Aucune config spéciale nécessaire !
Le reverse proxy transforme complètement la façon dont vous hébergez vos applications. Nginx pour la performance maximale, Traefik pour la simplicité : les deux sont excellents selon vos besoins !