Aller au contenu

Nginx : reverse proxy

Un reverse proxy reçoit les requêtes des visiteurs et les transmet à une application qui écoute sur un port local. Il gère aussi HTTPS, la compression et la sécurité. Les exemples utilisent une application fictive sur 127.0.0.1:3000.

server {
listen 80;
server_name app.exemple.com;
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;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
En-tête Rôle
Host Nom d’hôte demandé par le visiteur (sans lui, l’application voit 127.0.0.1:3000)
X-Real-IP Adresse du visiteur
X-Forwarded-For Liste des adresses traversées
X-Forwarded-Proto http ou https (pour que l’application génère les bons liens)

Pour réutiliser ces lignes, les placer dans un fragment :

Fenêtre de terminal
sudo tee /etc/nginx/snippets/proxy-headers.conf <<'CONF'
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;
CONF
location / {
proxy_pass http://127.0.0.1:3000;
include snippets/proxy-headers.conf;
}
Écriture Requête /api/utilisateurs transmise comme
location /api/ { proxy_pass http://127.0.0.1:4000; } /api/utilisateurs (le chemin est conservé)
location /api/ { proxy_pass http://127.0.0.1:4000/; } /utilisateurs (le préfixe /api/ est retiré)
location /api/ {
proxy_pass http://127.0.0.1:4000/; # retire /api/
include snippets/proxy-headers.conf;
}

Avec une adresse seule (sans chemin), le chemin d’origine est conservé ; avec un chemin, même /, la partie du location est remplacée.

map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
# …
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
include snippets/proxy-headers.conf;
proxy_read_timeout 3600s; # connexions longues
}
}

Le bloc map se place dans le contexte http (par exemple dans un fichier de /etc/nginx/conf.d/).

location /evenements {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_buffering off; # transmet immédiatement les données
proxy_read_timeout 1h;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_connect_timeout 5s; # établissement de la connexion à l'application
proxy_send_timeout 60s;
proxy_read_timeout 60s; # attente de la réponse
client_max_body_size 20m; # taille maximale des envois (défaut : 1m)
}
upstream application {
least_conn; # vers le serveur le moins chargé (défaut : tourniquet)
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3002 backup; # utilisé seulement si les autres sont en échec
keepalive 16; # connexions réutilisées vers l'application
}
server {
location / {
proxy_pass http://application;
proxy_http_version 1.1;
proxy_set_header Connection ''; # nécessaire pour keepalive
include snippets/proxy-headers.conf;
}
}
Méthode Comportement
(défaut) Tourniquet (round-robin)
least_conn Serveur ayant le moins de connexions actives
ip_hash Un visiteur reste sur le même serveur (sessions)

max_fails et fail_timeout retirent temporairement un serveur qui échoue (contrôle de santé passif).

# Contexte http
proxy_cache_path /var/cache/nginx/app levels=1:2 keys_zone=app:10m max_size=1g inactive=60m;
server {
location /api/public/ {
proxy_pass http://127.0.0.1:3000;
proxy_cache app;
proxy_cache_valid 200 5m;
add_header X-Cache-Status $upstream_cache_status always;
}
}

Adresse réelle du visiteur derrière un autre proxy

Section intitulée « Adresse réelle du visiteur derrière un autre proxy »

Si Nginx est lui-même derrière un répartiteur de charge ou un CDN :

set_real_ip_from 10.0.0.0/8; # adresses des proxys de confiance
real_ip_header X-Forwarded-For;
real_ip_recursive on;
Fenêtre de terminal
curl -I http://app.exemple.com/
curl -H "Host: app.exemple.com" http://127.0.0.1/
curl -i -H "Upgrade: websocket" -H "Connection: Upgrade" http://127.0.0.1/ws/
sudo tail -f /var/log/nginx/error.log
Symptôme Piste
502 Bad Gateway L’application est arrêtée, mal écoute, ou mauvais port : curl http://127.0.0.1:3000 ; sudo ss -tlnp
504 Gateway Timeout L’application est trop lente : augmenter proxy_read_timeout, ou corriger l’application
413 Request Entity Too Large Augmenter client_max_body_size
Liens générés en http:// au lieu de https:// Transmettre X-Forwarded-Proto et configurer l’application pour le lire
WebSocket qui se coupe Upgrade/Connection, proxy_http_version 1.1, et proxy_read_timeout assez long
Chemin transmis incorrect Barre oblique finale de proxy_pass (voir plus haut)
connect() failed (13: Permission denied) SELinux/AppArmor ou application en écoute sur un autre utilisateur ; vérifier le port et l’adresse