NGinx, après Apache, fait partie des serveurs web les plus populaires. Une URL
Uniform Resource Locator est une adresse qui permet d’identifier une ressource telle qu’une page web. Une URL
propre ou préparée pour le référencement SEO Search Engine Optimization est une adresse facile à lire, à retenir, qui indique à l’utilisateur le contenu qu’il peut trouver.
Le module ngx_http_rewrite_module
est utilisé pour modifier l’URI
de demande à l’aide d’expressions régulières PCRE
Perl Compatible Regular Expressions, et permet de renvoyer des redirections et de sélectionner conditionnellement des configurations.
URI, URL ?
- Une
URI
Uniform Resource Identifier est un identifiant d’une ressource sur le réseau, telle qu’une page web, un livre, un document … - Une
URL
est un identifiant spécial qui indique le protocole pour accéder à une ressource telle quehttp
,https
,ftp
,sftp
. Ce sont les plus fréquents, mais il y en a d’autres.
Si le protocole (https
, ftp
, …) est présent devant le domaine, cela s’appelle une URL
—sinon c’est une URI
.
Objectif
Lorsque l’on accède à une ressource en base de données, on fait fréquemment appelle à son identifiant id
dans une table. Le paramètre est défini après le nom de la page suivi d’un point d’interrogation, par un nombre entier :
1 |
https://galaxies-sf.com/index.php?id=74 |
Ce n’est pas très parlant, l’id
correspond à une page qui présente le numéro 67 d’une revue de Science-Fiction Galaxies SF. Il serait donc bien plus intérressant de pouvoir écrire :
1 |
https://galaxies-sf.com/galaxies-revue-67.html |
De même, pour lire le sommaire de ce numéro, on accède à la page :
1 |
https://galaxies-sf.com/sommaire.php?id=74 |
qu’il serait beaucoup mieux de référencer à l’adresse :
1 |
https://galaxies-sf.com/sommaire-revue-67.html |
URL Rewriting
L’URL rewriting est une technique qui utilise un moteur de réécriture pour modifier l’apparence de l’URL
. L’URL Rewriting est rapide et flexible et il n’est pas obligatoire de renommer les dossiers de l’application. Cela permet de donner au serveur web (NGinx
) l’information nécessaire afin d’interpréter l’adresse requise.
NGinx
et l’URL Rewriting
NGinx
(prononcez engine X) est un serveur http
Hypertext Transfer Protocol. Il dispose de fichiers de configuration par défaut qui réside habituellement dans le dossier /usr/local/nginx/conf
ou /opt/nginx/conf
ou /usr/local/etc/nginx
, mais plus fréquemment dans /etc/nginx
. Le fichier contient :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
events { worker_connections 768; # multi_accept on; } http { ## # Basic Settings ## sendfile on; tcp_nopush on; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; ## # Gzip Settings ## gzip on; # gzip_vary on; # gzip_proxied any; # gzip_comp_level 6; # gzip_buffers 16 8k; # gzip_http_version 1.1; # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; ## # Virtual Host Configs ## include /etc/nginx/conf.d/*.conf; include /etc/nginx/sites-enabled/*; } #mail { # # See sample authentication script at: # # http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript # # # auth_http localhost/auth.php; # # pop3_capabilities "TOP" "USER"; # # imap_capabilities "IMAP4rev1" "UIDPLUS"; # # server { # listen localhost:110; # protocol pop3; # proxy on; # } # # server { # listen localhost:143; # protocol imap; # proxy on; # } #} |
Le symbole #
indique un commentaire.
Le fichier de configuration d’un site, contient une directive server
, dans laquelle on trouve des directives location
en fonction du type de fichiers demandés. Par exemple pour un site en php
, on trouve dans /etc/nginx/sites-available
des fichiers de configuration qui sont liés symboliquement dans /etc/nginx/sites-enabled
. Les sites actifs d’un serveur se trouvent dans sites-enabled
référencés, à la ligne 55 du fichier précédent, par une wildcard *
: /etc/nginx/sites-enabled/*
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# ... server { listen *:443 ssl http2; server_name murviel-info.com; root /var/www/murviel-info; # ... location ~ \.php$ { include fastcgi.conf; fastcgi_pass unix: /var/.../....sock; # ... include /etc/nginx/fastcgi_params; } # ... } |
Un exemple simple
Supposons que l’on a l’URL
suivante :
1 |
https://galaxies-sf.com/1234xavMiNaIrisEl56.html |
Et l’on désire que les utilisateurs accède à cette page avec l’URL
:
1 |
https://galaxies-sf.com/generateurs-base64 |
On peut alors créer un bloc location
simple :
1 2 3 4 5 6 7 |
server { # ... location = /generateurs-bases64 { rewrite ^/generateurs-base64$ /1234xavMiNaIrisEl56.html break; } # ... } |
Fonctionnement
location = /generateurs-bases64
: Comme le signe =
est utilisé, le bloc location
capture l’URL
:
1 |
https://galaxies-sf.com/generateurs-base64 |
Mais pas :
1 |
https://galaxies-sf.com/generateurs-base64/generateurs.html |
ni
1 |
https://galaxies-sf.com/generateurs-base64-gen |
Si l’on enlève le signe =
, le bloc location
capturera les URLs
ci-dessus, c’est-à-dire n’importe quelle URL
contenant /generateurs-base64
. On peut utiliser location ~
pour capturer des blocs avec des expressions régulières, ou location ~*
pour que l’expression régulière soit insensible à la casse. Si l’on ne met pas le tilde ~
, NGinx
attend une expression régulière.
L’instruction rewrite
indique une règle de réécriture, ^/generateurs-base64$
est une expression régulière, ^
repésente le début de la chaîne, $
la fin. On recherche la chaîne qui se trouve après le protocole http
ou https
et le nom de domaine domain.tld
(URI
), soit https?://domain.tld/mon-adresse
.
Une directive rewrite
redirige vers une URI
avec le code 301 ou 302, c’est-à-dire une redirection permanente ou temporaire, et est de la forme :
1 |
rewrite regex URI [flag]; |
Dans notre exemple, break
est un flag drapeau. Les flags disponibles sont :
last
: arrête le traitement de directivesrewrite
et lance la recherche d’un nouvel emplacement correspondant à l’URL
,break
: n’effectue pas le traitement de directivesrewrite
avec le même motif si d’autres suivent,redirect
retourne une redirection temporaire avec le code 302, utilisé seulement si la chaîne ne commence pas parhttp://
,https://
, or$scheme
,permanent
retourne une redirection permanente avec le code 301.
Parenthèses capturantes
Expression régulière
Dans une expression régulière, un motif est capturé lorsqu’il est entre parenthèse. Par exemple, le motif galaxies-([a-z])
capture ce qui suit galaxies-
et le place dans la variable $1
. S’il y a deux parenthèses, les variables capturées seront $1
, $2
et ainsi de suite. Donc, pour notre exemple https://galaxies-sf.com/sommaire-revue-67.html
, on va capturer sommaire
(puisque j’aurai la même chose avec editorial
, …), revue
et 67
(sachant que l’on peut avoir aussi 67bis
). Le motif de l’expression régulière est alors /([a-z])-([a-z])-([a-z0-9])\.html
. [a-z]
représente les lettres minuscules, 0-9
sont les chiffres, un point représente n’importe quel caractère, en l’echappant avec un backslash \
, il capture un simple point .
. On cherche alors à mettre en paramètre $_GET[]
de l’URL
, le type
de revue et le numéro de la revue. On sera obligé de modifier le fichier sommaire.php
pour aller récupérer l’id
en base de données connaissant le type
et le numéro de la revue.
Règle de réécriture
1 |
rewrite ~^/([a-z])-([a-z])-([0-9a-z]).html$ /$1.php?type=$2&revue=$3; |
Si l’on indique l’expression régulière avec un tilde ~
, il ne doit pas y avoir d’espace entre le ~
et la regex à savoir le caractère caret ^
de début de chaîne.
Mais, je veux également rediriger l’URL galaxies-revue-57.html
vers la page d’accueil index.php
. On écrit donc une deuxième règle rewrite
avant celle que l’on vient d’écrire. En principe, la première règle qui capture une URL
l’emporte, mais on peut faire suivre la directive avec le flag last
ou break
, pour indiquer que la recherche est terminée.
1 2 3 |
# Rewrite rules rewrite ^/galaxies-([a-z])-([0-9a-z]).html /index.php?type=$1&revue=$2; rewrite ^/([a-z])-([a-z])-([0-9a-z]).html$ /$1.php?type=$2&revue=$3; |
On écrit les lignes de réécriture dans le bloc server
. Ainsi pour les fichiers index.php
, sommaire.php
et editorial.php
qui fonctionnent en utilisant la variable
$_GET['id'], on change le début du traitement en retrouvant cet identifiant en base de données avec les variables
$_GET['type'] et
$_GET['revue']. WordPress fait la même chose avec le slug
ou postname
unique d’un article.
Il semble que NGinx
n’apprécie pas l’espace entre le tilde ~
indiquant la ReGex
et le caret ^
indiquant le début de la chaîne :
1 |
rewrite ~ ^/galaxies-([a-z])-([0-9a-z]).html /index.php?type=$1&revue=$2 last; |
Cette directive renvoie l’ erreur NGinx
: [emerg] invalid number of arguments in "rewrite" directive in /etc/nginx/sites-enabled/galaxies-sf.murvielinfo.com:30
. Si l’on omet le tilde ~
, ou si l’on ne met pas d’espace entre le tilde ~
et le caret ^
, il n’y a pas d’erreur.
En fait je pense que si l’on met cet espace, NGinx
attend l’expression de remplacement, le motif étant indiqué après la directive location
, comme dans l’exemple ci-après.
1 2 3 4 |
location ~ ^/galaxies-([a-z]+)-([0-9a-z]+)\.html$ { # Rewrite rules rewrite /index.php?type=$1&revue=$2; } |
L’adresse URL
sera par exemple de la forme https://galaxies-sf.com/galaxies-revue-67.html
. Ce qui nous intéresse est la chaîne après le nom de domaine. Le suffixe est .html
, on va donc cibler dans un bloc location
les chaînes se terminant par .html
. Si le motif est reconnu, on renvoie vers un fichier php
, par exemple index.php
, avec des arguments $_GET[]
.
Dans ce cas, on met plusieurs blocs locations
pour chaque rewrite
. Dans notre cas, on teste la fin de la chaîne .htm
l, et l’on rédéfinit le motif, en fonction de ce que l’on trouve dans l’URL. Il y a plusieurs façons de faire.
Bloc location
1 2 3 4 5 6 7 |
location ~* \.html$ { # Rewrite rules rewrite ^/galaxies-([a-z]+)-([0-9a-z]+)\.html$ /index.php?type=$1&revue=$2; rewrite ^/([a-z]+)-([a-z]+)-([0-9a-z]+)\.html$ /$1.php?type=$2&revue=$3; rewrite ^/geante-rouge-([a-z]+)-([0-9a-z-]+)\.html$ /geante-rouge/index.php?type=$1&revue=$2; rewrite ^/geante-rouge-([a-z]+)-([a-z]+)-([0-9a-z-]+)\.html$ /geante-rouge/$1.php?type=$2&revue=$3; } |
Ainsi l’URL
: https://galaxies-sf.com/galaxies-revue-67.html
sera réécrite en https://galaxies-sf.com/index.php?type=revue&revue=67
. Il n’y a plus qu’à gérer les variables $_GET['type']
et $_GET['revue']
dans le fichier index.php
, c’est-à-dire aller chercher l’id
en base de données avec ces deux données, pour laisser le traitement qui suit inchangé.
Le flag permanent
indique une redirection 301 permanente. Si on l’ajoute à nos directives rewrite
, l’URL
indiquée dans la barre d’adresse changera également, par exemple https://galaxies-sf.com/galaxies-revue-67.html
changera en https://galaxies-sf.com/index.php?type=revue&revue=67
. Ce n’est pas vraiment ce que l’on recherche.
L’URL
https://galaxies-sf.com/galaxies-revue-67.html
est beaucoup plus jolie, on peut bien mieux s’en rappeler, elle indique ce que l’on va trouver et sera bien mieux référencée que l’URL
https://galaxies-sf.com/index.php?id=74
. On veut néanmoins que l’URL avec le paramètre id
continue de fonctionner. Certains sites ont peut être déjà inscrit en lien cette URL
.
Test des règles de réécriture NGinx
On teste la configuration. Si cela ne produit aucune erreur, on redémarre le serveur http
:
1 2 3 4 |
xavier@server:/etc/nginx/sites-available$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful xavier@server:/etc/nginx/sites-available$ sudo systemctl restart nginx |
Erreur 404, page non trouvée :
On peut indiquer au serveur http
NGinx ce qu’il faut faire si la page n’est pas trouvée. C’est ce que l’on appelle une erreur 404. Les moteurs de recherche n’aiment pas cela. Pour optimiser un site en terme de SEO, il faut que les liens internes (dans le site vers le site) ne renvoient aucune erreur 404. Malheureusement, cela peut arriver. Mais, on peut rediriger la page 404 par defaut vers une page plus personnalisée dans la configuration NGinx.
Pour un site de taille conséquente, ceci peut être très long à faire, et il n’est pas sûr qu’il ne reste pas quelque chose. La page 404 montrée par défaut est une page blanche avec 404 Not Found indiquée :
Directive NGinx
Pour rediriger l’erreur 404 vers une page personnalisée, on écrit dans le fichier de configuration, dans le bloc server
:
1 |
error_page 404 /page-inconnue.php |
On crée une nouvelle page page-inconnue.php
, et l’on indique que la page n’a pas été trouvée. Ainsi, les pages non trouvées sont redirigées vers cette page que l’on peut ainsi personaliser :
Test de la configuration
On écrit dans le fichier index.php
, au tout début :
1 |
echo "<pre>_GET<pre>"; print_r( $_GET ); echo "</pre>"; die(); |
Ainsi, on affiche les variables $_GET
. On entre l’adresse : https://domain.tld/galaxies-revue-67.html
. Le retour est :
1 2 3 4 5 6 |
_GET Array ( [type] => revue [revue] => 67 ) |
Cela fonctionne bien.
Écriture du code PHP
On recherche alors l’id
dans la base de données. On écrit donc dans index.php
:
1 2 3 4 5 6 7 8 9 |
// Rewrite rules, nice URLs if( isset( $_GET['type'] ) && isset( $_GET['revue'] ) ) { $query = 'SELECT id FROM myTable WHERE type = :type AND revue = :revue'; $stmt = $pdo->prepare( $query ); $stmt->bindValue( ':type', $_GET['type'], PDO::PARAM_STR ); $stmt->bindValue( ':revue', $_GET['revue'], PDO:: PARAM_STR ); $stmt->execute(); $_GET['id'] = $stmt->fetchColumn(); } |
Ainsi, les anciennes URLs
fonctionnent et les nouvelles aussi.
Mais ce qui serait encore mieux, c’est lorsque l’on tape l’adresse https://galaxies-sf.com/sommaire.php?id=74
ou l’on clique sur un lien de cette adresse, on soit redirigé vers https://galaxies-sf.com/sommaire-revue-67.html
, et que cette nouvelle adresse remplace l’ancienne dans la barre d’adresse. Cela évitera la duplication de contenus, c’est-à-dire un même contenu à des adresses différentes. Cela permettra que d’anciens liens, référencés sur des sites externes fonctionnent toujours et renvoient sur la bonne page, avec la nouvelle adresse URL
inscrite dans la barre d’adresse. C’est réellement très important en terme de SEO.
La redirection doit être du type permanent 301. La redirection 301 permanente indique au navigateur web et aux robots des moteurs de recherche que la page visitée a définitivement changé d’adresse. Le caractère définitif de cette redirection indique aux moteurs de recherche qu’ils doivent mettre à jour leur index. Ceci se fait en PHP
à l’aide de l’instruction header()
qui permet de spécifier l’en-tête http
. On indique le type de redirection, et l’emplacement de celle-ci.
1 2 3 4 5 6 7 8 9 10 11 |
// index.php?id=74 => galaxies-revue-67.html if( isset( $_GET['id'] ) ) { $query = 'SELECT revue, type FROM myTable WHERE id = :id'; $stmt = $pdo->prepare( $query ); $stmt->bindValue( ':id', $_GET['id'], PDO::PAMAM_INT ); $stmt->execute(); $arr = $stmt->fetch( PDO::FETCH_ASSOC ); header( 'Status: 301 Moved Permanently', false, 301 ); header( "Location: /galaxies-{$arr['type']}-{$arr['revue']}.html" ); } |
Et hop, on a nos redirections, nos jolies URLs
, on est prêt pour le SEO. Il ne reste plus qu’à faire une jolie page 404
, où l’on peut proposer au visiteur de visiter d’autres pages.
Bonjour,
Je suis en cours de développement d’une boutique en ligne basée sur Opencart 3.0.3.6
Le serveur est un Centos 7.9 Plesk Onyx 18.7 Nginx 1.19 et Apache 2.4
Je rencontre les pires difficulté pour les rediections URI très complexes chez Opencart surtout sur NGINX (auapravant avec les .htaccess cela se réglait en trois minutes.
Ci-dessous les directives supplémentaires que j’ai ajouté dans plesk NGINX:
——–
location /boutique/ {try_files $uri @boutique;}
location /boutique/admin {index index.php;}
location @oc3 {rewrite ^/(.+)$ /boutique/index.php?_route_=$1 last;}
Cela fonctionne sur les articles les catégories mais pas sur d’autres éléments tels que Livraison, Conditions Générales etc..
Pourriez-vous m’aider à résoudre ce problème.
Merci infiniment
David
Je pense qu’il y a un problème avec la définition de
@boutique
et@oc3
. Le prefixe@
définit une location. Si@boutique
n’est pas défini, y’a un souci. Tentez de changer@oc3
en@boutique
, et de rajoutez$uri/
après$uri
.Et pour le
sitemap.xml
si vous l’utilisez :Bonjour Xavier,
Désolé de vous repondre si tardivement, j’ai été un peu débordé avec certains 😉
Cela ne fonctionne pas du tout 😉
La seule url qui fonctionne c’est index.php?route=common/home
Les autres URL ressortent en erreur404
Question: Pouquoi ajouter @opencart dans le tri_files ??
Je suis vraiement perdu…avez-vous une autre idée??? Merci infiniment
David