服务器名称

服务器名称是使用 server_name 指令定义的,它确定了哪一个 server 块被给定的请求所使用。另请参见 nginx 如何处理请求。可以使用精确的名称、通配符或者正则表达式来定义他们:

server {
    listen       80;
    server_name  example.org  www.example.org;
    ...
}

server {
    listen       80;
    server_name  *.example.org;
    ...
}

server {
    listen       80;
    server_name  mail.*;
    ...
}

server {
    listen       80;
    server_name  ~^(?<user>.+)\.example\.net$;
    ...
}

当通过名称搜索虚拟服务器时,如果名称与多个指定的变体匹配,例如通配符和正则表达式,则将按照优先顺序选择第一个匹配的变体:

  1. 精确的名称
  2. 以星号开头的最长的通配符名称,例如 *.example.org
  3. 以星号结尾的最长的通配符名称,例如 mail.*
  4. 第一个匹配的正则表达式(按照在配置文件中出现的顺序)

通配符名称

通配符名称只能在名称的开头或者结尾包含一个星号,且只能在点的边界上包含星号。这些名称为 www.*.example.orgw*.example.org 都是无效的。然而,可以使用正则表达式指定这些名称,例如,~^www\..+\.example\.org$”~^w.*\.example\.org$。星号可以匹配多个名称部分。名称 *.example.org 不仅匹配了 www.example.org,还匹配了 www.sub.example.org

可以使用 .example.org 形式的特殊通配符名称来匹配确切的名称 example.org 和 通配符 *.example.org

正则表达式名称

nginx 使用的正则表达式与 Perl 编程语言(PCRE)使用的正则表达式兼容。要使用正则表达式,服务器名称必须以波浪符号开头:

server_name  ~^www\d+\.example\.net$;

否则将被视为确切的名称,或者如果表达式中包含星号,将被视为通配符名称(并且可能是无效的)。别忘了设置 ^$ 锚点。它们在语法上不是必须的,但在逻辑上是需要的。还要注意的是,域名的点应该使用反斜杠转义。正则表达式中的 {} 应该被引号括起:

server_name  "~^(?<name>\w\d{1,3}+)\.example\.net$";

否则 nginx 将无法启动并且显示错误信息:

directive "server_name" is not terminated by ";" in ...

正则表达式名称捕获到的内容可以作为变量为后面所用:

server {
    server_name   ~^(www\.)?(?<domain>.+)$;

    location / {
        root   /sites/$domain;
    }
}

PCRE 库使用以下语法捕获名称:

  • ?<name> Perl 5.10 兼容语法,自 PCRE-7.0 起支持
  • ?'name' Perl 5.10 兼容语法,自 PCRE-7.0 起支持
  • ?P<name> Python 兼容语法,自 PCRE-4.0 起支持

如果 nginx 无法启动并且显示错误信息:

