【问题标题】:Nginx no-www to www and www to no-wwwNginx 非 www 到 www 和 www 到非 www
【发布时间】:2011-12-18 07:44:21
【问题描述】:

我正在使用nginx on Rackspace cloud following a tutorial 并且已经搜索了网络,但到目前为止无法排序。

出于 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。

【问题讨论】:

  • 我觉得有必要评论一下,如果您使用的是 WordPress 网站,请检查 Dashboard > Settings > General Settings 并确保 WordPress 地址/站点地址 URL 中没有 www。无论你如何配置你的 nginx,如果你在这些 URL 中有一个 www,它会被重定向到其中有 www 的那个。

标签: redirect ubuntu nginx rackspace no-www


【解决方案1】:

HTTP 解决方案

来自documentation,“正确的做法是为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;
       }
}

【讨论】:

  • @puk 感激不尽。 Nginx 很棒,但是与服务器版本、操作系统和服务器硬件变化保持同步的良好文档非常令人厌烦。为我服务的最佳资源是 howtoforge.com,因为它支持 RackSpace 云版本。上面的某些命令在以后的版本中不起作用。但是这个 nginx/0.8.54 - 相信我,最好的 nginx 服务器)不需要升级或更新。工作正常。每天有 100,000 次唯一点击,平均每天有 4200 次交易。 Nginx 是快速的。就像使用没有流量的网站一样。
  • 您的重写应该成为回报,如return 301 $scheme://domain.com$request_uri;。无需捕获任何模式,请参阅Nginx pitfalls
  • @TheBlackBenzKid 对不起,也许我错过了一些东西,但更新的解决方案不起作用。这是因为听 80 - 你说只有 HTTP 匹配这个。如果 HTTP 和 HTTPS 使用相同的配置,应该有更多的端口来监听……或者?但绝对帮助我,+1。谢谢你的答复。干杯。
  • @TheBlackBenzKid 只是请注意。我找到了可行的解决方案。在您的示例中,只应添加 Listen 443 并完成工作。
  • 答案是错误的。它将所有子域重定向到 www.
【解决方案2】:

其实你甚至不需要重写。

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。为什么?因为 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...
}

$scheme 变量将仅包含 http 如果您的服务器仅侦听端口 80(默认)并且侦听选项不包含 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...
}

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

更多我的配置?去herehere

【讨论】:

  • 如果您使用 HSTS,您的 Chrome 应该无法访问您的 www 域。请打开一个包含尽可能详细信息的新问题,我会为您提供帮助(您可以在此处将问题的 URL 作为评论发布)。
  • @Fleshgrinder 我正在尝试实施您的设置,但在stackoverflow.com/questions/29451409/… 遇到以下问题@关于如何使其工作的任何想法?
  • 在第二块“将非 SSL 和 SSL 都重定向到它们的非 www 对应物:”中,两个服务器块都应该有 SSL 指令,因为浏览器需要验证 www 的证书。 example.com 在重定向到 example.com 之前。
  • 当然,我添加了这一点以及关于 HSTS 的简短信息。
  • @YPCrumble 是的,这种方式要快得多,因为我们没有对每个请求执行正则表达式匹配。只有当我们知道必须重定向时,我们才会重定向。没有检查,没有验证,什么都没有:只是重定向。 =)
【解决方案3】:
  1. 最佳实践:使用硬编码 server_name 分隔 server

使用 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,此解决方案会变得很棘手,因为如果您希望它正常工作,您必须拥有一个证书来覆盖您的所有域名。


wwwwww 带有正则表达式,在专用单个server 中适用于所有网站:

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

www 到非www 带有正则表达式的专用单个server 用于所有站点:

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

www 到非www 带有正则表达式的专用server 仅适用于某些网站:

可能需要将正则表达式限制为仅涵盖几个域,然后您可以使用类似的内容仅匹配 www.example.orgwww.example.comwww.subdomain.example.net

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

使用 nginx 测试正则表达式

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

% 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 server name regex when "Host" header has a trailing dot 处理了它。


  1. 在现有的server/HTTPS 中添加if

这个最终解决方案通常不被认为是最佳实践,但是,它仍然有效并且可以完成工作。

事实上,如果您使用的是 HTTPS,那么最终的解决方案可能会更易于维护,因为您不必在不同的 server 定义之间复制粘贴一大堆 ssl 指令,并且可以而是仅将 sn-ps 放入所需的服务器中,从而更容易调试和维护您的站点。


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

