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$;
...
}
当按名称搜索虚拟服务器时,如果名称匹配多个指定的名称,例如,通配符名称和正则表达式名称都匹配,第一个匹配的名称将被选择,优先顺序如下:
- 精确的名称
- 以
*
开头的最长的通配符名称,例如*.example.org
- 以
*
结尾的最长的通配符名称,例如mail.*
- 第一个匹配的正则表达式名称(按配置文件中出现的顺序排列)
通配符名称
通配符名称只能在名称的开始或结束处包含星号,并且只能在点符号.
的旁边。名称www.*.example.org
和w*.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 "。分组捕获也可以以数字形式使用:
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; # пример.испытание
...
}
虚拟服务器的选择
首先,在默认的服务器上下文中创建连接。然后,可以在以下请求处理阶段确定服务器名,每个阶段都涉及服务器配置选择:
- 在SSL握手时,提前,根据SNI
- 在处理请求行之后
- 在处理Host报头字段之后
- 如果在处理请求行或者Host报头字段后没有确定服务器名,nginx将使用空的名称作为服务器名。
在每个阶段,可以应用不同的服务器配置。因此,某些指令应谨慎指定:
- 在ssl_protocols指令的情况下,协议列表由OpenSSL库设置,然后根据SNI请求的名称应用服务器配置,因此,协议应该仅为默认服务器指定;
- 在读取请求行之前,涉及到client_header_buffer_size和merge_slashes指令,因此,此类指令使用默认的服务器配置或SNI选择的服务器配置;
- 在处理请求报头字段时,涉及到ignore_invalid_headers、large_client_header_buffers和underscores_in_headers指令,它还取决于服务器配置是否根据请求行或主机报头字段更新;
- 在当前执行请求的服务器中,error_page指令将处理错误响应。
优化
确切的名称、以星号开头的通配符名称和以星号结尾的通配符名称存储在绑定到侦听端口的三个散列表中。哈希表的大小在配置阶段进行了优化,以便在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必须执行该表达式来获取捕获。
兼容性
- 从0.9.4开始就支持特殊的服务器名称“$hostname”。
- 从0.8.48开始,默认的服务器名值为空名称“”。
- 自0.8.25以来,已支持命名正则表达式服务器名称捕获。
- 正则表达式服务器名称捕获从0.7.40开始支持。
- 自0.7.12以来,支持一个空的服务器名" "。
- 自0.6.25以来,支持使用通配符服务器名或正则表达式作为第一个服务器名。
- 正则表达式服务器名从0.6.7开始被支持。
example.*
这样的通配符形式从0.6.0开始支持。- 从0.3.18开始就支持特殊形式
.example.org
。 - 通配符形式
*.example.org
从0.1.13开始支持。
作者:Igor Sysoev
编辑:Brian Mercer
翻译:心蓝
欢迎来到testingpai.com!
注册 关于