pcre_compile() failed: unrecognized character after (?< in ...

说明 PCRE 库比较老,应该尝试使用语法 ?P<name>。捕获也可以使用数字形式:

server {
    server_name   ~^(www\.)?(.+)$;

    location / {
        root   /sites/$2;
    }
}

然而,这种方式仅限于简单情况(如上所述),因为数字引用容易被覆盖。

其他名称

有一些服务器名称需要被特别处理。

如果需要处理一个在不是默认的 server 块中的没有 Host 头字段的请求,应该指定一个空名称:

server {
    listen       80;
    server_name  example.org  www.example.org  "";
    ...
}

如果 server 块中没有定义 server_name,那么 nginx 将使用空名称作为服务器名。

此情况下,nginx 的版本到 0.8.48 使用机器的主机名作为服务器名称。

如果服务器名称被定义为 $hostname(0.9.4),则使用机器的主机名。

如果有人使用 IP 地址而不是服务器名称来发出请求,则 Host 请求 header 域将包含 IP 地址,可以使用 IP 地址作为服务器名称来处理请求。

server {
    listen       80;
    server_name  example.org
                 www.example.org
                 ""
                 192.168.1.1
                 ;
    ...
}

在所有的服务器示例中,可以发现一个奇怪的名称 _

server {
    listen       80  default_server;
    server_name  _;
    return       444;
}

这个名称没有什么特别之处,它只是众多无效域名中的一个,它永远不会与任何真实的名称相交。此外还有其他无效的名称,如 --!@# 也是如此。

nginx 到 0.6.25 版本支持特殊的名称 *,这常被错误地理解为所有名称。它并不是所有或者通配符服务器名称。相反,它的功能现在是由 server_name_in_redirect 指令提供。现在不推荐使用特殊的名称 *,应该使用 server_name_in_redirect 指令。请注意,无法使用 server_name 指令来指定所有名称或者默认服务器。这是 listen 指令的属性,而不是 server_name 的。请参阅 nginx 如何处理请求。可以定义监听 *:80*:8080 端口的服务器,并指定一个为 *:8080 端口的默认服务器,另一个为 *:80 端口的默认服务器。

server {
    listen       80;
    listen       8080  default_server;
    server_name  example.net;
    ...
}

server {
    listen       80  default_server;
    listen       8080;
    server_name  example.org;
    ...
}

国际化名称

应使用 server_name 指令中的ASCII(Punycode)表示来指定国际化域名(IDN

server {
    listen       80;
    server_name  xn--e1afmkfd.xn--80akhbyknj4f;  # пример.испытание
    ...
}

优化

确切的名称、以星号开头的通配符名称和以星号结尾的通配符名称被存储在绑定到监听端口的三种哈希表中。哈希表的大小可以在配置阶段优化,因此可以在 CPU 缓存未命中的最低情况下找到名称。设置哈希表的具体细节在单独的 文档 中提供。

首先搜索确切的名称哈希表。如果为找到名称,则会搜索以星号开头的通配符名称的哈希表。如果还是没有找到名称,则搜索以星号结尾的通配符名称哈希。

搜索通配符哈希表比搜索确切名称的哈希表要慢,因为名称是通过域部分搜索的。请注意,特殊通配符格式 .example.org 存储在通配符哈希表中,而不是确切名称哈希表中。

由于正则表达式是按顺序验证的,因此是最慢的方法,并且是不可扩展的。

由于这些原因,最好是尽可能使用确切的名称。例如,如果最常见被请求的服务器名称是 example.orgwww.example.org,则明确定义它们是最有效的:

server {
    listen       80;
    server_name  example.org  www.example.org  *.example.org;
    ...
}

简化形式:

server {
    listen       80;
    server_name  .example.org;
    ...
}

如果定义了大量的服务器名称,或者定义了非常长的服务器名称,则可能需要调整 http 级别的 server_names_hash_max_sizeserver_names_hash_bucket_size 指令。server_names_hash_bucket_size 指令的默认值可能等于 32 或者 64 或者其他值。具体取决于 CPU 超高速缓存储器线的大小。如果默认值为 32,并且服务器名称定义为 too.long.server.name.example.org,则 nginx 将无法启动并显示错误信息:

could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32

在这种情况下,指令值应该增加到 2 倍:

http {
    server_names_hash_bucket_size  64;
    ...

如果定义了大量的服务器名称,则会显示另一个错误信息:

could not build the server_names_hash,
you should increase either server_names_hash_max_size: 512
or server_names_hash_bucket_size: 32

在这种情况下,首先尝试将 server_names_hash_max_size 设置为接近服务器名称数量的数值。如果这样没有用,或者如果 nginx 的启动时间长的无法忍受,那么请尝试增加 server_names_hash_bucket_size 的值。

如果服务器是监听端口的唯一服务器,那么 nginx 将不会验证服务器名称(并且不会为监听端口建立哈希表)。但是,有一个例外。如果服务器名称具有捕获(captures)的正则表达式,则 nginx 必须执行表达式才能获取捕获。

兼容性

  • 自 0.9.4 起,支持特殊的服务器名称 $hostname
  • 自 0.8.48 起,默认服务器名称的值为空名称 ""
  • 自 0.8.25 其,已经支持命名的正则表达式服务器名称捕获。
  • 自 0.7.40 起,支持正则表达式名称捕获。
  • 自 0.7.12 起,支持空的服务器名称 ""
  • 自 0.6.25 起,支持使用通配符服务器名称和正则表达式作为第一服务器名称。
  • 自 0.6.7 起,支持正则表达式服务名称。
  • 自 0.6.0 起,支持类似 example.* 的通配符。
  • 自 0.3.18 起,支持类似 .example.org
  • 自 0.1.13 起,支持类似 *.example.org 的通配符。

Igor Sysoev 书写,由 Brian Mercer 编辑

最后编辑: kuteng  文档更新时间: 2021-11-01 16:44   作者:kuteng