Nginx no-www à www et www à no-www

497

J'utilise nginx sur le cloud Rackspace suite à un tutoriel et ayant cherché sur le net et jusqu'à présent, je ne peux pas trier cela.

Je veux que www.mysite.com se rende sur mysite.com comme d'habitude dans .htaccess pour le référencement et pour d'autres raisons.

Ma configuration /etc/nginx/sites-available/www.example.com.vhost :

server {
       listen 80;
       server_name www.example.com example.com;
       root /var/www/www.example.com/web;

       if ($http_host != "www.example.com") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

J'ai aussi essayé

server {
       listen 80;
       server_name example.com;
       root /var/www/www.example.com/web;

       if ($http_host != "www.example.com") {
                 rewrite ^ http://example.com$request_uri permanent;
       }

J'ai aussi essayé. Les deux tentatives donnent des erreurs de boucle de redirection.

if ($host = 'www.example.com' ) {
rewrite ^ http://example.com$uri permanent;
}

Mon DNS est configuré en standard:

site.com 192.192.6.8 A type at 300 seconds
www.site.com 192.192.6.8 A type at 300 seconds

(des exemples d'adresses IP et de dossiers ont été utilisés pour des exemples et pour aider les gens à l'avenir). J'utilise Ubuntu 11.

TheBlackBenzKid
la source
1
Je me sens obligé de dire que si vous travaillez avec un site Web WordPress, vérifiez le Dashboard > Settings > General Settingset assurez-vous qu'il n'y en a pas wwwdans les URL d'adresse WordPress / adresse du site. Peu importe comment vous configurez votre nginx, si vous avez un www dans ces URL, il sera redirigé vers celui avec www dedans.
Abhinav Sood

Réponses:

792

Solution HTTP

D'après la documentation , "la bonne façon est de définir un serveur séparé pour example.org":

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

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

Solution HTTPS

Pour ceux qui veulent une solution comprenant https://...

server {
        listen 80;
        server_name www.domain.com;
        # $scheme will get the http protocol
        # and 301 is best practice for tablet, phone, desktop and seo
        return 301 $scheme://domain.com$request_uri;
}

server {
        listen 80;
        server_name domain.com;
        # here goes the rest of your config file
        # example 
        location / {

            rewrite ^/cp/login?$ /cp/login.php last;
            # etc etc...

        }
}

Remarque: Je n'ai pas initialement inclus https://dans ma solution car nous utilisons des équilibreurs de charge et notre serveur https: // est un serveur de paiement SSL à fort trafic: nous ne mélangeons pas https: // et http: //.


Pour vérifier la version de nginx, utilisez nginx -v.

Supprimer www de l'url avec la redirection nginx

server {
    server_name  www.domain.com;
    rewrite ^(.*) http://domain.com$1 permanent;
}

server {
    server_name  domain.com;
    #The rest of your configuration goes here#
}

Vous devez donc avoir DEUX codes de serveur.

Ajoutez le www à l'url avec la redirection nginx

Si ce dont vous avez besoin est le contraire, pour rediriger de domain.com vers www.domain.com, vous pouvez utiliser ceci:

server {
    server_name  domain.com;
    rewrite ^(.*) http://www.domain.com$1 permanent;
}

server {
    server_name  www.domain.com;
    #The rest of your configuration goes here#
}

Comme vous pouvez l'imaginer, c'est tout le contraire et fonctionne de la même manière que le premier exemple. De cette façon, vous n'obtiendrez pas de marques SEO, car il s'agit d'une redirection et d'un déplacement permanents. Le no WWW est forcé et le répertoire affiché!

Une partie de mon code ci-dessous pour une meilleure vue:

server {
    server_name  www.google.com;
    rewrite ^(.*) http://google.com$1 permanent;
}
server {
       listen 80;
       server_name google.com;
       index index.php index.html;
       ####
       # now pull the site from one directory #
       root /var/www/www.google.com/web;
       # done #
       location = /favicon.ico {
                log_not_found off;
                access_log off;
       }
}
TheBlackBenzKid
la source
3
@puk l'apprécie. Nginx est incroyable, mais une bonne documentation qui reste à jour avec la version du serveur et les modifications du système d'exploitation et du matériel du serveur est assez fastidieuse. La meilleure ressource qui me sert est howtoforge.com car il prend en charge les versions cloud de RackSpace. Certaines des commandes ci-dessus ne fonctionneront pas dans les versions ultérieures. Mais ce nginx / 0.8.54 - est croyez-moi, le meilleur serveur nginx) pas besoin de mettre à niveau ou de mettre à jour. Fonctionne bien. 100 000 visites uniques par jour avec 4200 transactions en moyenne par jour. Nginx est RAPIDE. comme utiliser un site sans trafic.
TheBlackBenzKid
17
Vos réécritures devraient devenir des retours, comme dans return 301 $scheme://domain.com$request_uri;. Il n'est pas nécessaire de capturer de motifs, voir les pièges de Nginx
Roberto
4
@TheBlackBenzKid Désolé, j'ai peut-être manqué quelque chose, mais la solution mise à jour ne fonctionne pas. C'est parce que j'écoute 80 - avec cela, vous dites que seul HTTP correspond à cela. Il devrait y avoir plus de ports à écouter si la même configuration est utilisée pour HTTP et HTTPS ... Ou? Mais définitivement m'a aidé, +1. Merci pour votre réponse. À votre santé.
tomis
3
@TheBlackBenzKid C'était juste une note. J'ai trouvé une solution de travail. Dans votre exemple, seul Listen 443 doit être ajouté et le travail terminé.
tomis
2
la réponse est fausse. il redirige tous les sous-domaines vers www.
r3wt
399

En fait, vous n'avez même pas besoin d'une réécriture.

server {
    #listen 80 is default
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
    #listen 80 is default
    server_name example.com;
    ## here goes the rest of your conf...
}

Comme ma réponse obtient de plus en plus de votes, mais aussi ce qui précède. Vous ne devez jamais utiliser un rewritedans ce contexte. Pourquoi? Parce que nginx doit traiter et démarrer une recherche. Si vous utilisez return(qui devrait être disponible dans n'importe quelle version de nginx), il arrête directement l'exécution. Ceci est préférable dans n'importe quel contexte.

Redirigez les deux, non SSL et SSL vers leur homologue non www:

server {
    listen               80;
    listen               443 ssl;
    server_name          www.example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    return 301 $scheme://example.com$request_uri;
}

server {
    listen               80;
    listen               443 ssl;
    server_name          example.com;
    ssl_certificate      path/to/cert;
    ssl_certificate_key  path/to/key;

    # rest goes here...
}

La $schemevariable ne contiendra que httpsi votre serveur n'écoute que sur le port 80 (par défaut) et que l'option listen ne contient pas le sslmot - clé. Ne pas utiliser la variable ne vous fera gagner aucune performance.

Notez que vous avez besoin d'encore plus de blocs serveur si vous utilisez HSTS, car les en-têtes HSTS ne doivent pas être envoyés via des connexions non chiffrées. Par conséquent, vous avez besoin de blocs de serveur non chiffrés avec des redirections et de blocs de serveur chiffrés avec des redirections et des en-têtes HSTS.

Redirigez tout vers SSL (configuration personnelle sous UNIX avec IPv4, IPv6, SPDY, ...):

#
# Redirect all www to non-www
#
server {
    server_name          www.example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:80;
    listen               *:443 ssl spdy;
    listen               [::]:80 ipv6only=on;
    listen               [::]:443 ssl spdy ipv6only=on;

    return 301 https://example.com$request_uri;
}

#
# Redirect all non-encrypted to encrypted
#
server {
    server_name          example.com;
    listen               *:80;
    listen               [::]:80;

    return 301 https://example.com$request_uri;
}

#
# There we go!
#
server {
    server_name          example.com;
    ssl_certificate      ssl/example.com/crt;
    ssl_certificate_key  ssl/example.com/key;
    listen               *:443 ssl spdy;
    listen               [::]:443 ssl spdy;

    # rest goes here...
}

Je suppose que vous pouvez imaginer d'autres composés avec ce modèle maintenant par vous-même.

Plus de mes configs? Allez ici et ici .

Broyeur de chair
la source
3
Votre Chrome ne devrait pas pouvoir accéder à votre domaine www si vous utilisez HSTS. Veuillez ouvrir une nouvelle question avec autant de détails que possible et je vais vous aider (vous pouvez poster l'URL de la question en commentaire ici).
Fleshgrinder
1
@Fleshgrinder J'essaie d'implémenter votre configuration mais j'obtiens le problème suivant à stackoverflow.com/questions/29451409/… Des idées sur la façon de le faire fonctionner?
YPCrumble
4
Dans le 2ème bloc "Rediriger les deux, non SSL et SSL vers leur homologue non www:", les deux blocs serveur doivent avoir les directives SSL, car le navigateur doit vérifier le certificat pour www.example.com avant de rediriger vers l'exemple .com.
Jeff Tsay
1
Bien sûr, j'ai ajouté cela ainsi qu'une brève information sur HSTS.
Fleshgrinder
1
@YPCrumble oui, c'est BEAUCOUP plus rapide de cette façon car nous n'effectuons pas de correspondance d'expressions régulières à chaque demande. Nous ne redirigeons que si nous savons que nous devons rediriger. Pas de contrôles, pas de validation, rien: il suffit de rediriger. =)
Fleshgrinder
37

Vous pouvez découvrir que vous souhaitez utiliser la même configuration pour plus de domaines.

L'extrait suivant supprime www avant tout domaine:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}
Martin Höger
la source
7
J'aime mieux cette méthode que les blocs de serveurs dédiés. Changer httppour$scheme
ck_
2
Beaucoup mieux, je ne peux pas croire que tant de personnes coderaient en dur des domaines en configurations pour cette tâche.
MrYellow
1
@Oli Ce lien ne mentionne pas (à ce jour) les performances mais plutôt qu'ils ne sont pas sûrs à 100%. Il dit "les seules choses 100% sûres qui peuvent être faites à l'intérieur si dans un contexte d'emplacement sont: return ...et rewrite ... last". Des liens mis à jour vers des problèmes de performances?
Adam
1
Ça n'a pas marché pour moi. Obtention d'une erreur sur le navigateur indiquant une réponse non valide.
Nico Brenner
1
Malheureusement, je n'ai pas trouvé de moyen sans "si". J'utilise la même configuration pour de nombreux domaines, le codage en dur des noms de domaine n'est pas une option. Toute suggestion / commentaire est apprécié!
Martin Höger
27

Vous avez besoin de deux blocs serveur.

Mettez-les dans votre fichier de configuration, par exemple /etc/nginx/sites-available/sitename

Supposons que vous décidiez d'utiliser http://example.com comme adresse principale à utiliser.

Votre fichier de configuration devrait ressembler à ceci:

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

        # this is the main server block
        # insert ALL other config or settings in this server block
}

Le premier bloc serveur contiendra les instructions pour rediriger toutes les demandes avec le préfixe «www». Il écoute les demandes d'URL avec le préfixe «www» et les redirections.

Cela ne fait rien d'autre.

Le deuxième bloc serveur contiendra votre adresse principale - l'URL que vous souhaitez utiliser. Tous les autres réglages sont ici comme root, index, location, etc. Vérifiez le fichier par défaut de ces paramètres , vous pouvez inclure dans le bloc de serveur.

Le serveur a besoin de deux enregistrements DNS A.

Name: @ IPAddress: your-ip-address (for the example.com URL)

Name: www IPAddress: your-ip-address (for the www.example.com URL)

Pour ipv6, créez la paire d'enregistrements AAAA en utilisant votre adresse ipv6.

rouge
la source
23

Voici comment le faire pour plusieurs noms de serveur www vers no-www (je l'ai utilisé pour les sous-domaines):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}
Eric Johnson
la source
20
  1. Meilleure pratique: séparé serveravec codage en durserver_name

La meilleure pratique avec nginx est d'utiliser un séparé serverpour une redirection comme celle-ci (non partagée avec la serverconfiguration principale), de tout coder en dur et de ne pas utiliser du tout d'expressions régulières.

Il peut également être nécessaire de coder en dur les domaines si vous utilisez HTTPS, car vous devez savoir à l'avance quels certificats vous fournirez.

server {
    server_name www.example.com;
    return  301 $scheme://example.com$request_uri;
}
server {
    server_name www.example.org;
    return  301 $scheme://example.org$request_uri;
}
server {
    server_name example.com example.org;
    # real configuration goes here
}

  1. Utilisation d'expressions régulières dans server_name

Si vous avez un certain nombre de sites et que vous ne vous souciez pas des performances les plus élevées, mais que chacun d'entre eux ait la même politique en ce qui concerne le www.préfixe, vous pouvez utiliser des expressions régulières. La meilleure pratique d'utiliser un élément distinct serverserait toujours valable.

Notez que cette solution devient délicate si vous utilisez https, car vous devez alors avoir un seul certificat pour couvrir tous vos noms de domaine si vous voulez que cela fonctionne correctement.


non wwwà wwww / regex dans un single dédié serverpour tous les sites:

server {
    server_name ~^(?!www\.)(?<domain>.+)$;
    return  301 $scheme://www.$domain$request_uri;
}

wwwà non- wwww / regex dans un single dédié serverpour tous les sites:

server {
    server_name ~^www\.(?<domain>.+)$;
    return  301 $scheme://$domain$request_uri;
}

wwwà non- wwww / regex dans un site dédié serverà certains sites uniquement:

Il peut être nécessaire de limiter l'expression rationnelle pour couvrir seulement quelques domaines, vous pouvez alors utiliser quelque chose comme ça pour correspondre uniquement www.example.org, www.example.comet www.subdomain.example.net:

server {
    server_name ~^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$;
    return  301 $scheme://$domain$request_uri;
}

Test d'expressions régulières avec nginx

Vous pouvez tester que l' expression régulière fonctionne comme prévu avec pcretestsur votre système, qui est exactement la même pcrebibliothèque que votre nginx utilisera pour les expressions régulières:

% pcretest 
PCRE version 8.35 2014-04-04

  re> #^www\.(?<domain>(?:example\.org|example\.com|subdomain\.example\.net))$#
data> test
No match
data> www.example.org
 0: www.example.org
 1: example.org
data> www.test.example.org
No match
data> www.example.com
 0: www.example.com
 1: example.com
data> www.subdomain.example.net
 0: www.subdomain.example.net
 1: subdomain.example.net
data> subdomain.example.net
No match
data> www.subdomain.example.net.
No match
data> 

Notez que vous n'avez pas à vous soucier des points de fin ou de la casse, car nginx s'en occupe déjà, selon le nom du serveur nginx regex lorsque l'en-tête "Host" a un point de fin .


  1. Saupoudrer ifdans le existant server/ HTTPS:

Cette solution finale n'est généralement pas considérée comme la meilleure pratique, mais elle fonctionne et fait toujours l'affaire.

En fait, si vous utilisez HTTPS, cette solution finale peut être plus facile à maintenir, car vous n'auriez pas à copier-coller tout un tas de directives ssl entre les différentes serverdéfinitions, et pourriez à la place placer les extraits uniquement dans les serveurs nécessaires, ce qui facilite le débogage et la maintenance de vos sites.


non wwwà www:

if ($host ~ ^(?!www\.)(?<domain>.+)$) {
    return  301 $scheme://www.$domain$request_uri;
}

wwwà non www:

if ($host ~ ^www\.(?<domain>.+)$) {
    return  301 $scheme://$domain$request_uri;
}

codage en dur d'un seul domaine préféré

Si vous voulez un peu plus de performances, ainsi que la cohérence entre plusieurs domaines qu'un seul serverpeut utiliser, il peut toujours être judicieux de coder en dur explicitement un seul domaine préféré:

if ($host != "example.com") {
    return  301 $scheme://example.com$request_uri;
}

Références:

cnst
la source
16

Cette solution vient de mon expérience personnelle. Nous avons utilisé plusieurs compartiments Amazon S3 et un serveur pour la redirection non-wwwvers des wwwnoms de domaine pour correspondre à la stratégie d'en-tête "Host" S3 .

J'ai utilisé la configuration suivante pour le serveur nginx :

server {
    listen 80;
    server_name ~^(?!www\.)(?<domain>.+)$;
    return 301 $scheme://www.$domain$request_uri;
}

Cela correspond à tous les noms de domaine pointés vers le serveur commençant par n'importe quoi mais www.et redirige vers www.<domain>. De la même manière, vous pouvez faire une redirection opposée de wwwvers non-www.

Vision
la source
qu'en est-il de https? note: https BESOIN du certificat
Toskan
Il n'y a absolument aucun problème avec HTTPS ici. Après, listen 80vous devez ajouter des directives listen 443 sslet puis ssl_certificateet ssl_certificate_key.
VisioN
personne n'utilise http de nos jours. Je lisais un guide top répertorié dans google qui a montré votre exemple juste avec la ligne ajoutée listen 443 ssl avec certificat manquant. Cela ne fonctionnera pas et cause de sérieux maux de tête.
Toskan
Je ne sais pas de quel guide vous parlez. J'ai cette configuration qui fonctionne avec succès depuis près de trois ans. L'année dernière, j'ai ajouté la prise en charge de SSL et cela fonctionne comme prévu. Et bien sûr, vous devez avoir un certificat avec une clé privée en main.
VisioN
donc cela va encombrer tous les sous-domaines sauf www, correct?
Métagraphe
15

J'ai combiné le meilleur de toutes les réponses simples, sans domaines codés en dur.

301 redirection permanente de non-www vers www (HTTP ou HTTPS):

server {
    if ($host !~ ^www\.) {
        rewrite ^ $scheme://www.$host$request_uri permanent;
    }

    # Regular location configs...
}

Si vous préférez non HTTPS, non www vers HTTPS, www redirigez en même temps:

server {
    listen 80;

    if ($host !~ ^www\.) {
        rewrite ^ https://www.$host$request_uri permanent;
    }

    rewrite ^ https://$host$request_uri permanent;
}
Matt Janssen
la source
11

Rediriger non www vers www

Pour un domaine unique:

server {
        server_name example.com;
        return 301 $scheme://www.example.com$request_uri;
}

Pour tous les domaines:

server {
        server_name "~^(?!www\.).*" ;
        return 301 $scheme://www.$host$request_uri;
}

Redirigez www vers non-www pour un seul domaine:

server {
        server_name www.example.com;
        return 301 $scheme://example.com$request_uri;
}

Pour tous les domaines:

server {
         server_name "~^www\.(.*)$" ;
         return 301 $scheme://$1$request_uri ;
}
Ravindra Bhalothia
la source
Pourriez-vous faire la différence entre 80et 443?
Hassan Baig
1
Cela semble fonctionner sans listendirectives pour moi (nginx 1.4.6).
Ibrahim
11

essaye ça

    if ($host !~* ^www\.){
        rewrite ^(.*)$ https://www.yoursite.com$1;
    }

Autre moyen: Nginx no-www à www

server {
  listen       80;
  server_name  yoursite.com;
  root /path/;
  index index.php;
  return       301 https://www.yoursite.com$request_uri;
}

et www à no-www

server {
  listen       80;
  server_name  www.yoursite.com;
  root /path/;
  index index.php;
  return       301 https://yoursite.com$request_uri;
}
Kevin Nguyen
la source
Pourquoi les auteurs ont-ils fourni une instruction if dans nginx et ont ensuite dit aux gens de l'éviter? Cela me semble désinvolte.
Greg Smethells
4
Il est indiqué "SI l'emplacement est mauvais". Vous pouvez le mettre en toute sécurité dans votre bloc serveur
Kukunin
Citation directe du lien ci-dessus ... Les seules choses 100% sûres qui peuvent être faites à l'intérieur si dans le contexte de l'emplacement sont: retour ...; réécrire ... dernier;
Justin E
8

Format unique:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}
Andriyun
la source
1
Vous pouvez le rendre générique en l'écrivant de cette façon: server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
Ramast
5
location / { 
    if ($http_host !~ "^www.domain.com"){ 
        rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
    } 
}
Maoz Zadok
la source
1
$scheme://www.domain.com$1pour éviter la double barre oblique
karimhossenbux
3

Je ne sais pas si quelqu'un remarque qu'il peut être correct de retourner un 301, mais les navigateurs s'y étouffent en faisant

rewrite ^(.*)$ https://yoursite.com$1; 

est plus rapide que:

return 301 $scheme://yoursite.com$request_uri;
Steven
la source
1
mon commentaire s'adressait au navigateur pas à l'efficacité côté nginx! avec une redirection, le navigateur fait 2 demandes vs 1 demande lors de la ré
steven
2

Blog fantôme

afin de faire la méthode recommandée par nginx avec le return 301 $scheme://example.com$request_uri;travail avec Ghost, vous devrez ajouter dans votre bloc serveur principal:

proxy_set_header    X-Real-IP           $remote_addr;
proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
proxy_set_header    Host                $http_host;
proxy_set_header    X-Forwarded-Proto   $scheme;
proxy_set_header    X-NginX-Proxy       true;

proxy_pass_header   X-CSRF-TOKEN;
proxy_buffering     off;
proxy_redirect      off;  
stevek
la source
2

Si vous ne voulez pas coder en dur le nom de domaine, vous pouvez utiliser ce bloc de redirection. Le domaine sans le www de tête est enregistré en tant que variable $domainqui peut être réutilisée dans l'instruction de redirection.

server {
    ...
    # Redirect www to non-www
    if ( $host ~ ^www\.(?<domain>.+) ) {
       rewrite ^/(.*)$ $scheme://$domain/$1;
    }
}

REF: rediriger un sous-domaine avec une expression régulière dans nginx

Drakes
la source
0
if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}
karadayi
la source
-6

Si vous rencontrez des difficultés pour que cela fonctionne, vous devrez peut-être ajouter l'adresse IP de votre serveur. Par exemple:

server {
listen XXX.XXX.XXX.XXX:80;
listen XXX.XXX.XXX.XXX:443 ssl;
ssl_certificate /var/www/example.com/web/ssl/example.com.crt;
ssl_certificate_key /var/www/example.com/web/ssl/example.com.key;
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}

où XXX.XXX.XXX.XXX est l'adresse IP (évidemment).

Remarque: crs SSL et l'emplacement des clés doivent être définis pour rediriger correctement les demandes https

N'oubliez pas de redémarrer nginx après avoir effectué les modifications:

service nginx restart
défaire
la source
3
/etc/init.d/nginx reloadvous pouvez aussi reloadle serveur qui ne cause aucun temps d'arrêt.
TheBlackBenzKid