Nginx Document 总结(一)
写于2020年05月14日

Starting, Stopping, and Reloading Configuration

启动,停止和重载

格式

1
nginx -s signal
  • stop - 退出
  • quit - 优雅退出
  • reload - 重新加载配置文件
  • reopen - 重新打开日志文件

或者借助Unix工具(例如kill)向nginx进程发送指定信号

1
kill -s QUIT 1628

默认情况下,nginx主进程的进程ID将写入目录/usr/local/nginx/logs或/var/run中的nginx.pid文件

主进程支持以下信号:

  • TERM, INT - 退出
  • QUIT - 优雅退出
  • HUP - 重新加载配置文件(仅适用于FreeBSD和Linux)
  • USR1 - 重新打开日志文件
  • USR2 - 升级可执行文件
  • WINCH - 优雅关闭工作进程

虽然不是必需的,但是也可以通过信号控制单个工作进程。支持的信号是:

  • TERM, INT - 退出
  • QUIT - 优雅退出
  • USR1 - 重新打开日志文件
  • WINCH - 调试异常终止(需要启用debug_points)

Command-line parameters 命令行参数

nginx 命令支持以下命令行参数:

  • -? | -h 打印命令行工具帮助信息
  • -c file 指定配置文件
  • -g directives 设置全局全局配置指令,例如
    1
    nginx -g "pid /var/run/nginx.pid; worker_processes \`sysctl -n hw.ncpu\`;"
  • -p prefix 设置nginx路径前缀,即将保留服务器文件的目录(默认值为/usr/local/nginx)
  • -s signal 向主进程发送信号,如上
  • -t 检查配置文件语法是否正确
  • -T 类似-t参数,但还会向标准输出打印所有配置
  • -v 打印nginx版本
  • -V 打印nginx版本,编译器版本和配置参数

How nginx processes a request

nginx如何处理一个请求

Name-based virtual servers 基于名称的虚拟服务器

以下三个虚拟服务器都在80端口上侦听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name example.org www.example.org;
...
}

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

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

在此配置中,nginx会用请求头中的”Host”字段去匹配所有serverserver_name,用来确定应该将请求路由到哪个虚拟服务器中。如果”Host”字段值与所有server中的server_name都不匹配,则会将请求路由到请求端口(当前为80)默认的虚拟服务器。在上面的配置中,默认的虚拟服务器是从上到下配置的第一个server。这是nginx的默认行为。你可以使用listen指令中的default_server参数来明确设置哪个server应为默认的虚拟服务器。

1
2
3
4
5
server {
listen 80 default_server;
server_name example.net www.example.net;
...
}

注意
* 在0.8.21版本之前请使用default参数
* 参数default_serverlisten指令的参数,而不是server_name指令的参数

How to prevent processing requests with undefined server names

如何防止使用未定义的服务器名称处理请求

如果不允许不带”Host”字段的请求,可以定义仅丢弃指定请求的虚拟服务器:

1
2
3
4
5
server {
listen 80;
server_name "";
return 444;
}

上面配置虚拟服务器的server_name字段为空字符串,该字符串与没有”Host”请求头的请求匹配,返回特殊的nginx非标准代码444,然后关闭连接。

注意
* 从版本0.8.48开始,这是server_name的默认设置,因此可以省略server_name属性
* 在早期版本中,计算机的主机名用作默认server_name

Mixed name-based and IP-based virtual servers

基于名称和IP的虚拟服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
...
}

server {
listen 192.168.1.1:80;
server_name example.net www.example.net;
...
}

server {
listen 192.168.1.2:80;
server_name example.com www.example.com;
...
}

在上面的配置中,nginx首先会根据server块的listen指令测试请求中的IP地址和端口。然后,它根据匹配到的server块中的server_name继续匹配请求头中的”Host”字段。如果找不到对应的server_name,则将请求路由至默认虚拟服务器。例如,在192.168.1.1:80端口上接收到的www.example.com请求将由192.168.1.1:80端口的默认服务器(即第一台服务器)处理,因为没有为此端口定义www.example.com
如前所述,default_serverlisten指令的参数,并且可以为不同IP或端口定义不同的默认虚拟服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 192.168.1.1:80;
server_name example.org www.example.org;
...
}

server {
listen 192.168.1.1:80 default_server;
server_name example.net www.example.net;
...
}

