Le travail, ce n'est pas « installer nginx »
Presque personne ne veut nginx pour lui-même. Ce que vous voulez, c'est que app.exemple.com atteigne un processus en écoute sur 127.0.0.1:3000, en HTTPS, sans exposer ce processus directement à Internet. Le serveur web est le moyen ; le reverse proxy est le travail. Confondre les deux, c'est finir avec une page d'accueil par défaut en production et un vrai service toujours lié à un port que n'importe qui peut atteindre.
La thèse de cet article est donc étroite : le reverse proxy est une petite configuration bien comprise, et presque toutes ses façons de mal tourner sont des façons de continuer à servir l'ancienne chose en silence. Un proxy cassé ne renvoie que rarement une erreur bruyante. Il sert un bloc server périmé, ou le site par défaut de la distribution, ou un 502 qui ressemble à un crash de votre application alors que nginx ne l'a jamais atteinte. Le travail est dans la vérification, pas dans la frappe.
Avant le premier paquet : lire la machine
Une image cloud neuve est rarement aussi vide qu'elle en a l'air. Quelque chose possède peut-être déjà le port 80 — un Apache issu d'une expérience à moitié terminée, un conteneur qui publie :80, un vieux nginx dont personne ne se souvient. La reconnaissance n'est pas une politesse ; c'est la différence entre installer un service et en percuter un.
- nginx est-il déjà là, et dans quelle version ?
command -v nginx && nginx -v. Si oui, vous configurez, vous n'installez pas — et vous ne devez pas réinstaller par-dessus une config qui marche. - Quelque chose écoute-t-il déjà sur 80 et 443 ?
ss -tlnH 'sport = :80' 'sport = :443'vous dit qui possède les ports avant que vous n'essayiez de vous y lier. Un proxy qui ne peut pas se lier est un proxy qui ne démarre jamais. - Un vhost pour ce domaine existe-t-il déjà ? Un fichier dans
/etc/nginx/sites-enabled/contenant votre domaine est une config que vous êtes sur le point d'écraser. Lisez-la d'abord ; sauvegardez-la avant d'y toucher.
La disposition diffère selon la distribution, et supposer la mauvaise est un grand classique du but contre son camp. Debian et Ubuntu livrent le couple sites-available / sites-enabled avec un lien symbolique entre les deux ; la famille RHEL dépose tout dans /etc/nginx/conf.d/*.conf et n'a pas de sites-enabled du tout. Un runbook qui code en dur un seul chemin échoue sur la moitié du parc. L'étape de reconnaissance, c'est ce qui indique au run dans quel monde il se trouve.
1. Installer, mais seulement si c'est absent
L'installation est l'étape la moins intéressante et celle que l'on sur-analyse. Sur Debian et Ubuntu, c'est apt-get install -y nginx ; dans la famille RHEL, dnf install -y nginx. La seule règle qui compte est celle qu'on saute facilement sous la pression : si nginx est déjà installé et en service, ne réinstallez pas. Vérifiez la version, confirmez que le service tourne, et passez à la partie qui change réellement le résultat. Réinstaller un serveur web en marche ne vous apporte rien et risque de le redémarrer à un moment que vous n'avez pas choisi.
La preuve que cette étape a réussi n'est pas « la commande a rendu 0 ». C'est une chaîne de version de nginx -v et un active de systemctl is-active nginx. Deux faits concrets, vérifiables par une machine, qu'un humain ou un modèle peut lire sans deviner.
2. Le vhost : là où vit vraiment le reverse proxy
C'est tout l'enjeu de l'exercice. Un bloc server de reverse proxy est court, et chaque ligne mérite sa place. En clair, il dit : réponds pour ce server_name, et fais tout passer vers une adresse amont avec les bons en-têtes attachés.
Trois détails séparent un proxy qui marche d'un proxy subtilement cassé :
- L'amont est un host:port, et il devrait être en loopback. Faire proxy vers
127.0.0.1:3000signifie que l'application n'a jamais à écouter sur une interface publique. Si votre app est liée à0.0.0.0, le proxy est décoratif — le port reste joignable directement. Liez l'app au loopback et laissez nginx être la seule porte. proxy_set_header Hostet la paire forwarded-for sont ce qui permet à l'amont de savoir qui a vraiment appelé et sous quel nom. Omettez-les et votre application journalise tout le monde comme127.0.0.1, vos redirections pointent vers le mauvais hôte, et toute logique basée sur l'IP en aval devient aveugle.- Les en-têtes d'upgrade WebSocket sont ceux que tout le monde oublie. Sans
proxy_set_header Upgrade $http_upgradeetConnection "upgrade", le HTTP simple fonctionne et chaque WebSocket échoue à se connecter en silence. Le symptôme, c'est une fonctionnalité temps réel qui « ne marche tout simplement pas » sans rien dans le journal d'erreurs, parce que du point de vue de nginx, rien n'a mal tourné.
Et la règle qui domine toutes les autres : ne pas écraser un vhost existant sans le sauvegarder d'abord. Un cp site.conf site.conf.bak ne coûte rien et fait la différence entre une erreur qu'on annule en une commande et un après-midi à reconstruire une configuration de mémoire.
3. Valider avant de recharger — toujours, sans exception
C'est la seule habitude qui évite la plupart des pannes nginx auto-infligées, et c'est une commande : nginx -t. Elle parse toute la configuration, suit chaque include, et vous dit si le démon l'accepterait — avant que vous ne demandiez au démon en marche d'y basculer.
nginx -t && systemctl reload nginx
Le && fait un vrai travail. Un reload garde les connexions établies en vie et n'applique la nouvelle configuration que si elle se parse ; mais si vous restart sur une config qui ne se parse pas, nginx s'arrête et ne revient pas, et le site est à terre pour une faute de frappe. Enchaîner le test au reload, c'est garantir qu'une config cassée n'atteint jamais le serveur en marche. Testez, puis rechargez ; ne rechargez jamais à l'aveugle.
La vérification de cette étape est tout aussi concrète : nginx -t qui annonce syntax is ok et test is successful, suivi de systemctl is-active nginx qui rend toujours active. Si l'un des deux échoue, vous n'avez rien changé que le monde extérieur puisse voir — ce qui est exactement la propriété qu'on veut d'une étape ratée.
4. Le TLS : la partie avec un rate limiter attaché
Un reverse proxy sur le port 80, c'est la moitié du travail. L'autre moitié, c'est un certificat, et la façon honnête d'en obtenir un est Certbot contre Let's Encrypt — certbot --nginx -d app.exemple.com obtient le certificat et réécrit votre vhost pour le servir. C'est réellement aussi fluide, avec deux réserves qui piègent :
- Le DNS doit d'abord pointer sur cette machine. Let's Encrypt prouve que vous contrôlez le domaine en l'atteignant ; si l'enregistrement
A/AAAAne résout pas encore vers ce serveur, l'émission échoue, et aucune quantité de réessais ne corrige un problème DNS. - Les rate limits sont réels et sans pitié. Quelques émissions ratées pour le même domaine et vous êtes bloqué pour des heures. C'est pourquoi le geste sensé est de tester la plomberie avec
certbot renew --dry-run— il exerce tout le chemin de renouvellement contre la frontière de staging sans dépenser votre quota réel. Prouvez que le timer de renouvellement existe (systemctl list-timers | grep certbot) et vous avez prouvé que le certificat n'expirera pas en silence dans quatre-vingt-dix jours.
Le renouvellement automatique est l'étape qu'on saute parce que le certificat qu'on vient d'émettre marche aujourd'hui. C'est aussi l'étape dont l'absence fait tomber le site dans trois mois, à une date que personne n'a notée. Vérifiez le timer, pas le certificat.
Ce qu'un reverse proxy ne vous donne pas
Être honnête sur la limite, c'est tout l'enjeu. Terminer le TLS et transférer les requêtes ne fait rien pour la sécurité de l'application derrière — une app vulnérable derrière un proxy parfait reste une app vulnérable. Ce n'est pas un WAF ; il ne filtre rien du contenu d'une requête à moins que vous ne le configuriez délibérément pour. Ce n'est pas un load balancer tant que vous ne lui donnez pas plusieurs amonts et une politique pour choisir entre eux. Et il fera volontiers proxy vers un amont à terre, renvoyant un 502 qui a l'air d'être votre faute alors que le vrai problème est un processus planté une couche plus bas.
Ce qu'il vous donne, c'est une porte d'entrée unique et contrôlable : un seul endroit qui termine le TLS, un seul endroit qui pose les en-têtes, un seul endroit dont les journaux disent qui a demandé quoi. Cela vaut la peine d'être pris, tant qu'on ne confond pas la porte avec la maison.
La vérification qui prouve que le proxy est réel
Un reload qui réussit prouve que nginx a accepté la config. Il ne prouve pas que le proxy atteint votre app. Donc, dans l'ordre :
curl -sf -o /dev/null -w '%{http_code}' http://localhost/sur le vhost — un200, ou un301délibéré vers HTTPS, pas la page par défaut de la distribution ;- le même curl directement sur l'amont, pour savoir si un 502 est la faute de nginx ou de l'app ;
- pour une fonctionnalité temps réel, une vraie poignée de main WebSocket — l'en-tête que vous avez posé n'est prouvé que par une connexion qui s'upgrade et reste ouverte ;
ss -tlpnpour confirmer que l'application est en loopback et pas, en douce, toujours exposée sur0.0.0.0;- le chemin TLS de bout en bout une fois le DNS résolu, et le timer de renouvellement listé et activé.
Ce que Servor apporte là-dedans
Servor livre cela comme une recette — l'un de ses 150+ playbooks vérifiés — et la forme d'une recette est exactement ce dont ce travail a besoin. Ce n'est pas un script figé tiré à l'aveugle sur la machine : il commence par la reconnaissance, en lisant si nginx est déjà là, si les ports sont libres, et si un vhost pour votre domaine existe déjà, si bien que le run s'adapte à un vrai serveur au lieu d'en supposer un vide. Un modèle bon marché le pilote, mais chaque étape qu'il propose porte sa propre vérification — le nginx -t, le code de statut curl, le is-active — si bien que le succès est prouvé, pas affirmé. Le playbook est idempotent : si nginx sert déjà, il vérifie et rapporte plutôt que de réinstaller, et il n'écrasera pas votre vhost sans sauvegarde.
Et le modèle d'exécution est le même que celui qui régit le copilote. Chaque commande est signée dans votre navigateur avec une clé dérivée de votre clé de vault, relayée verbatim, et vérifiée sur la machine par l'agent avant de s'exécuter — la recette reverse proxy ne plie aucune des règles zero-knowledge. L'agent atteint le plan de contrôle par une connexion sortante : resserrer les ports mêmes que vous êtes en train de proxifier ne coupe donc jamais votre chemin d'administration.
Ajoutez le TLS par-dessus avec la recette Let's Encrypt, et associez-lui un monitor sur le point d'accès public pour qu'un 502 réveille une machine et non votre prochain client. La discipline derrière cette boucle approuver-signer-vérifier fait l'objet de l'article Plan-Execute-Verify, et la partie exploitation vit dans notre guide de l'exploitation de serveurs.