英文文档对应页面:Server names
主机名
服务器名称被定义用于 “server_name” 指令,决定了请求将使用哪一个 “server”块。可以使用 “准确的名称”,“通配符名称”,“正则表达式名称” 来定义服务器名称:
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$;
}
当通过name搜索一个虚拟主机,如果name匹配到多于一个的变体类型,例如:同时匹配到了“通配符”&“正则表达式”,将会选择第一个匹配到的变体类型,按照下面的优先次序:
1.准确的名称
2.以*开头的最长的通配符名称,例如:*.example.org
3.以*结尾的最长的通配符名称,例如:mail.*
4.第一个匹配到的正则表达式名称(在配置文件中出现的顺序依次匹配)
通配符名称
通配符名称,可能包含一个*,只能在名称的开始或者结尾,而且只能以一个"."为边界。“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),支持Perl正则。使用正则表达式,服务器名称必须以一个“~”开头,例如:server_name ~^www\d+\.example\.net$;
否则,它将被当作一个“准确的名称”,或者如果表达式中包含一个“*”,将被当作一个“通配符名称”(很可能是一个无效的通配符名称)。别忘记设置“^”和“$”符号,它们并非是语法上需要,而是逻辑上需要。还得注意:域名中的“.”,应该添加上反斜线“\.”。包含“{”和“}”字符的正则表达式,应该使用"",引起来:
server_name "~^(?<name>\w\d{1,3}+)\.example\.net$";
否则,nginx将启动失败,并报错:
directive "server_name" is not terminated by ";" in ...
一个命名的正则表达式捕获(capture),在之后可以当作变量来调用(自己定义向后匹配的名称):
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
root /sites/$domain;
}
}
PCRE库,使用如下语法,支持命名捕获:
?<name> - Perl5.10兼容性语法,PCRE-7.0以后支持
?'name' - Perl5.10兼容性语法,PCRE-7.0以后支持
?P<name> - Python兼容性语法,PCRE-4.0以后支持
如果nginx启动失败,将报错:
pcre_compile() failed: unrecognized character after (?< in ...
这意味着:PCRE库是老版本,并且语法“?P<name>”应该尝试被替换。捕获(capture)也可以以数字形式被调用(这就是我们正则中一般使用的向后匹配):
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版本,使用机器主机名(machine's hostname),作为服务器名称。
如果服务器名称,定义为:“$hostname”(0.9.4),表示使用“机器主机名”(machine's hostname)
如果客户使用 “IP地址” 代替服务器主机名访问,请求头的“Host”字段将包含IP地址,请求可以被使用 “IP地址作为服务器名称” 的 “server”块 来处理:
server {
listen 80;
server_name example.org
www.example.org
""
192.168.1.1// 使用IP作为服务器名称
;
}
在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”指令的值,而被使用。注意:使用“server_name”指令无法指定“catch-all”服务器名称或者默认服务器(default_server)。它们都是“listen”指令的属性,而不是“server_name”指令的属性(之前说过default_server,这里又多了一个catch-all)。同时定义监听在“*:80”和“*:8080”端口的服务器是可能的,一个作为默认服务器,另一个作为默认端口,例如:
server {
listen 80;
listen 8080 default_server;
server_name example.net;
}
server {
listen 80 default_server;
listen 8080;
server_name example.org;
}
优化
准确的名称,以*开头的通配符名称以及以*结尾的通配符名称,存储在绑定在监听端口的3个hash表中。在配置指令中,hash表的尺寸被优化,目的是:使用最少的CPU缓存失败率,去检索主机名。准确的名称的hash表首先被检索。如果没有发现名称,检索以*开头的通配符名称的hash表,最后检索以*结尾的通配符名称的hash表。
检索通配符名称的hash表比检索准确名称的hash表要慢,因为,使用部分域名检索。注意:特殊形式的通配符“.example.org”存储在一个通配符名称的hash表中,而不在准确名称的hash表中。
正则表达式是顺序测试,因此是最慢的方法,也是不可扩展的。
针对以上原因,尽可能使用准确的名称。例如:最频繁请求的服务器名称是“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 level” 里的“server_names_hash_max_size”和“server_names_hash_bucket_size”指令。默认“server_names_hash_bucket_size”指令的值可能是32,64,或是其他值,依赖CPU高速缓存的大小。如果默认值时32,并且服务器名称定义的很长,nginx可能启动失败,并报错:
could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32
在这种情况下,指令的值,应该增加到下一个更大的值,当前的2倍(每次增加,都应该以CUP高速缓存的整数倍增加):
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将不会检测服务器名称(而且不会为监听端口构建hash表)。然后,有一个例外。如果服务器名称是一个带有捕获(capture,向后引用)的正则表达式,nginx将不得不计算表达式去获取捕获(capture,向后引用)。