nginx 虚拟服务名称详解 (翻译文档)

本贴最后更新于 780 天前,其中的信息可能已经斗转星移

nginx虚拟服务名称详解

服务器名是使用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库使用以下语法支持命名捕获:

如果nginx启动失败,并显示如下错误提示:

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

这意味着PCRE库是旧的,应该尝试改为语法“?P "。分组捕获也可以以数字形式使用:

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

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

然而,这种用法应该限于简单的情况(如上述),因为数字引用很容易被覆盖。

其他名称

有一些服务名称被特殊对待。如果需要处理服务器块中没有" Host "报头字段的请求,这不是默认值,应该指定一个空的名称:

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

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

0.8.48之前的Nginx版本使用机器的主机名作为服务器名

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

如果某人使用IP地址而不是服务器名发出请求,“Host”请求报头字段将包含IP地址,可以使用IP地址作为服务器名处理请求:

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

catch-all的例子中我们可以看到特殊名称_

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

这个名字没什么特别的,它只是无数无效域名中的一个,永远不会与任何真实名称相交。其他无效的名称如__!@#也同样适用。Nginx版本到0.6.25都支持特殊名称*,它被错误地解释为一个catch-all名称。它从未作为catch-all或通配符服务器名。相反,它提供了现在由server_name_in_redirect指令提供的功能。特殊名称*现在已弃用,应该使用server_name_in_redirect指令。

名称国际化

国际化域名(idn)应该在server_name指令中用ASCII (Punycode)表示来指定:

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

虚拟服务器的选择

首先,在默认的服务器上下文中创建连接。然后,可以在以下请求处理阶段确定服务器名,每个阶段都涉及服务器配置选择:

在每个阶段,可以应用不同的服务器配置。因此,某些指令应谨慎指定:

优化

确切的名称、以星号开头的通配符名称和以星号结尾的通配符名称存储在绑定到侦听端口的三个散列表中。哈希表的大小在配置阶段进行了优化,以便在CPU缓存缺失最少的情况下找到名称。建立哈希表的详细信息在一个单独的文档中提供。

首先搜索确切的名字哈希表。如果没有找到名称,则搜索通配符名称以星号开头的散列表。如果在那里没有找到名称,则搜索以星号结尾的通配符名称的散列表。

搜索通配符名称哈希表比搜索精确名称哈希表慢,因为名称是按域名部分搜索的。注意,特殊的通配符形式“.example.org”存储在通配符名称哈希表中,而不是精确名称哈希表中。

正则表达式是按顺序测试的,因此是最慢的方法,而且是不可伸缩的。

由于这些原因,在可能的情况下最好使用确切的名称。例如,如果服务器中被请求次数最多的名称是example.org和www.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_size和server_names_hash_bucket_size指令。根据CPU缓存行大小的不同,server_names_hash_bucket_size指令的默认值可以是32、64或其他值。如果默认值是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根本不会测试服务器名称(并且不会为侦听端口构建哈希表)。然而,有一个例外。如果服务器名是带有捕获的正则表达式,那么nginx必须执行该表达式来获取捕获。

兼容性

作者:Igor Sysoev

编辑:Brian Mercer

翻译:心蓝

原文地址

回帖
请输入回帖内容 ...