Aller au contenu
English
Compte : non connecté, synchronisation possible Mon apprentissage
Selectionner le thème
English

Nginx : choisir le bon server et la bonne location

Par mis à jour le

Améliorer cette page

Logo NGINX

Nginx choisit un server d'après le port et le nom d'hôte de la requête, puis un location d'après son chemin, et ces deux choix suivent des règles fixes qui ne dépendent pas de l'ordre visuel des blocs. Cette leçon s'adresse à une personne qui sait installer Nginx et lire ses contextes, et qui veut cesser de deviner quel bloc répond. Vous apprendrez à prédire la réponse avant d'envoyer la requête, à fermer la porte aux noms inconnus par un server par défaut, et à écrire des redirections qui conservent l'hôte et ne bouclent pas.

La leçon suit l'ordre dans lequel Nginx décide : le server, puis la location, puis la redirection éventuelle.

  • Prédire le server retenu d'après listen et server_name.
  • Refuser les noms d'hôte inconnus avec un server par défaut qui ne sert rien.
  • Prédire la location retenue parmi exacte, préfixe, préfixe prioritaire et regex.
  • Distinguer une réécriture interne d'une redirection externe.
  • Rédiger une redirection qui conserve l'hôte sans boucler.
  • Contrôler l'ordre des fichiers inclus avec nginx -T.

La leçon suppose que vous savez écrire un site (un fichier .conf dans /etc/nginx/conf.d/, que le paquet de l'éditeur sur Debian 13 charge par include /etc/nginx/conf.d/*.conf;), le valider par nginx -t puis recharger Nginx : écrire le fichier suffit à l'activer, sans lien ni répertoire intermédiaire.

Nginx cherche d'abord les server qui écoutent l'adresse et le port de la connexion (listen), puis compare l'en-tête Host de la requête à leurs server_name. Le listen filtre, le server_name départage. Si aucun nom ne correspond, la requête va au server par défaut de ce couple adresse et port.

Quand plusieurs server_name correspondent, Nginx applique cet ordre de priorité :

RangForme du server_nameExemple
1Nom exactboutique.lab.test
2Joker au début, le plus long*.lab.test
3Joker à la fin, le plus longboutique.*
4Première regex qui correspond, dans l'ordre du fichier~^b[a-z]+\.lab\.test$
5Le server par défautvoir ci-dessous

Sans default_server déclaré, le server par défaut est le premier server lu pour ce listen. C'est le piège principal de cette leçon : si le premier bloc du fichier est une page d'administration, tout nom inconnu (une sonde de scanner, un enregistrement DNS oublié, une requête forgée) tombe sur l'administration. Un server qui répond par défaut est une porte ouverte, pas une commodité.

On déclare explicitement un server par défaut qui ne sert rien : listen 80 default_server; suivi d'un refus. Ce bloc capte tout nom qu'aucun autre server_name ne revendique et répond par une erreur, de sorte qu'un site n'est jamais joignable par un nom qu'on n'a pas autorisé.

server {
listen 80 default_server;
server_name _;
return 404;
}

Le nom _ n'a aucun pouvoir particulier : c'est une convention pour un nom qui ne correspondra jamais à un vrai domaine. Le rôle de défaut vient de default_server, pas du nom. Le refus est une vraie réponse HTTP (404, 403 ou 421, ce dernier signifiant « Misdirected Request »). La valeur spéciale 444 de Nginx ferme la connexion sans rien répondre : elle est efficace contre les scanners, mais le client ne reçoit aucun code, ce qui complique le diagnostic : curl affiche alors 000 à la place d'un code HTTP. Le lab de cette leçon exige donc un vrai code HTTP pour un nom inconnu : un return 444, pourtant valable en production, ferait échouer son test, puisque curl y lit 000 et non un code.

Le même défaut existe en HTTPS, où le certificat est choisi avant la lecture de Host, d'après le SNI (Server Name Indication, le nom d'hôte que le client annonce dans la poignée de main TLS). Pour refuser aussi les poignées de main TLS vers un nom inconnu, le server par défaut de listen 443 ssl peut porter ssl_reject_handshake on; (disponible depuis Nginx 1.19.4), ce qui évite même de présenter un certificat à un nom que vous ne servez pas.

Vérifiez l'effet avec curl, en forçant l'en-tête Host pour simuler un nom, sans toucher au DNS. Remplacez l'adresse par celle de votre serveur :

Fenêtre de terminal
curl -s -o /dev/null -w '%{http_code}\n' -H 'Host: inconnu.exemple.test' http://127.0.0.1/

La commande doit afficher le code de refus que vous avez choisi (000 si vous avez retenu 444). Si elle affiche 200, un site répond à un nom inconnu que personne n'a autorisé : le server par défaut manque ou sert du contenu.

Dans le server retenu, Nginx choisit la location en trois temps : l'exacte, puis le meilleur préfixe, puis les regex, et l'ordre d'écriture ne compte que pour départager les regex. C'est une source classique d'erreurs de prédiction : on lit le fichier de haut en bas alors que Nginx ne le fait pas.

Il existe cinq formes de location. Retenez leur modificateur :

FormeSignificationSensibilité
location = /xChemin exactement égal à /xexacte
location /xPréfixe : tout chemin qui commence par /xpar préfixe
location ^~ /xPréfixe prioritaire : s'il gagne, les regex ne sont pas essayéespar préfixe
location ~ regexExpression régulière, sensible à la casseregex
location ~* regexExpression régulière, insensible à la casseregex

L'algorithme se lit sur le schéma suivant, de haut en bas. Le premier choix est le server ; ensuite une location exacte l'emporte sur tout ; sinon Nginx retient le préfixe le plus long, et s'il porte ^~ il gagne immédiatement ; sinon les regex sont essayées dans l'ordre du fichier et la première qui correspond l'emporte ; sans regex qui correspond, c'est le préfixe retenu.

Arbre de décision. La requête passe d'abord au choix du server par listen et server_name, sinon le default_server. Ensuite, si une location exacte correspond, elle gagne. Sinon Nginx retient le préfixe le plus long ; s'il porte ^~, il gagne. Sinon les regex sont essayées dans l'ordre du fichier : la première qui correspond gagne, et sans regex qui correspond le préfixe le plus long gagne.ouinonouinonouinonRequête : port, en-tête Host, chemin① Choix du serverlisten, puis server_namesinon le default_server② Un location = exactcorrespond-il ?Retenir : le préfixe le plus longde tous les préfixesCe préfixe porte-t-il ^~ ?③ Une regex correspond-elle ?essai dans l'ordre du fichierLe location exact gagneCe préfixe gagneLa première regex gagneLe préfixe le plus long gagne
Choix du server, puis de la location : la regex ne passe qu'après un préfixe sans ^~, et l'exacte passe avant tout. Source · SVG
Échap pour fermer, + et − pour zoomer, défilement pour se déplacer. 100 %

Voici une configuration d'exemple, volontairement différente de celle du lab. Chaque location répond par son propre nom, ce qui permet de voir laquelle a été choisie, sans consulter les journaux :

server {
listen 80;
server_name boutique.lab.test;
location = /panier { return 200 "exact-panier\n"; }
location /produits { return 200 "prefixe-produits\n"; }
location /produits/images/ { return 200 "prefixe-images\n"; }
location ^~ /medias/ { return 200 "prefere-medias\n"; }
location ~ \.(png|jpg)$ { return 200 "regex-images\n"; }
location / { return 200 "racine\n"; }
}

Tracez maintenant six URL avant de les envoyer, en appliquant l'algorithme. Le tableau donne le raisonnement ; le but est que vous obteniez la même prédiction sans le lire.

URLRaisonnementGestionnaire prédit
/panierExacte : elle gagne sur toutexact-panier
/panier/Le / final fait échouer l'exacte ; seule / correspondracine
/produits/listeMeilleur préfixe /produits, aucune regex ne correspondprefixe-produits
/produits/images/logo.pngMeilleur préfixe /produits/images/, sans ^~ : la regex .png prend la mainregex-images
/medias/logo.pngMeilleur préfixe /medias/ avec ^~ : les regex sont ignoréesprefere-medias
/contactSeul le préfixe / correspondracine

Comparez ensuite à la réponse réelle avec curl -s -H 'Host: boutique.lab.test' http://127.0.0.1/produits/images/logo.png. Le quatrième cas est celui qui surprend : le préfixe est plus précis, mais une regex prend la main parce que ce préfixe n'est pas prioritaire. Quand on veut qu'un préfixe protège ses fichiers des regex, on le déclare avec ^~. Une prédiction juste sur une configuration fautive ne prouve rien, et une configuration juste qu'on ne sait pas prédire non plus : c'est ce que le lab mesure.

Que fait Nginx de l'URL avant de la comparer aux locations ?

Section intitulée « Que fait Nginx de l'URL avant de la comparer aux locations ? »

Nginx compare les location au chemin normalisé, sans la chaîne de requête. Avant de choisir, il décode les séquences %XX, résout les segments . et .. et, par défaut, fusionne les barres obliques répétées (merge_slashes on). Il ignore enfin tout ce qui suit le ? : /produits?page=2 est comparé comme /produits.

Deux conséquences se mesurent. D'abord, /produits//liste et /produits/%6Ciste sont comparés comme /produits/liste : une règle de filtrage écrite sur le texte brut de l'URL se contourne facilement, alors qu'une règle écrite sur le chemin normalisé non. Ensuite, la variable $uri contient le chemin normalisé et $request_uri l'URL brute avec sa chaîne de requête. Pour une règle de sélection ou de sécurité, on utilise $uri ; pour recopier l'URL telle que le client l'a envoyée dans une redirection, on utilise $request_uri.

Comment une map évite-t-elle une série de conditions ?

Section intitulée « Comment une map évite-t-elle une série de conditions ? »

La directive map associe une valeur d'entrée à une variable de sortie, dans une table lue une fois, et remplace une pile de if. Elle se déclare dans le contexte http, hors de tout server, et n'est évaluée que lorsque la variable est utilisée. C'est l'outil adapté à une liste d'anciennes adresses et de leurs remplaçantes.

map $uri $nouvelle_adresse {
default "";
/ancien/tarifs /tarifs;
/ancien/contact /contact;
}
server {
listen 80;
server_name boutique.lab.test;
if ($nouvelle_adresse) {
return 301 $scheme://$host$nouvelle_adresse;
}
}

La valeur default couvre toute entrée absente de la table : ici une chaîne vide, que if lit comme fausse. Le if ne contient qu'un return, ce qui est son usage sûr : combiné à d'autres directives dans une location, il a un comportement surprenant que la documentation de Nginx déconseille, et c'est une raison de plus de préférer map.

Réécriture interne ou redirection externe : laquelle choisir ?

Section intitulée « Réécriture interne ou redirection externe : laquelle choisir ? »

Une redirection externe renvoie un code 3xx au client, qui refait une requête vers la nouvelle adresse ; une réécriture interne change le chemin à l'intérieur de Nginx, sans que le client le sache. La première change l'URL affichée par le navigateur, la seconde non.

Redirection externeRéécriture interne
Directivereturn 301 URL;rewrite regex remplacement last;
Le client voitUn code 3xx et une nouvelle URLUne réponse 200 sous l'URL d'origine
Nombre de requêtesDeuxUne
UsageUn contenu a déménagéUn chemin public couvre une organisation interne

Préférez return à rewrite pour une simple redirection : la règle y est lisible et il n'y a pas de regex à relire. Dans rewrite, le drapeau last relance le choix de la location avec le chemin réécrit, ce qui explique qu'une réécriture puisse boucler. Le risque commun aux deux formes est la boucle. Une redirection externe qui vise une adresse couverte par la location dont elle part se rappelle elle-même :

# ❌ boucle : /boutique/accueil commence par /boutique et retombe ici
location /boutique {
return 301 /boutique/accueil;
}

Le navigateur finit par afficher « trop de redirections » ; curl s'arrête à la limite que vous lui donnez. Une réécriture interne qui boucle est arrêtée par Nginx après dix passages, avec une erreur 500 et un message « rewrite or internal redirection cycle » dans le journal d'erreurs. Pour le même besoin, une location exacte (location = /boutique) évite la boucle, puisqu'elle ne capte pas /boutique/accueil.

Le second défaut est la perte de l'hôte. Une redirection qui écrit en dur un nom ou une adresse renvoie le client vers un autre site, par exemple 127.0.0.1 ou le nom du backend. Écrivez $scheme://$host pour conserver l'autorité de la requête. Pour mesurer le nombre de sauts et la destination finale, demandez à curl de suivre les redirections avec une limite :

Fenêtre de terminal
curl -s -o /dev/null -L --max-redirs 5 \
-w '%{num_redirects} saut(s), arrivée : %{url_effective}\n' \
-H 'Host: boutique.lab.test' http://127.0.0.1/ancien/tarifs

Un seul saut vers l'adresse attendue, sur le bon hôte, est le résultat correct. Deux sauts ou plus signalent un enchaînement à simplifier, et un compte qui atteint la limite fixée (ici 5) trahit une boucle.

Dans quel ordre Nginx lit-il les fichiers inclus ?

Section intitulée « Dans quel ordre Nginx lit-il les fichiers inclus ? »

L'ordre de lecture n'est pas celui que vous voyez dans votre éditeur : un include avec un joker remplace la ligne par plusieurs fichiers, dans un ordre que la documentation de Nginx ne garantit pas. Il peut ressembler à l'ordre alphabétique, mais il dépend de la façon dont le système liste le dossier : ne le déduisez pas du nom des fichiers. Pour le « premier server » d'un listen, c'est donc le premier lu après expansion des include.

Deux dangers en découlent. Le joker conf.d/*.conf charge tous les fichiers du dossier dont le nom se termine par .conf : une sauvegarde nommée boutique.conf.bak n'est pas lue, mais une copie nommée boutique-ancien.conf l'est, et elle redéfinit le même server_name. Nginx émet un avertissement « conflicting server name » (de la forme conflicting server name "boutique.lab.test" on 0.0.0.0:80, ignored) : c'est un simple avertissement, nginx -t réussit quand même, et la déclaration en double est ignorée, ce que le lecteur ne remarque pas si personne ne lit la sortie du test. Ensuite, ajouter ou renommer un fichier, par exemple avec un préfixe 00- ou zz-, peut changer le rang du server dans l'ordre de lecture. Pour trancher, ne devinez pas : sudo nginx -T affiche la configuration complète dans l'ordre exact de lecture, chaque fichier précédé de son chemin.

Fenêtre de terminal
sudo nginx -T | grep -nE '^# configuration file|server_name|default_server'

Cette commande résume en quelques lignes quel fichier déclare quel nom et quel default_server. Elle est le premier réflexe quand une requête n'arrive pas là où vous l'attendiez.

Le lab vous donne une configuration qui fonctionne mais dont les règles se recouvrent : un préfixe capte ce qu'une regex devait traiter, une redirection boucle, et aucun server n'est déclaré par défaut. Vous réparez la sélection, fermez la porte aux noms inconnus, corrigez la redirection, puis écrivez vos prédictions dans un fichier. La validation interroge le serveur par de vraies requêtes : elle vérifie le gestionnaire réellement choisi pour chaque URL d'une matrice, le refus d'un nom inconnu, le nombre de sauts de la redirection et la conservation de l'hôte, puis compare votre prédiction à ce que le serveur fait. Prédire juste sur une configuration fausse ne passe pas.

  • Nginx choisit le server par listen, puis server_name : exact, joker au début, joker à la fin, regex, puis défaut.
  • Sans default_server, le premier server lu reçoit tout nom inconnu : déclarez un défaut qui ne sert rien et répond par un refus.
  • La location se choisit en trois temps : exacte =, meilleur préfixe (qui gagne seul avec ^~), puis première regex dans l'ordre du fichier.
  • Un préfixe plus précis ne protège pas de la regex : seul ^~ empêche une regex de prendre la main.
  • Nginx compare le chemin normalisé sans la chaîne de requête ; $uri est normalisé, $request_uri est brut.
  • map remplace une pile de conditions par une table lue une fois.
  • Une redirection externe (return 301) coûte deux requêtes et change l'URL ; une réécriture interne n'en coûte qu'une. Dans les deux cas, ne visez pas une adresse couverte par la location de départ.
  • nginx -T donne l'ordre réel de lecture des fichiers : c'est lui qui tranche, pas l'éditeur.

Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

8 questions
8 min.
70% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Ce projet vous est utile ?

Les guides, formations, quiz et labs restent gratuits. Si vous les utilisez régulièrement, vous pouvez contribuer à leur maintenance et à leur développement.

Devenir membre de soutien (nouvel onglet) Soutenir une fois (nouvel onglet) En savoir plus

Suivez aussi le projet sur LinkedIn