NGINX reverse proxy : exposer plusieurs services
NGINX reverse proxy pour plusieurs services : chemins proxy_pass, en-têtes fiables, WebSocket, frontière TLS et diagnostic avant rechargement.
Serveurs dédiés, infogérance et migration
Il couvre les serveurs dédiés, l'infogérance, le stockage, la supervision et les plans de sortie.
Un reverse proxy NGINX reçoit les requêtes HTTPS, choisit le service cible selon le nom d’hôte ou le chemin, puis renvoie sa réponse au client. Une configuration fiable doit préserver les URI, transmettre seulement les en-têtes utiles, traiter WebSocket explicitement et définir clairement où le TLS se termine.
Le bloc minimal trouvé dans un exemple fonctionne rarement comme contrat universel. Une barre oblique change le chemin envoyé. Un en-tête transmis sans frontière de confiance peut fausser l’adresse cliente. Un tunnel WebSocket exige un changement de protocole explicite. Et un cadenas côté navigateur ne dit rien du segment entre NGINX et l’application.
Ce guide part de deux services HTTP déjà fonctionnels sur la machine. Il montre des choix, pas un fichier à coller sans lecture. Testez chaque application directement, identifiez le chemin qu’elle attend et sachez qui peut joindre son port avant d’ajouter NGINX.
Le proxy inverse est une frontière, pas un simple relais
NGINX devient le point d’entrée public. Il reçoit la connexion, sélectionne un bloc server selon le nom demandé, choisit ensuite une location selon l’URI et transmet la requête à l’upstream configuré. Chaque étape peut modifier le comportement ; il faut donc écrire son intention avant les directives.
Relevez ces éléments pour chaque service :
- nom public : domaine ou sous-domaine présenté au navigateur ;
- adresse interne : socket, adresse loopback ou nom résolu sur un réseau privé ;
- racine attendue : l’application sert-elle sous / ou sous un préfixe ;
- protocole : HTTP classique, WebSocket, flux long ou téléchargement volumineux ;
- identité cliente : quels en-têtes l’application sait lire et quelles sources elle doit croire ;
- frontière TLS : terminaison dans NGINX ou chiffrement maintenu jusqu’à l’upstream ;
- signal de panne : journal, page de santé et procédure de retour arrière.
Un proxy inverse concentre aussi le risque. Une erreur de routage touche plusieurs applications ; une clé privée mal protégée touche tous les noms qu’elle couvre. Avant de mutualiser l’entrée, écrivez la panne la plus plausible et son chemin de retour.
Choisir le routage par domaine ou par chemin
Deux modèles dominent. Le routage par nom donne un sous-domaine à chaque application. Le routage par chemin place plusieurs applications derrière le même domaine. Le premier respecte généralement mieux les URL natives ; le second exige de connaître précisément les préfixes, redirections et chemins absolus produits par chaque logiciel.
| Modèle | Exemple public | Avantage | Piège principal |
|---|---|---|---|
| Nom d’hôte | site.example.fr | URI inchangée, séparation nette | DNS et certificat pour chaque nom |
| Nom d’hôte | api.example.fr | Politique distincte par service | Origines et cookies à vérifier |
| Préfixe | example.fr/app/ | Un seul domaine visible | Réécriture des chemins et des redirections |
| Préfixe | example.fr/api/ | Frontière facile à annoncer | Application parfois incapable de vivre sous un préfixe |
Préférez le nom d’hôte lorsque l’application suppose être à la racine. Choisissez un préfixe seulement si elle accepte un chemin de base configurable ou si vous avez vérifié ses URL, cookies, redirections et ressources statiques. NGINX peut réécrire une URI ; il ne répare pas une application qui fabrique partout des liens absolus incohérents.
Construire une base par noms d’hôte
L’extrait suivant appartient au contexte http de NGINX. Les upstreams écoutent uniquement sur l’adresse loopback de l’hôte. Le certificat présenté doit couvrir les deux noms, ou chaque bloc doit recevoir son propre certificat. Les chemins sont des exemples : adaptez-les à votre installation et à votre mécanisme de renouvellement.
upstream service_web {
server 127.0.0.1:9000;
}
upstream service_api {
server 127.0.0.1:9100;
}
server {
listen 80;
server_name site.example.fr api.example.fr;
return 308 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name site.example.fr;
ssl_certificate /etc/nginx/tls/example-fullchain.pem;
ssl_certificate_key /etc/nginx/tls/example-privkey.pem;
location / {
proxy_pass http://service_web;
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;
}
}
server {
listen 443 ssl;
server_name api.example.fr;
ssl_certificate /etc/nginx/tls/example-fullchain.pem;
ssl_certificate_key /etc/nginx/tls/example-privkey.pem;
location / {
proxy_pass http://service_api;
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;
}
}
Les ports applicatifs ne doivent pas être publics si seul NGINX les utilise. Sur un VPS, liez-les à loopback ou au réseau privé approprié, puis contrôlez l’écoute réelle avec les outils du système. Le pare-feu complète cette limite ; il ne corrige pas une application liée par erreur à toutes les interfaces.
La clé privée mérite son propre contrôle. NGINX doit pouvoir la lire au démarrage, mais elle ne doit pas devenir lisible par tous les comptes de la machine. Vérifiez aussi que le fichier de certificat contient la chaîne attendue. Un fichier présent n’est pas nécessairement une chaîne correcte.
Comprendre la barre oblique de proxy_pass
La forme de proxy_pass décide si NGINX conserve ou remplace la partie de l’URI qui correspond à location. Cette différence explique une grande part des erreurs où l’upstream reçoit un chemin doublé, amputé ou inattendu.
location /app/ {
proxy_pass http://service_web;
}
Avec cette forme sans URI ajoutée à proxy_pass, la requête /app/doc est transmise avec ce chemin complet. L’application doit donc connaître le préfixe /app/.
location /app/ {
proxy_pass http://service_web/;
}
Ici, la barre oblique constitue une URI. NGINX remplace le préfixe correspondant à location : la même requête arrive à l’upstream sous /doc. Ce comportement est utile quand le public voit /app/ mais que l’application sert à la racine.
| location | proxy_pass | URI publique | URI envoyée |
|---|---|---|---|
| /app/ | Upstream sans URI | /app/doc | /app/doc |
| /app/ | Upstream avec / | /app/doc | /doc |
Écrivez un test avec une URI réelle avant le rechargement. Les locations régulières, les réécritures et les variables ajoutent d’autres règles ; n’étendez pas ce tableau à ces cas sans relire la documentation de la directive.
Transmettre les en-têtes sans inventer la confiance
NGINX redéfinit certains en-têtes lorsqu’il transmet une requête. Les quatre lignes de l’exemple rendent le contrat explicite : nom public, adresse du pair direct, chaîne d’adresses et protocole reçu par NGINX.
X-Forwarded-For n’est pas une preuve d’identité. La variable qui ajoute l’adresse cliente conserve aussi une éventuelle chaîne reçue. L’application doit faire confiance à NGINX, pas à n’importe quel client capable d’envoyer son propre en-tête. Si un CDN ou un autre proxy précède NGINX, définissez précisément quelles adresses intermédiaires sont fiables.
Le protocole transmis influence souvent les redirections et les cookies sécurisés. Si l’application croit recevoir HTTP alors que le navigateur utilisait HTTPS, elle peut produire une boucle de redirection ou une URL incorrecte. L’application doit toutefois être configurée pour croire X-Forwarded-Proto uniquement lorsqu’il vient de votre proxy.
Le choix de Host dépend du besoin de l’application. La variable $host garde le nom public sélectionné par NGINX. Laisser la valeur par défaut expose plutôt le nom de l’upstream. Ne recopiez pas un en-tête par habitude : documentez le consommateur et la conséquence.
Traiter WebSocket comme un changement de protocole
WebSocket commence par HTTP puis demande un changement de protocole. Les en-têtes Upgrade et Connection sont hop-by-hop ; NGINX ne les transmet pas automatiquement. Le modèle officiel utilise map pour envoyer upgrade seulement lorsqu’un client a réellement demandé ce changement.
Placez map dans le contexte http, puis limitez les en-têtes au chemin WebSocket :
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name api.example.fr;
location /socket/ {
proxy_pass http://service_api;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Cette forme conserve le préfixe /socket/ parce que proxy_pass ne contient pas d’URI. Si l’upstream attend la racine, ajoutez une URI et vérifiez le chemin obtenu. Le timeout dépend de l’application : préférez des messages de maintien en vie utiles et une valeur justifiée plutôt qu’un délai énorme copié au hasard.
Dessiner la frontière TLS
Terminer TLS dans NGINX signifie que le navigateur chiffre jusqu’au proxy. Le segment suivant est une décision séparée. Un upstream en loopback sur un hôte maîtrisé peut utiliser HTTP selon votre modèle de menace. Un service distant, un réseau partagé ou une exigence de chiffrement de bout en bout justifie HTTPS avec vérification du certificat upstream.
La frontière TLS se trouve dans NGINX : le segment suivant dépend du niveau de confiance du réseau interne, pas d’une règle universelle.

Pour un upstream HTTPS signé par une autorité interne, configurez la confiance et activez la vérification. Mettre seulement https dans proxy_pass chiffre la liaison, mais ne définit pas à lui seul quelle identité doit être acceptée.
location / {
proxy_pass https://service_api_tls;
proxy_ssl_server_name on;
proxy_ssl_name api.internal.example;
proxy_ssl_trusted_certificate /etc/nginx/ca/internal-ca.pem;
proxy_ssl_verify on;
}
Le nom vérifié, la chaîne de confiance et la résolution de l’upstream doivent correspondre. Si vous ne contrôlez pas ces trois éléments, vous avez déplacé le problème derrière le proxy.
Valider et diagnostiquer par couches
Ne rechargez jamais avant le test de configuration. La commande de test vérifie la syntaxe et tente d’ouvrir les fichiers référencés, notamment les certificats. La variante qui affiche toute la configuration résolue aide à repérer une directive héritée ou un fichier inclus inattendu ; protégez sa sortie si elle contient des informations sensibles.
nginx -t
nginx -T
Ensuite, testez de l’intérieur vers l’extérieur :
curl -v http://127.0.0.1:9000/
curl -v http://127.0.0.1:9100/
curl --resolve site.example.fr:443:127.0.0.1 https://site.example.fr/
curl --resolve api.example.fr:443:127.0.0.1 https://api.example.fr/
Le certificat doit couvrir le nom utilisé par curl. Ne désactivez pas sa vérification pour faire disparaître une erreur : vous masqueriez précisément la frontière que vous cherchez à valider.
| Symptôme | Couche probable | Vérification suivante |
|---|---|---|
| Refus de connexion upstream | Processus ou adresse interne | Écoute réelle et journal applicatif |
| Réponse 502 | Connexion ou réponse upstream invalide | error_log et test direct de l’upstream |
| Réponse 504 | Upstream silencieux jusqu’au délai | Temps de connexion et de réponse |
| Boucle de redirection | Host ou protocole public mal interprété | En-têtes reçus par l’application |
| WebSocket fermé au démarrage | Upgrade ou Connection absent | map, location et journal upstream |
| Mauvais chemin | Contrat proxy_pass incohérent | URI publique contre URI reçue |
Les journaux d’accès disent quelle requête est sortie de NGINX. Le journal d’erreur explique souvent pourquoi la connexion upstream a échoué. Ajoutez temporairement les temps de connexion et de réponse upstream au format d’accès pour distinguer une attente réseau d’une application lente.
Après un test vert, rechargez proprement puis répétez les requêtes externes. Gardez la configuration précédente disponible pour un retour rapide. Le retour arrière appartient au coût d’exploitation, même lorsqu’il ne concerne que deux noms de domaine.
Quand choisir ou éviter cette architecture
| Situation | Reverse proxy NGINX | Réserve à traiter |
|---|---|---|
| Plusieurs services sur un hôte | Adapté | Ports internes, journaux et sauvegarde de configuration |
| Plusieurs domaines sur une adresse publique | Adapté | DNS, certificats et isolation des virtual hosts |
| Application compatible avec un préfixe | Possible | URI, cookies, redirections et ressources statiques |
| Réseau upstream non fiable | Possible | HTTPS upstream avec identité vérifiée |
| Découverte dynamique complexe de services | Limité seul | Outil d’orchestration ou registre adapté |
| Haute disponibilité de la passerelle exigée | Insuffisant seul | Deuxième entrée, état, DNS ou bascule supervisée |
Liste de contrôle
- Vérifiez chaque upstream directement et bloquez tout port applicatif exposé au-delà du réseau prévu.
- Testez une URI réelle par location afin de confirmer le chemin exact produit par proxy_pass.
- Définissez les proxies de confiance avant d’utiliser les en-têtes forwarded pour l’adresse cliente ou le protocole public.
- Validez syntaxe, certificats, WebSocket et retour arrière avant chaque rechargement de la passerelle.
Questions fréquentes
Faut-il une barre oblique après l’upstream dans proxy_pass ?
Dois-je transmettre X-Forwarded-For ?
Pourquoi WebSocket échoue-t-il alors que HTTP fonctionne ?
Le trafic entre NGINX et l’application doit-il utiliser HTTPS ?
Préparé par
Serveurs dédiés, infogérance et migration
Il couvre les serveurs dédiés, l'infogérance, le stockage, la supervision et les plans de sortie.
Faits vérifiés
HostScout editorialArticles liés
Clés SSH : l’authentification sans mot de passe
Créer une clé SSH Ed25519, installer la clé publique, vérifier l’hôte et désactiver le mot de passe sans perdre l’accès.
Installer Zabbix pour superviser ses serveurs
Installer Zabbix 7.0 LTS sur Ubuntu 24.04 avec PostgreSQL, Nginx et Agent 2, puis sécuriser et valider chaque composant.
MySQL : créer un utilisateur et gérer les droits
Créer un utilisateur MySQL 8.4, limiter son hôte, attribuer puis retirer des droits, imposer TLS et contrôler le résultat.
Docker Compose : guide multi-conteneurs
Docker Compose orchestre plusieurs conteneurs avec un fichier lisible : services, réseau, volumes, secrets, santé et diagnostic sans perte de données.
Installer Docker sur Ubuntu et Debian
Installer Docker sur Ubuntu et Debian via le dépôt officiel, vérifier Engine et Compose, puis sécuriser les droits et les ports publiés.
Adresse IP publique ou privée : la repérer
Adresse IP publique ou privée : comprenez ce qui vous identifie en ligne, où trouver chaque adresse et quoi vérifier avant d'exposer un serveur.