Nginx从无到www到www和www到无www


497

按照教程在Rackspace云上使用nginx,并且已经在网上搜索,到目前为止无法进行排序。

由于SEO和其他原因,我希望www.mysite.com在.htaccess中像往常一样转到mysite.com。

我的/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;
       }

我也尝试过

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;
       }

我也试过了。第二次尝试都给出了重定向循环错误。

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

我的DNS已作为标准设置:

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

(示例IP和文件夹已用于示例,并在将来为人们提供帮助)。我使用Ubuntu 11。


1
我不得不评论一下,如果您使用的是WordPress网站,请检查Dashboard > Settings > General Settings并确保wwwWordPress地址/站点地址URL中没有任何内容。无论您如何配置nginx,如果在这些URL中都有一个www,它将被重定向到其中带有www的网址。
Abhinav Sood

Answers:


792

HTTP解决方案

文档中,“正确的方法是为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;
    ...
}

HTTPS解决方案

对于那些谁想要解决方案,包括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...

        }
}

注意:https://由于我们使用负载均衡器,并且我们的https://服务器是高流量SSL付款服务器,因此我最初并未包含在解决方案中:我们不将https://和http://混合使用。


要检查nginx版本,请使用nginx -v

使用nginx重定向从URL中删除www

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

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

因此,您需要两个服务器代码。

使用Nginx重定向将www添加到URL

如果您需要的是相反的方法,则可以使用以下方法将域名从domain.com重定向到www.domain.com:

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#
}

可以想象,这恰好相反,并且与第一个示例的工作方式相同。这样,您就不会降低SEO标记,因为它完全是烫发重定向和移动。禁止WWW,并显示目录!

我的一些代码如下所示,以便更好地查看:

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;
       }
}

3
@puk感激不尽。Nginx令人惊叹,但是优秀的文档却与服务器版本以及操作系统和服务器硬件的变化保持同步,非常累人。支持我的最佳资源是howtoforge.com,因为它支持RackSpace云版本。上面的某些命令在更高版本中不起作用。但是这个nginx / 0.8.54-相信我,最好的nginx服务器)不需要升级或更新。工作良好。每天有100,000次唯一匹配,平均每天有4200笔交易。Nginx是RAPID。例如使用无流量的网站。
TheBlackBenzKid 2011年

17
您的重写应成为return,如中所示return 301 $scheme://domain.com$request_uri;。无需捕获任何模式,请参阅Nginx陷阱
罗伯托(Roberto)

4
@TheBlackBenzKid对不起,也许我错过了一些东西,但是更新的解决方案无法正常工作。这是因为听80-就是说,只有HTTP与此匹配。如果对HTTP和HTTPS使用相同的配置,应该有更多的端口可以监听...或者?但是绝对可以帮助我+1。谢谢您的回复。干杯。
tomis

3
@TheBlackBenzKid只是注意。我找到了可行的解决方案。在您的示例中,仅应添加Listen 443并完成工作。
tomis

2
答案是错误的。它将所有子域重定向到www。
r3wt

398

实际上,您甚至不需要重写。

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...
}

我的回答是越来越多的投票,但以上情况也是如此。rewrite在这种情况下,您永远不要使用a 。为什么?因为nginx必须处理并开始搜索。如果您使用return(应该在任何Nginx版本中可用),它将直接停止执行。在任何情况下,这都是首选。

将非SSL和SSL都重定向到其非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...
}

$schemehttp当服务器仅在端口80上侦听(默认值)并且listen选项不包含ssl关键字时,该变量才会包含。不使用该变量将不会获得任何性能。

请注意,如果您使用HSTS,则需要更多的服务器块,因为HSTS标头不应通过非加密连接发送。因此,您需要具有重定向的未加密服务器块和具有重定向和HSTS标头的加密服务器块。

将所有内容重定向到SSL(在UNIX上使用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...
}

我猜您现在可以自己想象具有这种模式的其他化合物。

更多我的配置?去这里这里


3
如果您使用的是HSTS,那么Chrome浏览器将无法访问您的www域。请打开一个新问题,并提供尽可能多的详细信息,我们将为您提供帮助(您可以在此处将问题的URL发布为评论)。
Fleshgrinder 2014年

