nginx:重定向到非www,包括所有子域

时间:2019-01-20 17:41:40

标签: nginx redirect server url-rewriting no-www

这个问题已经以各种方式问了一百万遍。我仍然找不到足够通用的答案来涵盖所有情况。

我想要的是从任何传入URL中删除www,并将其应用于所有子域。这是我的Nginx配置,否则可以正常工作:

# redirect HTTP to HTTPS, no www
server {
    listen      80;
    listen [::]:80;

    server_name ~^(?<www>www\.)(?<subdomain>.+)\.example\.com$;

    # redirect
    return 301 https://${subdomain}.example.com$request_uri;
}

#redirect HTTPS www to non-www
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name ~^(?<www>www\.)(?<subdomain>.+)\.example\.com$;

    # ssl config...

    # redirect
    return 301 https://${subdomain}.example.com$request_uri;
}

#default server
server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    server_name example.com *.example.com;

    # other calls below this point include
    # root dir
    # ssl config
    # security headers
    # various location blocks, specific to my project
    # error page
    # error/access logs...
}

所有这些映射都可以通过上面的配置很好地处理:

  • http://example.com-> https://example.com
  • http://client1.example.com-> https://client1.example.com
  • http://dev.client1.example.com-> https://dev.client1.example.com
  • http://stage.client1.example.com-> https://stage.client1.example.com

但是这些不是:

  • http://www.example.com-> https://example.com
  • http://www.client1.example.com-> https://client1.example.com
  • http://www.dev.client1.example.com-> https://dev.client1.example.com

您能帮助我了解我需要在配置中进行哪些更改或如何对其进行调试吗?

1 个答案:

答案 0 :(得分:0)

对于http块:

由于HSTS,仅为首次访问的客户提供服务。因此,您可以使用简单的重定向并在https块中执行www.删除。

例如:

server {
    listen      80;
    listen [::]:80;
    return 301 https://$host$request_uri;
}

如果要在此阶段删除www.前缀,则需要一个始终匹配的正则表达式。

例如:

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

有关详细信息,请参见this document


对于https块:

您需要一个正则表达式来捕获www.之后的那部分域名。您有两种选择:

使用两个server块(如现在所述),但不要在第二个块中放入通配符server_name语句。您可以使用其他正则表达式(例如server_name ~example\.com$;)或根本不使用server_name并将其设置为默认值。

例如:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name   ~^www\.(?<domain>.+)$;
    # ssl config...
    return 301 https://$domain$request_uri;
}
server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    # no server_name statement needed
    ...
}

或者使用单个server块,并使用$http_host语句测试if变量。

例如:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name  .example.com;

    if ($http_host ~ ~^www\.(.+)$) { return 301 https://$1$request_uri; }
    ...
}

有关if的使用,请参见this caution