和大多数软件一样,Nginx也有自己的配置文件,但它又有很多与众不同的地方,本帖就来揭开Nginx基础配置的面纱。
了解指令和指令块有助于大家了解配置的上下文,下面是一个配置模板示例:
在这个配置模板中主要包含两种指令:
在前面的配置示例中,http块是全局参数,对整体产生影响;server块是虚拟主机,主要对指定的主机和端口进行配置;location块在虚拟主机下根据请求URI(Uniform Resource Identifier,统一资源标识符)进行配置,URI即去掉参数后的URL。
简单指令在指令块中的配置存在一定的区段。有些简单指令不能在某些指令块中使用;而有些简单指令既可以在http块也可以在server块中配置,甚至可以在location块中配置。当某个变量同时出现在多个指令块中时,最终会以在最小指令块中的赋值为准。
例如,如果在location中设置expires为1m,那么expires就会使用location中的设置;如果没有在location中设置expires,那么expires的值则会使用http块中的1d。这有点类似于编程语言里的变量。
对指令和指令块有了初步了解之后,下面将根据前面的配置示例,对Nginx的指令块进行逐一说明,以帮助大家理解每个指令块的作用。
在http块之前的配置是全局参数,如前面配置示例中的Main 1,全局参数对整个Nginx块都产生作用。下面是一个简单示例:
与客户端有关的配置主要在http块中设置,如前面配置中的指令Main 1和server块之间的Main 2就是对客户端进行的配置,其作用是处理与客户端相关的信息。客户端配置常用的指令见下表:
很多指令都可以在多个Main中配置,但不是所有的指令都可以出现在2.1节的配置中的Main 1、Main 2和Main 3里面。例如client_body_timeout可以在http、server、location块中设置,但server_names_hash_bucket_size却只能出现在http块中。
上表中的指令和客户端的请求操作有直接关系,熟悉这些指令对配置和优化Nginx有很大的帮助。
server块即虚拟主机部分,如果请求中的Host头和server_name相匹配,则将请求指向对应的server块,示例如下:
server_name支持使用通配符正则表达式,支持配置多域名、服务名称。当有多个server块时,会存在匹配的优先级问题,优先级顺序如下:
1.精确的名字;
2.以开头的最长通配符名称,如.testnginx.com;
3.以结尾的最长通配符名称,如testnginx.;
4.按照文件顺序,第1个匹配到的正则表达式;
5.如果没有匹配到对应的server_name,则会访问default_server。
location块在server块中使用,它的作用是根据客户端请求URL去定位不同的应用。即当服务器接收到客户端请求之后,需要在服务器端指定目录中去寻找客户端所请求的资源,这就需要使用请求URL匹配对应的location指令。下表是URL在location块中的匹配规则说明:
上表中匹配的优先级顺序为如下:
“=”优先级最高,如果“=”匹配不到,会和“^~”进行匹配;继而是“~”,如果有多个“~”,则按照在文件里的先后顺序进行匹配;如果还匹配不到,则与“/uri”进行匹配;通用匹配“/”的优先级最低,如果找不到其他配置,就会进行通用匹配;“@”表示命名空间的位置,通常在重定向时进行匹配,且不会改变URL的原始请求。
建议:打开Debug模式并观察日志,会看到每个请求的执行过程,包括匹配到对应location的操作。
location块也支持嵌套配置:
有些指令只能在location块中执行,主要有如下3个:
include用来指定主配置文件包含的其他扩展配置文件。扩展文件的内容也要符合Nginx的格式规范。include可以简化主配置文件,使之更易于读取。include可以出现在全局参数、location块、server块等任何一个位置。
include支持通配符,例如下面的配置会将后缀是.conf的所有文件都加载到Nginx配置中:
因此,可以将Nginx配置成多个文件,并提取出相同的数据,从而精简配置,方便管理。
前面的介绍了Nginx中的main指令、server块、location块、include,以及与客户端相关的一些配置知识,本节将进一步介绍Nginx常见的配置及其实战技巧。
学完常见配置的注解,相信大家已经对Nginx配置有了基本的认识。但在实际应用中,Nginx配置可以通过巧妙的变化实现不同的功能,下面将会讲解在实战中应如何进行合理的配置。
Nginx的常见配置在使用中有着不同的变化,熟悉Nginx的官方Wiki是发挥其巨大作用的前提。
在客户端请求过程中,Nginx提供了内置变量来获取HTTP或TCP的信息。充分了解这些内置变量,才能够对应用场景中的业务进行合理的配置,下面先来熟悉一下常见的内置变量。
注意:Nginx 1.9之后的版本开始支持TCP代理,这使Nginx的功能更为丰富(后面会有单独的介绍和案例示范)。本书默认以HTTP代理为例进行讲解,中间涉及TCP的地方会有特别说明。
注意:随着Nginx版本的不断更新,会出现更多新的指令,更多与Nginx内置变量有关的解释可参考Nginx 官方Wiki。
Nginx的内置变量主要用于日志记录和分析,以及业务逻辑的处理。下面将介绍一些常用内置变量的配置方式。
1、$arg_name
:
上述代码的请求默认路径是http://a,如果URL中的参数是at=5,则路径变为http://b。
2、 $body_bytes_sent和$bytes_sent
:
这两个变量的值之差就是HTTP 响应头的大小。如果两个值相差悬殊,那么响应头就很大,需要确保proxy_buffer设置了合适的大小,因为如果超过proxy_buffer设置的值,error.log就会显示如下内容:
3、$realip_remote_addr
:
在Nginx 1.9.7版本以后加入ngx_http_realip_module的变量,此变量可以获取用户的IP地址(如常见的代理或CDN的节点IP地址)。
4、$request_time和$upstream_response_time
:
$upstream_response_time
指的是在Nginx启用了upstream的情况下,从Nginx与后端建立连接开始到接收完数据然后关闭连接为止的时间。$request_time
指从接收到用户请求到发送完响应数据的时间,包括接收请求数据的时间、程序响应的时间和输出响应数据的时间。如果要检查后端服务的性能,需要使用$upstream_response_time
的值。
5、$uri和$request_uri
:
$uri
记录的是执行一系列内部重定向操作后最终传递到后端服务器的URL(不包含参数$args
的值)。
$request_uri
记录的是当前请求的原始URL(包含参数),如果没有执行内部重定向操作,$request_uri
去掉参数后的值和$uri
的值是一样的。在线上环境中排查问题时,如果在后端服务中看到的请求和在Nginx中存放的$request_uri
无法匹配,可以考虑去 $uri
里面进行查找。
6、$scheme
:
近几年来,HTTPS非常流行,很多互联网企业都把HTTP切换成了HTTPS,但是当用户手动输入网站地址时,很少会主动加上https://。为了让用户的请求能够顺利跳转到HTTPS,首先需要判断用户输入的是HTTP还是HTTPS。$scheme
就具有此功能,如果用户输入的是HTTP可以通过重定向跳转到HTTPS,示例代码如下: