infra / nginx
Server blocks et routing
Explication
Ce que vous allez apprendre
- Comprendre ce qu'est un "server block" et comment plusieurs sites cohabitent sur une même IP
- Voir comment Nginx choisit un site à partir du header
Hostenvoyé par le client - Prévoir systématiquement un
default_serverpour rejeter les requêtes suspectes - Comprendre les quatre types de
locationet l'ordre réel dans lequel Nginx les évalue - Éviter le piège classique de croire que l'ordre du fichier détermine toujours la priorité
Dans quel contexte ?
Une agence web héberge trois sites clients différents sur un seul serveur, pour économiser les coûts d'infrastructure. Les trois sites partagent la même adresse IP et le même port 80, mais doivent chacun afficher un contenu totalement différent selon le nom de domaine tapé par le visiteur. C'est exactement le problème que les server blocks résolvent.
D'abord, un server block correspond à un "site virtuel"
Chaque bloc server { } dans une configuration Nginx représente un site distinct, avec son propre server_name, sa propre racine de fichiers (root) et ses propres règles. Rien n'empêche plusieurs server blocks d'écouter sur le même port : c'est même la situation la plus courante en hébergement mutualisé.
Une fois plusieurs sites déclarés, comment Nginx sait-il lequel servir ?
La réponse ne vient pas de l'adresse IP, identique pour les trois sites, mais du header HTTP Host, envoyé automatiquement par le navigateur et qui contient le nom de domaine tapé par l'utilisateur. Nginx compare ce header à chaque server_name déclaré et sert le bloc correspondant.
Il reste une question de sécurité : que se passe-t-il si le Host ne correspond à rien ?
Sans précaution, une requête avec un Host inconnu (souvent un scan automatisé cherchant des vulnérabilités par IP directe) tomberait sur le premier server block du fichier, potentiellement le mauvais site. Un server_name _; avec listen 80 default_server; capte tout ce qui ne matche aucun autre bloc, et return 444; (un code spécial propre à Nginx) ferme la connexion sans réponse, ce qui décourage les scans automatisés en leur faisant perdre du temps sans leur donner d'information.
Prérequis
Cette leçon suppose une notion de base des headers HTTP (savoir que le navigateur envoie automatiquement un header Host avec chaque requête) — voir la leçon précédente pour la structure générale de la configuration.
Ensuite, un mécanisme plus subtil : router à l'intérieur d'un même site
Une fois le bon server sélectionné, Nginx doit encore choisir quel bloc location traiter, selon le chemin de l'URL demandée. Il existe quatre syntaxes de location, avec des priorités qui ne suivent PAS simplement l'ordre d'écriture dans le fichier.
| Syntaxe | Type de correspondance | Priorité |
|---|---|---|
location = /chemin | Exact | Maximale, gagne toujours si elle matche |
location ^~ /prefixe/ | Préfixe prioritaire | Coupe la recherche parmi les regex |
location ~ /regex/ ou ~* | Expression régulière | Dans l'ordre d'apparition entre elles |
location /prefixe | Préfixe simple | Le plus long préfixe qui matche gagne |
Piège fréquent
Beaucoup de débutants pensent que Nginx évalue les location dans l'ordre où elles apparaissent dans le fichier, comme un if/elif classique. C'est faux sauf entre les blocs de type regex (~, ~*), où l'ordre d'écriture compte réellement. Pour les autres types, c'est la spécificité de la correspondance (exact > préfixe prioritaire > regex > préfixe simple le plus long) qui détermine le gagnant, indépendamment de l'ordre dans le fichier.
Bonne pratique
Utilise location ^~ /static/ pour tout dossier de fichiers statiques que tu veux garantir de ne JAMAIS voir intercepté par une règle regex plus bas dans le fichier (par exemple une règle générique sur les extensions d'image) : le préfixe prioritaire coupe immédiatement la recherche parmi les expressions régulières.
Maintenant que le routage entre sites et entre chemins est clair, la prochaine leçon aborde le cas le plus fréquent en pratique : transmettre une requête à une application derrière Nginx, avec proxy_pass.
Commandes & code
Server blocks et routing
# Un "server block" = un site virtuel. Plusieurs peuvent cohabiter sur la même IP:port.
server {
listen 80;
server_name blog.example.com; # Nginx route selon le header Host: envoyé par le client
root /var/www/blog; # racine des fichiers pour ce site
index index.html;
}
server {
listen 80;
server_name shop.example.com;
root /var/www/shop;
index index.html;
}
# Server block "par défaut" : capte tout ce qui ne matche aucun server_name
server {
listen 80 default_server;
server_name _; # "_" = catch-all, évite de servir des sites par IP nue
return 444; # 444 = Nginx ferme la connexion sans réponse (anti-scan)
}# location : route selon le chemin de l'URL, PLUSIEURS syntaxes avec priorités différentes
server {
listen 80;
server_name example.com;
root /var/www/example.com;
location = /favicon.ico { # (1) "=" = match exact, priorité maximale
access_log off;
log_not_found off;
}
location ^~ /static/ { # (2) "^~" = préfixe prioritaire, arrête la recherche regex
expires 30d;
}
location ~* \.(jpg|jpeg|png|gif)$ { # (3) "~*" = regex insensible à la casse
expires 7d;
}
location ~ \.php$ { # (4) "~" = regex sensible à la casse
return 403; # ex : bloquer tout accès direct aux .php
}
location /api/ { # (5) préfixe simple, priorité la plus basse (sauf ^~)
proxy_pass http://127.0.0.1:8000/;
}
location / { # fallback général
try_files $uri $uri/ =404;
}
}Ordre d'évaluation des location (résumé) :
1. location = (exact)
2. location ^~ (préfixe, coupe la recherche regex)
3. location ~ / ~* (regex, dans l'ordre d'apparition dans le fichier)
4. location /path (préfixe simple, le plus long préfixe qui matche gagne)Résumé
server_nameroute par headerHost,listenroute par IP/port : un serveur peut cumuler plusieursserver_name.- Toujours prévoir un
default_serverqui rejette (return 444) les requêtes avec un Host inconnu. - L'ordre de priorité des
locationn'est PAS l'ordre du fichier sauf pour les regex entre elles :=>^~> regex > préfixe.
Exercices pratiques
Mission : corriger un routage location mal priorisé
Objectif : Diagnostiquer pourquoi une règle regex intercepte un dossier statique malgré un bloc préfixe prioritaire, et sécuriser l'accès par IP nue.
Contexte
Sur example.com, les fichiers de /static/logo.png sont censés bénéficier d'un cache long via location ^~ /static/ { expires 30d; }, mais un autre développeur a aussi ajouté location ~* \.(png|jpg)$ { expires 7d; } plus bas dans le fichier, et jure que l'ordre du fichier devrait faire gagner sa règle. Par ailleurs, un scan automatisé accède au site via son IP nue et reçoit une page qu'il ne devrait jamais voir.