【问题标题】:Nginx rewrite non-www-prefixed domain to www-prefixed domainNginx 将非 www 前缀的域重写为 www 前缀的域
【发布时间】:2010-12-10 09:31:26
【问题描述】:

我看到 Nginx HttpRewriteModule documentation 有一个示例,可以将 www 前缀的域重写为非 www 前缀的域:

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

我该如何做相反的事情——将非 www 前缀的域重写为 www 前缀的域?我想也许我可以执行以下操作,但 Nginx 不喜欢嵌套的 if 语句。

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

此外,我希望它适用于任何域名,而无需明确告诉 Nginx 重写 domain1.com -> www.domain1.com、domain2.com -> www.domain2.com 等,因为我有大量要重写的域。

【问题讨论】:

    标签: nginx rewrite url-rewriting


    【解决方案1】:

    As noted in the Nginx documentation, you should avoid using the if directive in Nginx where possible,因为一旦您的配置中有if,您的服务器就需要评估每个请求,以决定是否匹配if

    更好的解决方案是多个服务器指令。

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

    如果您尝试为启用 SSL (HTTPS) 的网站提供服务,您或多或少有三种不同的选择。

    1. 设置多个 IP 地址,让每个服务器指令监听它们自己的 IP(或不同的端口,如果您愿意的话)。此选项需要 website.comwww.website.com 的 SSL 证书,因此您要么拥有通配符证书、UNI 证书(多个域),要么只是简单地两个不同的证书。
    2. 在应用程序中进行重写。
    3. 使用可怕的if 指令。

    There is also an option to use SNI, but I'm not sure this is fully supported as of now.

    【讨论】:

    • 此解决方案的另一个好处是发回 HTTP 301 Moved Permanently 响应状态代码。这是一个高效、优雅且易读的解决方案。谢谢!
    【解决方案2】:
    if ($host !~* ^www\.) {
        rewrite ^(.*)$ http://www.$host$1 permanent;
    }
    

    【讨论】:

    【解决方案3】:

    好吧,我想我真的不需要外部的“if”语句,因为无论如何我只检查 xxx.xxx 形式的域。以下内容对我有用,尽管它并不强大。让我知道是否有更好的解决方案。

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

    编辑:向正则表达式添加连字符,因为它是主机名中的有效字符。

    【讨论】:

    【解决方案4】:
    if ($host ~* ^[^.]+\.[^.]+$) {
        rewrite ^(.*)$ https://www.$host$1 permanent;
    }
    

    只能获取有效的主机名,否则请求将永远无法到达您的服务器,因此无需构建您自己的验证逻辑。

    【讨论】:

    【解决方案5】:

    nginx 文档警告不要使用 if 进行重写。请在此处查看链接:http://wiki.nginx.org/Pitfalls#Server_Name

    【讨论】:

      【解决方案6】:

      不带 if 条件的 HTTP 和 HTTPS:

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

      【讨论】:

        【解决方案7】:

        多域解决方案,为我在 nginx 1.17 上工作:

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

        在此配置示例中,如果您不想重写,则另外在 HTTPS 上重写 HTTP — 将 return 字符串中的 https:// 替换为 http://。

        如果你想保持协议 - 使用 $scheme 变量。

        【讨论】:

        • @NicolasDusart :D 是的,对不起。一开始我想发布另一个配置示例,但它不能正常工作,所以我发布了这个(如果),但不要编辑评论文本。
        • @NicolasDusart 但至少这个例子对多个服务器名称是正确的。
        猜你喜欢
        • 1970-01-01
        • 2015-12-29
        • 2013-06-24
        • 1970-01-01
        • 2020-12-31
        • 1970-01-01
        • 1970-01-01
        • 2011-01-13
        • 2014-03-04
        相关资源
        最近更新 更多