1
@Fleshgrinder我正在尝试实施您的设置,但在stackoverflow.com/questions/29451409 / ...上遇到以下问题:关于如何使其工作的任何想法?
YPCrumble 2015年

4
在第二个块“将非SSL和SSL都重定向到其非www副本:”中,两个服务器块均应具有SSL指令,因为浏览器需要在重定向到example之前验证www.example.com的证书。 .com。
Jeff Tsay 2015年

1
当然,我添加了该内容以及有关HSTS的简短信息。
Fleshgrinder

1
@YPCrumble是的,这种方式要快得多,因为我们不在每个请求上执行正则表达式匹配。仅当我们知道必须重定向时,我们才会重定向。没有检查,没有验证,什么也没有:只是重定向。=)
Fleshgrinder

37

您可能会发现要对更多域使用相同的配置。

以下代码段会在任何域之前删除www:

if ($host ~* ^www\.(.*)$) {
    rewrite / $scheme://$1 permanent;
}

7
我比专用服务器块更喜欢这种方式。更改http$scheme
ck_ 2015年

2
更好的是,不敢相信会有这么多人将域硬编码到此任务的配置中。
MrYellow 2015年

1
@Oli该链接(截至今天)没有提到性能,而是说它们不是100%安全的。它确实说:“如果在位置上下文中,可以在内部完成的唯一100%安全的事情是:return ...rewrite ... last”。是否有任何有关性能问题的更新链接?
亚当

1
这对我不起作用。继续在浏览器上显示错误消息,指出响应无效。
Nico Brenner

1
不幸的是,如果没有“ if”,我找不到办法。我对许多域使用相同的配置,对域名进行硬编码不是一种选择。任何建议/评论表示赞赏!
马丁·霍格(MartinHöger)

27

您需要两个服务器块。

将这些放入您的配置文件中,例如 /etc/nginx/sites-available/sitename

假设您决定使用http://example.com作为主要地址。

您的配置文件应如下所示:

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
}

第一个服务器块将保存指令以重定向任何带有“ www”前缀的请求。它侦听带有“ www”前缀的URL请求并重定向。

它什么也没做。

第二个服务器块将保留您的主要地址,即您要使用的URL。所有其他设置在这里,比如去rootindexlocation,等检查的默认文件对这些设置,您可以包括在服务器块。

服务器需要两个DNS A记录。

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

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

对于ipv6,请使用your-ipv6-address创建一对AAAA记录。


23

这是针对多个www到no-www服务器名称的方法(我将其用于子域):

server {
        server_name 
             "~^www\.(sub1.example.com)$"
             "~^www\.(sub2.example.com)$"
             "~^www\.(sub3.example.com)$";
         return 301 $scheme://$1$request_uri ;
}

19
  1. 最佳做法:单独进行server硬编码server_name

nginx的最佳实践是对server这样的重定向使用单独的名称(不与server主配置共享),对所有内容进行硬编码,并且完全不使用正则表达式。

如果您使用的是HTTPS,则可能还需要对域进行硬编码,因为您必须预先知道要提供的证书。

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. 在内部使用正则表达式 server_name

如果您有多个站点,并且不希望获得最高的性能,但是希望每个站点在www.前缀方面都具有相同的策略,则可以使用正则表达式。使用单独的最佳实践server仍然有效。

请注意,如果您使用https,则此解决方案会很棘手,因为如果您希望此方法正常运行,则必须具有一个证书来覆盖所有域名。


wwwwwwW /在一个专用的单正则表达式server的所有网站:

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

wwwwww专用server于所有站点的非w /正则表达式:

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

wwwwww专用server于某些网站的非w /正则表达式:

这可能是必要的限制正则表达式覆盖只有一对夫妇域,那么你可以使用这样的事情只匹配www.example.orgwww.example.com并且www.subdomain.example.net

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

使用nginx测试正则表达式

您可以测试正则表达式是否可以pcretest在您的系统上正常工作,这与pcre您的nginx用于正则表达式的库完全相同:

% 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> 

