web-dev-qa-db-fra.com

Nginx réécrit le domaine non préfixé www vers le domaine préfixé www

Je vois le Nginx documentation HttpRewriteModule a un exemple pour réécrire un domaine préfixé www vers un domaine non préfixé www:

if ($Host ~* www\.(.*)) {
  set $Host_without_www $1;
  rewrite ^(.*)$ http://$Host_without_www$1 permanent; # $1 contains '/foo', not 'www.mydomain.com/foo'
}

Comment puis-je faire l'inverse - réécrire un domaine non préfixé par www dans un domaine préfixé par www? J'ai pensé que je pourrais peut-être faire quelque chose comme ceci, mais Nginx n'aime pas l'instruction if imbriquée.

if ($Host !~* ^www\.) {                       # check if Host doesn't start with www.
    if ($Host ~* ([a-z0-9]+\.[a-z0-9]+)) {    # check Host is of the form xxx.xxx (i.e. no subdomain)
        set $Host_with_www www.$1;
        rewrite ^(.*)$ http://$Host_with_www$1 permanent;
    }
}

Je voulais également que cela fonctionne pour n'importe quel nom de domaine sans dire explicitement à Nginx de réécrire domain1.com -> www.domain1.com, domain2.com -> www.domain2.com, etc. car j'ai un grand nombre de domaines à réécrire .

39
saltycrane

Eh bien, je suppose que je n'ai pas vraiment besoin de la déclaration externe "si" car je ne vérifie que les domaines de la forme xxx.xxx de toute façon. Ce qui suit fonctionne pour moi, bien qu'il ne soit pas robuste. Faites-moi savoir s'il existe une meilleure solution.

    if ($Host ~* ^([a-z0-9\-]+\.(com|net|org))$) {
        set $Host_with_www www.$1;
        rewrite ^(.*)$ http://$Host_with_www$1 permanent;
    }

Edit: ajout d'un trait d'union à l'expression régulière car il s'agit d'un caractère valide dans un nom d'hôte.

14
saltycrane

Comme indiqué dans la documentation Nginx, vous devez éviter d'utiliser la directive if dans Nginx si possible , car dès que vous avez un if dans votre configuration, votre serveur a besoin pour évaluer chaque demande afin de décider si elle doit correspondre à cette if ou non.

Une meilleure solution serait de multiples directives de serveur.

server {
        listen 80;
        server_name website.com;
        return 301 $scheme://www.website.com$request_uri;
}

server {
        listen 80;
        server_name www.website.com;
        ... 
}

Si vous essayez de servir un site compatible SSL (HTTPS), vous avez plus ou moins trois options différentes.

  1. Configurez plusieurs adresses IP pour que chaque directive serveur écoute sur leur propre IP (ou différents ports si c'est une option pour vous). Cette option nécessite des certificats SSL pour website.com et www.website.com , vous disposez donc d'un certificat générique, d'un certificat UNI (plusieurs domaines) ou simplement de deux certificats différents.
  2. Faites la réécriture dans l'application.
  3. Utilisez la directive if redoutée.

Il existe également une option pour utiliser SNI, mais je ne suis pas sûr que cela soit entièrement pris en charge pour l'instant .

62
Lars
if ($Host !~* ^www\.) {
    rewrite ^(.*)$ http://www.$Host$1 permanent;
}
15
ss.
if ($Host ~* ^[^.]+\.[^.]+$) {
    rewrite ^(.*)$ http://www.$Host$1 permanent;
}

Il est uniquement possible d'obtenir des noms d'hôtes valides car la demande ne parviendra jamais à votre serveur autrement, il n'est donc pas nécessaire de créer votre propre logique de validation.

6
Anthony DiSanti

La documentation de nginx met en garde contre l'utilisation de if pour la réécriture. Veuillez consulter le lien ici: http://wiki.nginx.org/Pitfalls#Server_Name

4
Robert Brown

HTTP et HTTPS sans conditions if:

server {
    listen          80;
    listen          443;
    server_name     website.com;

    return 301 $scheme://www.website.com$request_uri;
}
server {
    listen          80;
    listen          443 default_server ssl;
    server_name     www.website.com;

    # Your config goes here #
}
1
Andrei

Solution pour plusieurs domaines, travaillant sur nginx 1.17 pour moi:

server {
        listen                                80;
        server_name                           .example.com;

        set $Host_with_www                 $Host;

        if ($Host !~* www\.(.*)) {
            set $Host_with_www www.$Host;
        }

        return                                301 https://$Host_with_www$request_uri;
}

Dans cet exemple de configuration, réécrit également HTTP sur HTTPS, si vous ne voulez pas réécrire - remplacez https: // par http: // dans la chaîne return.

Si vous souhaitez conserver le protocole, utilisez $scheme variable.

0
irsi