infra / nginx
Rewrite rules et redirections avancées
Explication
Ce que vous allez apprendre
- Choisir
returnplutôt querewritechaque fois qu'aucune transformation de pattern n'est nécessaire - Comprendre la différence critique entre
lastetbreakdans une directiverewrite - Rediriger proprement d'un domaine www vers son équivalent non-www (ou l'inverse)
- Comprendre pourquoi
ifa une réputation méritée de "piège" dans une configuration Nginx - Utiliser une
mapcomme alternative propre à desifen cascade
Dans quel contexte ?
Une entreprise migre son ancien blog vers une nouvelle structure d'URL (/blog/42/mon-titre devient /articles/42/mon-titre) et doit rediriger automatiquement toutes les anciennes URLs déjà indexées par les moteurs de recherche et partagées sur les réseaux sociaux, sans perdre leur référencement ni casser les liens existants.
D'abord, le cas le plus simple ne nécessite pas rewrite du tout
Rediriger une URL fixe vers une autre (/old-page vers /new-page) ne demande aucune transformation de pattern : return 301 /new-page; suffit, et c'est plus rapide à évaluer pour Nginx qu'une règle rewrite, en plus d'être plus lisible pour quiconque relit la configuration plus tard.
Une fois ce cas simple couvert, rewrite devient nécessaire pour des transformations réelles
Dès qu'une partie de l'URL doit être capturée et réinjectée dans la destination (comme l'identifiant 42 dans /blog/42/titre vers /articles/42/titre), une expression régulière avec des groupes capturants ($1, $2) devient indispensable — c'est exactement le rôle de rewrite.
Il reste une distinction technique qui déroute presque tout le monde au début
last et break semblent similaires mais se comportent très différemment. last relance complètement la recherche de location avec la nouvelle URI réécrite, ce qui peut créer une boucle infinie si la nouvelle URI re-matche accidentellement le même location. break continue l'exécution dans le location courant, sans jamais relancer la recherche : plus prévisible, mais limité au traitement en cours.
| Mot-clé | Comportement | Risque |
|---|---|---|
last | Relance la recherche de location depuis le début, avec la nouvelle URI | Boucle infinie possible si mal utilisé |
break | Continue dans le location courant, sans re-matching | Plus prévisible, mais pas de re-routage possible |
Ensuite, un choix de référencement à trancher une fois pour toutes
Un site accessible à la fois en www.example.com et example.com sans redirection est perçu par les moteurs de recherche comme deux sites distincts avec du contenu dupliqué, ce qui dilue le référencement. Choisir un domaine canonique et rediriger systématiquement (301, permanent) vers celui-ci règle ce problème une bonne fois pour toutes.
Prérequis
Cette leçon suppose que tu es à l'aise avec les server blocks et location (leçon 3) : rewrite et return s'utilisent dans ces deux contextes.
Il reste un dernier point, presque une règle de la communauté Nginx : "if is evil"
Le bloc if, dans un location, a un comportement souvent contre-intuitif en dehors de cas très simples (il ne se comporte pas comme un if de langage de programmation classique, et peut interagir mal avec d'autres directives). Une map, définie une fois au niveau global, remplace élégamment la plupart des if en cascade pour des redirections conditionnelles basées sur un header ou une URL.
Piège fréquent
Empiler plusieurs blocs if imbriqués dans un même location pour tester plusieurs conditions est une source classique de bugs difficiles à diagnostiquer dans Nginx : la documentation officielle elle-même recommande d'éviter if sauf dans les cas les plus simples (une seule condition, pas de logique combinée), au profit d'une map.
Maintenant que les redirections sont maîtrisées, la prochaine leçon aborde un protocole différent du HTTP classique : le WebSocket, et les réglages spécifiques nécessaires pour le faire transiter correctement par un reverse proxy Nginx.
Commandes & code
Rewrite rules et redirections avancées
server {
server_name example.com;
# return : la manière PRÉFÉRÉE de rediriger (plus rapide, plus lisible que rewrite)
location = /old-page {
return 301 /new-page; # redirection interne, même domaine
}
location = /old-domain-path {
return 301 https://newdomain.com/path; # redirection vers un autre domaine
}
# rewrite : nécessaire pour des transformations de pattern plus complexes
rewrite ^/blog/(\d+)/(.*)$ /articles/$1/$2 permanent; # /blog/42/titre -> /articles/42/titre (301)
rewrite ^/old-api/(.*)$ /api/v2/$1 last; # "last" = relance la recherche de location avec la nouvelle URI
}# Différence cruciale entre "last" et "break" dans un rewrite
location /api/ {
rewrite ^/api/(.*)$ /$1 break; # "break" : réécrit puis CONTINUE dans ce même location (pas de re-matching)
proxy_pass http://127.0.0.1:8000;
}
location /redirect-me/ {
rewrite ^/redirect-me/(.*)$ /new/$1 last; # "last" : réécrit puis RECOMMENCE la recherche de location depuis le début
# ATTENTION : mal utilisé, "last" peut créer une boucle infinie si la nouvelle URI re-matche le même location
}# Redirection www <-> non-www (choisir UN canonique, jamais laisser les deux indexés)
server {
listen 80;
server_name www.example.com;
return 301 https://example.com$request_uri; # www -> non-www, en HTTPS, en conservant le path+query
}# Rewrite conditionnel avec "if" — À ÉVITER autant que possible (comportement souvent contre-intuitif dans Nginx)
server {
location / {
# Mauvaise pratique classique : if imbriqué dans location pour tester un header
if ($http_user_agent ~* "curl") {
return 403;
}
# Préférer une "map" (voir ci-dessous) plutôt que des blocs if en cascade
}
}
# map : alternative propre et performante à "if" pour des redirections conditionnelles multiples
map $http_user_agent $is_bot {
default 0;
"~*bot|crawler|spider" 1;
}
server {
location / {
if ($is_bot) {
return 403;
}
}
}# Redirections en masse depuis une migration (ex : ancien CMS -> nouveau site)
map $uri $redirect_uri {
/produits/ancien-nom /produits/nouveau-nom;
/promo-2023 /promotions;
default ""; # pas de redirection si pas dans la map
}
server {
if ($redirect_uri) {
return 301 $redirect_uri; # ici, "if" est acceptable : cas simple, une seule condition, pas de logique métier
}
}Résumé
returnest préférable àrewritechaque fois qu'aucune transformation de pattern n'est nécessaire : plus simple et plus rapide.lastrelance la recherche delocation(risque de boucle) ;breakcontinue dans lelocationcourant (plus prévisible).- "If is evil" dans Nginx :
ifa un comportement surprenant en dehors de cas très simples ; préférermappour la logique conditionnelle. - Toujours choisir un domaine canonique (www ou non-www, http vs https) et rediriger 301 systématiquement vers celui-ci pour le SEO.
Exercices pratiques
Mission : migrer les URLs d'un blog sans casser le référencement ni créer de boucle
Objectif : Choisir entre return et rewrite selon le cas, éviter une boucle infinie avec last, et rediriger proprement un domaine www vers son canonique.
Contexte
Le blog migre de /blog/42/mon-titre vers /articles/42/mon-titre. Un développeur propose d'utiliser rewrite ^/blog/(.*)$ /articles/$1 last; mais s'inquiète d'une possible boucle infinie si /articles/ matche un jour un location qui redéclenche la même règle. Il faut aussi rediriger une fois pour toutes www.example.com vers example.com, sans jamais laisser les deux versions indexées.