40

我看到 Nginx HttpRewriteModule 文档有一个将 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 等,因为我有大量域要重写.

4

7 回答 7

62

如 Nginx 文档中所述,您应该尽可能避免if在 Nginx 中使用该指令,因为一旦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指令。

还有一个使用 SNI 的选项,但我不确定目前是否完全支持

于 2013-03-20T06:48:32.027 回答
15
if ($host !~* ^www\.) {
    rewrite ^(.*)$ http://www.$host$1 permanent;
}
于 2009-11-06T23:01:21.240 回答
14

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

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

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

于 2009-10-28T19:30:41.403 回答
6
if ($host ~* ^[^.]+\.[^.]+$) {
    rewrite ^(.*)$ https://www.$host$1 permanent;
}

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

于 2010-09-22T06:55:11.207 回答
4

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

于 2012-12-28T21:06:13.213 回答
1

不带 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 #
}
于 2019-03-24T01:12:19.757 回答
0

多个域的解决方案,为我在 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变量。

于 2019-07-11T15:55:20.920 回答