server {
listen 192.168.1.2:80 default_server;
server_name example.com www.example.com;
...
}

Server names 服务器名称

虚拟服务器名称是由server_name指令定义的,用于确定请求的具体路由,可以使用确切名称,通配符名称或正则表达式来定义它们。

按名称搜索虚拟服务器时,如果名称匹配到多个,则按以下优先级选择第一个匹配:

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

Wildcard names 通配符名称

通配符名称只能在名称的开头或结尾包含星号,例如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

Regular expressions names 正则表达式名称

nginx使用的正则表达式与Perl语言(PCRE)使用的正则表达式兼容。要使用正则表达式,server_name必须与波浪号字符开头:

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

否则将被视为确切名称。如果表达式里面包含星号,将被视为通配符名称。不要忘记设置”^”和”$”锚点,虽然在语法上不是必须的,但在逻辑上是必须的。另外请注意,域名点符号应该用反斜杠(\)转义,包含字符”{“和”}”应该用引号包裹:

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

否则,nginx将在启动时报出以下错误:

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

命名的正则表达式捕获组可以在之后用作变量:

1
2
3
4
5
6
7
server {
server_name ~^(www\.)?(?<domain>.+)$;

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

PCRE库使用以下语法支持命名捕获:

1
2
3
?<name> Perl5.10兼容语法,自PCRE-7.0起受支持
?'name' Perl5.10兼容语法,自PCRE-7.0起受支持
?P<name> Python兼容语法,自PCRE-4.0起受支持

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

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

这意味着PCRE库较旧,你应该尝试?P<name>语法。捕获分组也可以以数字形式引用:

1
2
3
4
5
6
7
server {
server_name ~^(www\.)?(.+)$;

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

但是,这种用法应仅限于简单场景(像上面这种),因为数字参考很容易被覆盖。

Miscellaneous names 杂项名称

如果要求处理请求头中没有”Host”字段的请求,应该指定一个空名称:

1
2
3
4
5
server {
listen 80;
server_name example.org www.example.org "";
...
}

如果虚拟服务器中未定义server_name,则nginx使用空名称作为服务器名称。

注意
* 在0.8.48及以下版本前使用计算机的主机名作为服务器名称

如果服务器名称定义为$hostname(0.9.4开始),则使用计算机的主机名。
如果有人使用IP地址而不是服务器名称发出请求,则请求头”Host”字段将包含IP地址,并且可以使用IP地址作为服务器名称来处理请求:

1
2
3
4
5
6
7
8
9
server {
listen 80;
server_name example.org
www.example.org
""
192.168.1.1
;
...
}

在所有虚拟服务器示例中,可以看到一个奇怪的名称”_”:

1
2
3
4
5
server {
listen 80 default_server;
server_name _;
return 444;
}

这个名称没有什么特别,它表示未匹配到其他有效server_name之外的所有无效域名。同样可以使用其他无效名称,例如”-“和”!@#”。

nginx在0.6.25及以下版本支持特殊名称”*“,该名称被错误地解释为万能名称。它从不用作通用或通配符名称服务器名称。相反,它提供了server_name_in_redirect指令现在提供的功能。现在不赞成使用特殊名称”*“,而应该使用server_name_in_redirect指令。请注意,无法使用server_name指令指定通用名称或默认虚拟服务器。因为这是listen指令的属性,而不是server_name指令的属性。可以定义监听端口*:80*:8080的虚拟服务器,并指示其中一个是*:8080的默认虚拟服务器,而另一个是*:80的默认虚拟服务器。

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
listen 8080 default_server;
server_name example.net;
...
}
server {
listen 80 default_server;
listen 8080;
server_name example.org;
...
}

Optimization 优化

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

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

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

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

由于这些原因,最好在可能的地方使用确切的名称。例如,如果服务器最常请求的名称是example.orgwww.example.org,则显式定义它们将更有效:

1
2
3
4
5
server {
listen 80;
server_name example.org www.example.org *.example.org;
...
}

而不是使用简化形式:

1
2
3
4
5
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将无法启动并显示错误消息:

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

在这种情况下,应将指令值增加到下一个二次幂:

1
2
3
4
http {
server_names_hash_bucket_size 64;
...
}

如果定义了大量服务器名称,则会出现另一条错误消息:

1
2
3
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必须执行该表达式以获取捕获。

Compatibility 兼容性

  • 从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