说明:“Nginx烂笔头”系列Blog是自己对Nginx官方文档的的翻译,用作阅读笔记便于日后查阅的成分居多,无关重要内容会删减,也可能会加入自己的理解。囿于个人水平,一些专业的名称翻译不会太准确,推荐查看Nginx官网原始文档。翻译内容如果有错误,欢迎指正。
本文翻译自Nginx官网Server names网页文档。
摘要
本文主要讲述了server指令块中server_name
指令的使用事项,主要为server_name
指令的精确命名、通配符命名、正则表达式命名和其他命名方法。
一、server_name指令命名方法总览
服务名称是使用server_name
指令定义的并决定了一个请求使用哪一个服务块来处理。可以参考How nginx processes a request。服务名可以使用一个确切的、通配符或者正则表达式来命名。
#确切地指定一个名称
server {
listen 80;
server_name example.org www.example.org;
...
}
#通配符命名
server {
listen 80;
server_name *.example.org;
...
}
#通配符命名2
server {
listen 80;
server_name mail.*;
...
}
#正则表达式命名
server {
listen 80;
server_name ~^(?<user>.+)\.example\.net$;
...
}
1.1 搜索规则
当nginx通过名称来搜索虚拟服务时,如果一个名称匹配到多个指定的服务块,例如,同时匹配上了通配符和正则表达式的,那nginx会按照下面优先级来选择最先匹配到的server块来处理这个请求:
1. 准确的名称
2. 以号开始最长的通配符命名
3. 以号结束最长的通配符命名
4. 第一个匹配到的正则表达式命名(按照在配置文件出现的先后顺序)
二、通配符命名
一个通配符名称可以在开始或结束包含号,也可以在“.”号之间。名称www.*.example.org```和```w*.example.org
都是正确的命名 。然而,这些名称也可以使用正则表达式来命名,例如,~^www\..+\.example\.org$
和~^w.*\.example\.org$
。一个号可以同时匹配上server name以“.”号分割的不同部分。*.example.org
可以同时匹配上www.example.org
和www.sub.example.org
这两个服务名称。
A special wildcard name in the form “.example.org” can be used to match both the exact name “example.org” and the wildcard name “*.example.org”.
三、正则表达式命名
3.1 使用规则
nginx使用的正则表达式和Perl语言使的(PCRE)是兼容的,server_name的参数必须以~
开头:
server_name ~^www\d+\.example\.net$;
否则,nginx会把参数视作一个准确的名称,如果表达式包含一个*号,则会被视作一个通配符命名方式。不要忘记^
和$
符号。他们在语法上不是必须的,但是在(nginx)逻辑上是必须的。同时注意,域名的“."符号需要使用反斜线进行转义。表达式里面如果有“{”和“}”需要用括号扩起来:
server_name "~^(?<name>\w\d{1,3}+)\.example\.net$";
否则,nginx会启动失败并抛出下面的错误信息
directive “server_name” is not terminated by “;” in …
3.2 表达式变量
正则表达式中的字段可以被捕获成一个变量,在接下来可以使用:
server {
server_name ~^(www\.)?(?<domain>.+)$;
location / {
root /sites/$domain;
}
}
PCRE库使在不同版本对变量捕获的语法支持:
- ? 兼容Perl 5.10语法,从PCRE-7.0开始支持
- ?’name’ 兼容Perl5.10语法,从PCRE-7.0开始支持
- ?P 兼容Pyton语法,从PCRE-4.0开始支持
如果ngins启动失败,并出现下面的错误信息:
pcre_compile() failed: unrecognized character after (?< in …
这说明PCRE库版本太旧,应该使用?P 语法。
捕获也可以使用数字的格式:
server {
server_name ~^(www\.)?(.+)$;
location / {
root /sites/$2;
}
}
但是,这种用法应该被限制在简单的例子中使用,比如上面的,因为数值应用容易被重写覆盖。
其他命名方式
有一些其他的命名方式被特殊对待。
在一个不是默认server块指令中需要处理不带“Host”请求头的请求,需要加上空名称:
server {
listen 80;
server_name example.org www.example.org "";
...
}
如果server指令块种没有指定server_name指令,nginx回默认用空字符串做server_name。
nginx在0.8.48前都是用机器的主机名作为服务名。
如果服务名被定义为"$hostname"(0.9.4),就回使用机器的主机名。
如果请求是使用ip的也可以配置在服务名种,nginx也会处理:
server {
listen 80;
server_name example.org
www.example.org
""
192.168.1.1
;
...
}
在下面的例子中会处理所有host的请求,你可以看到有一个“_”字符串:
server {
listen 80 default_server;
server_name _;
return 444;
}
名称没有特别之处,都是不合法的host之一。其他类似的不合法字符,如:“!@#”也可以使用。
nginx在0.6.25之前都支持特殊名称“*”,通常会被错误地认为是用来处理所有host请求地特殊名字。使用“*”从来不会起到处理所有host地作用,或者类似一个通配符名称。相反地,它提供了server_name_in_redirect
指令地功能。现在,“*”已经被弃用,应该使用server_name_in_redirect
指令来代替。需要注意的是,使用server_name
指令不能配置一个默认的server或者处理所有请求的server。可以查看How nginx processes a request.只能指定默认的host是默认由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表示:
server {
listen 80;
server_name xn--e1afmkfd.xn--80akhbyknj4f; # пример.испытание
...
}
优化
准确名称,以“*”号开头或结尾的通配符名称被存储在和端口绑定的3个哈希表中。哈希表的大小是可以使用配置文件来优化的,以减少CPU的未命中缓存时间来加快检索。具体可以查看此文档.
三张哈希表的优先顺序是:准确名称哈希表,“*号”开头的哈希表,“*号”结束的哈希表。
搜索通配符名称要比准确的名称慢因为是根据域名不分来检索的。需要注意的是特殊通配符“.example.com"是保存在通配符哈希表中的而不是准确名称哈希表中。
正则表达式会被顺序的匹配,所以是最慢的一个而且无法伸缩。
所以,如果可以最好使用准确的名称。例如:如果最频繁的访问是example.org和www.example.org,最有效率的配置是直接配置:
server {
listen 80;
server_name example.org www.example.org *.example.org;
...
}
比这样简单的配置要高效:
server {
listen 80;
server_name .example.org;
...
}
如果配置了很多server name或者很长的server name,那有必要通过http指令块中的server_name_hash_max_size
和server_names_hash_bucket_size
指令来调整哈希表的大小。server_names_hash_bucket_size
默认值是32或者64,取决于CPU的缓存页大小。如果值是32,但是server name过长,会报以下的错误:
could not build the server_names_hash,
you should increase server_names_hash_bucket_size: 32
此时,需要修改server_names_hash_bucket_size
,数值需为2的N次幂:
http {
server_names_hash_bucket_size 64;
...
}
如果过多server name会报下面的异常:
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_name_hash_max_size
的大小。
如果server只监听了一个端口,nginx完全就不会匹配server name了,也就不会创建三张哈希表。有个例外就是,当server name是正则表达式的时候还是会去匹配server name了。