参考资料:

【讨论】:

    【解决方案4】:

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

    在 sn-p 之后删除任何域之前的 www:

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

    【讨论】:

    • 我比专用服务器块更喜欢这种方式。将http 更改为$scheme
    • 好多了,不敢相信这么多人会为这项任务将域硬编码到配置中。
    • @Oli 该链接没有(截至今天)提到性能,而是它们不是 100% 安全的。它确实说“如果在位置上下文中,可以在内部完成的唯一 100% 安全的事情是:return ...rewrite ... last”。任何更新的性能问题链接?
    • 这对我不起作用。一直在浏览器上收到错误提示无效响应。
    • 不幸的是,我没有找到没有“if”的方法。我对许多域使用相同的配置,对域名进行硬编码不是一种选择。任何建议/意见表示赞赏!
    【解决方案5】:

    您需要两个服务器块。

    将这些放入您的配置文件中,例如/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 记录。

    【讨论】:

      【解决方案6】:

      以下是多个 www 到 no-www 服务器名称的操作方法(我将其用于子域):

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

      【讨论】:

        【解决方案7】:

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

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

        【讨论】:

          【解决方案8】:

          此解决方案来自我的个人经验。我们使用多个 Amazon S3 存储桶和一台服务器将 non-www 重定向到 www 域名以匹配 S3 "Host" header policy

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

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

          这匹配指向服务器的所有域名,但以www. 开头,并重定向到www.&lt;domain&gt;。以同样的方式,您可以从wwwnon-www 进行相反的重定向。

          【讨论】:

          • 那么 https 呢?注意:https 需要证书
          • 这里的HTTPS绝对没有问题。在listen 80 之后,您需要添加listen 443 ssl,然后是ssl_certificatessl_certificate_key 指令。
          • 现在没有人使用 http。我正在阅读 google 中列出的顶级指南,该指南仅显示了您的示例,其中添加了 listen 443 ssl 缺少证书的行。这不会起作用,而且会引起一些严重的头痛。
          • 我不知道你在说什么指南。我有这个配置成功地工作了近三年。去年我添加了对 SSL 的支持,它按预期工作。当然,您需要有一个带有私钥的证书。
          • 所以这会破坏除 www 之外的所有子域,对吗?
          【解决方案9】:

          试试这个

              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 语句,然后告诉人们避免使用它?对我来说听起来很轻率。
          • 上面写着“IF in location is evil”。您可以安全地将 if 放入您的服务器块中
          • 直接引用上述链接...如果在位置上下文中,唯一可以在内部完成的 100% 安全的事情是:返回...;重写...最后;
          【解决方案10】:

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

          【讨论】:

          • 你能区分80443吗?
          • 它似乎在没有 listen 指令的情况下对我有用(nginx 1.4.6)。
          【解决方案11】:

          独特的格式:

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

          【讨论】:

          • 你可以通过这样写来使其通用:server {server_name "~^www\.(.*)$" ;return 301 $scheme://$1$request_uri ;}
          【解决方案12】:

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

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

          参考号:Redirecting a subdomain with a regular expression in nginx

          【讨论】:

          • 糟糕的解决方案!
          【解决方案13】:
          location / { 
              if ($http_host !~ "^www.domain.com"){ 
                  rewrite ^(.*)$ $scheme://www.domain.com/$1 redirect; 
              } 
          }
          

          【讨论】:

          • $scheme://www.domain.com$1 避免双斜线
          【解决方案14】:

          不确定是否有人注意到返回 301 可能是正确的,但浏览器却无法做到这一点

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

          比:

          return 301 $scheme://yoursite.com$request_uri;
          

          【讨论】:

          【解决方案15】:

          幽灵博客

          为了使带有return 301 $scheme://example.com$request_uri; 的 nginx 推荐方法与 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;  
          

          【讨论】:

            【解决方案16】:
            if ($host ~* ^www.example.com$) {
                return 301 $scheme://example.com$request_uri;
            }
            

            【讨论】:

              【解决方案17】:

              如果您无法正常工作,您可能需要添加服务器的 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
              

              【讨论】:

              • /etc/init.d/nginx reload 你也可以reload 服务器,不会导致任何停机。
              猜你喜欢
              • 2015-02-13
              • 2019-01-28
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-03-10
              • 2014-12-16
              • 2016-04-02
              相关资源
              最近更新 更多