请注意,您不必担心尾随点或大小写,因为nginx已经处理了它,根据“主机”标头中包含尾随点的nginx服务器名称regex


  1. 散布if在现有server/ HTTPS中:

最终解决方案通常不被视为最佳实践,但是,它仍然可以正常工作。

实际上,如果您使用的是HTTPS,那么最终的解决方案可能最终更易于维护,因为您不必在不同的server定义之间复制粘贴一堆ssl指令,而只需将代码段放入所需的服务器,从而使调试和维护站点变得更加容易。


wwwwww

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

www到非www

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

硬编码单个首选域

如果您希望获得更高的性能以及单个域server可以使用的多个域之间的一致性,则明确地对单个首选域进行硬编码可能仍然有意义:

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

参考文献:


16

此解决方案来自我的个人经验。我们使用了多个Amazon S3存储桶和一台服务器重定向non-wwwwww域名,以匹配S3“主机”标头策略

我对nginx服务器使用了以下配置:

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

该名称与指向服务器的所有域名匹配,但开头不是,www.然后重定向到www.<domain>。您可以通过相同的方式执行从www到的相反重定向non-www


那https呢?注意:https 需要证书
Toskan

这里的HTTPS绝对没有问题。之后listen 80需要添加listen 443 ssl然后再ssl_certificatessl_certificate_key指令。
VisioN

如今没有人使用http。我正在阅读google中排名第一的指南,该指南仅通过添加listen 443 ssl 缺少证书的行显示了您的示例。那将行不通,并引起一些严重的头痛。
Toskan

我不知道您在说什么指南。我已经使这种配置成功运行了近三年。去年,我添加了对SSL的支持,它可以按预期运行。当然,您需要拥有一个带有私钥的证书。
VisioN

所以这会破坏除www之外的所有子域,对吗?
传记作者

15

我结合了所有简单答案中最好的一个,没有硬编码的域。

301从非www永久重定向到www(HTTP或HTTPS):

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

    # Regular location configs...
}

如果您更喜欢非HTTPS,非www而不是HTTPS,则www会同时重定向:

server {
    listen 80;

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

    rewrite ^ https://$host$request_uri permanent;
}

11

将非www重定向到www

对于单个域:

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

对于所有域:

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

将www重定向到非www 对于单个域:

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

对于所有域:

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

您能否区分80和之间443
哈桑·贝格

1
它对listen我来说似乎没有指令即可工作(nginx 1.4.6)。
易卜拉欣

11

尝试这个

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

其他方式:Nginx no-www到www

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

和www到没有www

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

作者为什么在nginx中提供if语句,然后告诉人们避免使用它?听起来对我很客气。
Greg Smethells

4
有人说:“如果地点是邪恶的”。您可以放心地将其放入服务器块
Kukunin 2015年

从上面的链接直接引出...如果在位置上下文中,则可以在内部完成的唯一100%安全的事情是:return ...; 改写...最后;
贾斯汀E

8

独特格式:

server {
  listen 80;
  server_name "~^www\.(.*)$" ;
  return 301 https://$1$request_uri ;
}

1
您可以通过以下方式使其通用: server { server_name "~^www\.(.*)$" ; return 301 $scheme://$1$request_uri ; }
Ramast



2

鬼博客

为了使Nginx建议的方法return 301 $scheme://example.com$request_uri;可以与Ghost 一起使用,您需要在主服务器块中添加:

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;  

2

如果您不想对域名进行硬编码,则可以使用此重定向块。没有前导www的域将另存为变量$domain,可以在重定向语句中重用。

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

REF:使用Nginx中的正则表达式重定向子域


0
if ($host ~* ^www.example.com$) {
    return 301 $scheme://example.com$request_uri;
}

-6

如果您无法正常工作,则可能需要添加服务器的IP地址。例如:

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;
}

其中XXX.XXX.XXX.XXX是IP地址(显然)。

注意:必须定义ssl crt和密钥位置才能正确重定向https请求

进行更改后,请不要忘记重启nginx:

service nginx restart

3
/etc/init.d/nginx reload您也可以reload使用不会造成任何停机时间的服务器。
TheBlackBenzKid 2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.