Nginx配置文件
Nginx的主配置文件是nginx.conf,这个配置文件一共由三部分组成,分别为全局块
、events
块和http
块。在http块中,又包含http全局块、多个server块。每个server块中,可以包含server全局块和多个location块。在同一配置块中嵌套的配置块,各个之间不存在次序关系。
配置文件支持大量可配置的指令,绝大多数指令不是特定属于某一个块的。同一个指令放在不同层级的块中,其作用域也不同,一般情况下,高一级块中的指令可以作用于自身所在的块和此块包含的所有低层级块。如果某个指令在两个不同层级的块中同时出现,则采用“就近原则”,即以较低层级块中的配置为准。比如,某指令同时出现在http全局块中和server块中,并且配置不同,则应该以server块中的配置为准。\
整个配置文件的结构大致如下:\
1 |
|
全局块
全局块是默认配置文件从开始到events块之间的一部分内容,主要设置一些影响Nginx服务器整体运行的配置指令,因此,这些指令的作用域是Nginx服务器全局。
通常包括配置运行Nginx服务器的用户(组)、允许生成的worker process数、Nginx进程PID存放路径、日志的存放路径和类型以及配置文件引入等。
1 |
|
events块
events块涉及的指令主要影响Nginx服务器与用户的网络连接。常用到的设置包括是否开启对多worker process下的网络连接进行序列化,是否允许同时接收多个网络连接,选取哪种事件驱动模型处理连接请求,每个worker process可以同时支持的最大连接数等。
这一部分的指令对Nginx服务器的性能影响较大,在实际配置中应该根据实际情况灵活调整。
1 |
|
http块
http块是Nginx服务器配置中的重要部分,代理、缓存和日志定义等绝大多数的功能和第三方模块的配置都可以放在这个模块中。
前面已经提到,http块中可以包含自己的全局块,也可以包含server块,server块中又可以进一步包含location块,在本书中我们使用“http全局块”来表示http中自己的全局块,即http块中不包含在server块中的部分。
可以在http全局块中配置的指令包括文件引入、MIME-Type定义、日志自定义、是否使用sendfile传输文件、连接超时时间、单连接请求数上限等。\
1 |
|
server块
server块和“虚拟主机”的概念有密切联系。
虚拟主机,又称虚拟服务器、主机空间或是网页空间,它是一种技术。该技术是为了节省互联网服务器硬件成本而出现的。这里的“主机”或“空间”是由实体的服务器延伸而来,硬件系统可以基于服务器群,或者单个服务器等。虚拟主机技术主要应用于HTTP、FTP及EMAIL等多项服务,将一台服务器的某项或者全部服务内容逻辑划分为多个服务单位,对外表现为多个服务器,从而充分利用服务器硬件资源。从用户角度来看,一台虚拟主机和一台独立的硬件主机是完全一样的。
在使用Nginx服务器提供Web服务时,利用虚拟主机的技术就可以避免为每一个要运行的网站提供单独的Nginx服务器,也无需为每个网站对应运行一组Nginx进程。虚拟主机技术使得Nginx服务器可以在同一台服务器上只运行一组Nginx进程,就可以运行多个网站。
在前面提到过,每一个http块都可以包含多个server块,而每个server块就相当于一台虚拟主机,它内部可有多台主机联合提供服务,一起对外提供在逻辑上关系密切的一组服务(或网站)。
和http块相同,server块也可以包含自己的全局块,同时可以包含多个location块。在server全局块中,最常见的两个配置项是本虚拟主机的监听配置和本虚拟主机的名称或IP配置。\
listen指令
server块中最重要的指令就是listen指令,这个指令有三种配置语法。这个指令默认的配置值是:listen *:80 | *:8000;只能在server块种配置这个指令。
1 |
|
listen指令的配置非常灵活,可以单独制定ip,单独指定端口或者同时指定ip和端口。
1 |
|
关于上面的一些重要参数做如下说明:
- address:监听的IP地址(请求来源的IP地址),如果是IPv6的地址,需要使用中括号“[]”括起来,比如[fe80::1]等。
- port:端口号,如果只定义了IP地址没有定义端口号,就使用80端口。这边需要做个说明:要是你压根没配置listen指令,那么那么如果nginx以超级用户权限运行,则使用*:80,否则使用*:8000。多个虚拟主机可以同时监听同一个端口。
- default_server:假如通过Host没匹配到对应的虚拟主机,则通过这台虚拟主机处理。具体的可以参考这篇文章,写的不错。
- backlog=number:设置监听函数listen()最多允许多少网络连接同时处于挂起状态,在FreeBSD中默认为-1,其他平台默认为511。
- accept_filter=filter,设置监听端口对请求的过滤,被过滤的内容不能被接收和处理。本指令只在FreeBSD和NetBSD 5.0+平台下有效。filter可以设置为dataready或httpready,感兴趣的读者可以参阅Nginx的官方文档。
- bind:标识符,使用独立的bind()处理此address:port;一般情况下,对于端口相同而IP地址不同的多个连接,Nginx服务器将只使用一个监听命令,并使用bind()处理端口相同的所有连接。
- ssl:标识符,设置会话连接使用SSL模式进行,此标识符和Nginx服务器提供的HTTPS服务有关。
listen指令的使用看起来比较复杂,但其实在一般的使用过程中,相对来说比较简单,并不会进行太复杂的配置。
server_name指令
用于配置虚拟主机的名称。语法是:
1 |
|
对于name 来说,可以只有一个名称,也可以由多个名称并列,之间用空格隔开。每个名字就是一个域名,由两段或者三段组成,之间由点号“.”隔开。比如
1 |
|
在该例中,此虚拟主机的名称设置为myserver.com或www. myserver.com。Nginx服务器规定,第一个名称作为此虚拟主机的主要名称。
在name 中可以使用通配符“*”,但通配符只能用在由三段字符串组成的名称的首段或尾段,或者由两段字符串组成的名称的尾段,如:
1 |
|
另外name还支持正则表达式的形式。这边就不详细展开了。
由于server_name指令支持使用通配符和正则表达式两种配置名称的方式,因此在包含有多个虚拟主机的配置文件中,可能会出现一个名称被多个虚拟主机的server_name匹配成功。那么,来自这个名称的请求到底要交给哪个虚拟主机处理呢?Nginx服务器做出如下规定:
- 对于匹配方式不同的,按照以下的优先级选择虚拟主机,排在前面的优先处理请求。
① 准确匹配server_name
② 通配符在开始时匹配server_name成功
③ 通配符在结尾时匹配server_name成功
④ 正则表达式匹配server_name成功 - 在以上四种匹配方式中,如果server_name被处于同一优先级的匹配方式多次匹配成功,则首次匹配成功的虚拟主机处理请求。
有时候我们希望使用基于IP地址的虚拟主机配置,比如访问192.168.1.31有虚拟主机1处理,访问192.168.1.32由虚拟主机2处理。
这时我们要先网卡绑定别名,比如说网卡之前绑定的IP是192.168.1.30,现在将192.168.1.31和192.168.1.32这两个IP都绑定到这个网卡上,那么请求这个两个IP的请求才会到达这台机器。
绑定别名后进行以下配置即可:
1 |
|
location块
每个server块中可以包含多个location块。在整个Nginx配置文档中起着重要的作用,而且Nginx服务器在许多功能上的灵活性往往在location指令的配置中体现出来。
location块的主要作用是,基于Nginx服务器接收到的请求字符串(例如, server_name/uri-string),对除虚拟主机名称(也可以是IP别名,后文有详细阐述)之外的字符串(前例中“/uri-string”部分)进行匹配,对特定的请求进行处理。地址定向、数据缓存和应答控制等功能都是在这部分实现。许多第三方模块的配置也是在location块中提供功能。
在Nginx的官方文档中定义的location的语法结构为:
1 |
|
其中,uri变量是待匹配的请求字符串,可以是不含正则表达的字符串,如/myserver.php等;也可以是包含有正则表达的字符串,如 .php$(表示以.php结尾的URL)等。为了下文叙述方便,我们约定,不含正则表达的uri称为“标准uri”,使用正则表达式的uri称为“正则uri”。
其中方括号里的部分,是可选项,用来改变请求字符串与 uri 的匹配方式。在介绍四种标识的含义之前,我们需要先了解不添加此选项时,Nginx服务器是如何在server块中搜索并使用location块的uri和请求字符串匹配的。
在不添加此选项时,Nginx服务器首先在server块的多个location块中搜索是否有标准uri和请求字符串匹配,如果有多个可以匹配,就记录匹配度最高的一个。然后,服务器再用location块中的正则uri和请求字符串匹配,当第一个正则uri匹配成功,结束搜索,并使用这个location块处理此请求;如果正则匹配全部失败,就使用刚才记录的匹配度最高的location块处理此请求。
了解了上面的内容,就可以解释可选项中各个标识的含义了:
- “=”,用于标准uri前,要求请求字符串与uri严格匹配。如果已经匹配成功,就停止继续向下搜索并立即处理此请求。
- “^~”,用于标准uri前,要求Nginx服务器找到标识uri和请求字符串匹配度最高的location后,立即使用此location处理请求,而不再使用location块中的正则uri和请求字符串做匹配。
- “~”,用于表示uri包含正则表达式,并且区分大小写。
- “~”,用于表示uri包含正则表达式,并且不区分大小写。注意如果uri包含正则表达式,就必须要使用“~”或者“~”标识。
我们知道,在浏览器传送URI时对一部分字符进行URL编码,比如空格被编码为“%20”,问号被编码为“%3f”等。“~”有一个特点是,它对uri中的这些符号将会进行编码处理。比如,如果location块收到的URI为“/html/%20/data”,则当Nginx服务器搜索到配置为“~ /html/ /data”的location时,可以匹配成功。
root指令
这个指令用于设置请求寻找资源的跟目录,此指令可以在http块、server块或者location块中配置。由于使用Nginx服务器多数情况下要配置多个location块对不同的请求分别做出处理,因此该指令通常在location块中进行设置。
1 |
|
path变量中可以包含Nginx服务器预设的大多数变量,只有$document_root和$realpath_root不可以使用。
alisa指令
对于root,操作上很简单,只要把root地址替换host后就是文件在硬盘路径(真实地址)。对于alise,它并不是替换匹配后的url地址,而是替换匹配部分的url。alias指令也可以有多个。
添加一个location,和root的方式几乎一样:
1 |
|
访问 http://192.168.33.10/upload/up.png 并没有图片,查看error得到:
1 |
|
可见 alias的模式并不是/vagrant/pro + /upload/up.png,而是 /vagrant/pro + /up.png。
alias这个词在计算机里很常用,字面意思是“别名”,顾名思议就是换一个名字啦。实际替换规则就是把匹配的url地址,换成alias中的路径即可。例如上述的例子替换过程可以模拟如下:
过程 | 模式或url |
---|---|
url模式 | ^~ /upload |
alias路径 | /vagrant/pro |
访问地址 | http://192.168.33.10/upload/up.png |
匹配部分的地址 | /upload + /up.png |
替换 | /upload == /vagrant/pro |
结果 | /vagrant/pro + /up.png |
为了修改图片的访问,修改locaton如下:
1 |
|
此时访问 http://192.168.33.10/upload/up.png 就能得到正确的图片啦
从结果可以看出,正确的找到了文件路径,如果alias指令路径加上斜杠,那么计算处理的文件路径为:
1 |
|
多个斜杠是合法的。等价于一个斜杠的情况。
下面修改locaiton如下:
1 |
|
此时匹配时的url则变成 /upload/ + up.jpg, 那么置换的结果为 /vagrant/pro/upload + up.png,而/vagrant/pro/uploadup.png的路径是非法的,从error中也能看到置换的错误:
1 |
|
解决办法也很简单,把/vagrant/pro/upload 改成 /vagrant/pro/upload/即可。由此可见,alias最后的斜杠并不像root指令那样可有可无,是否需要,取决于配合loacation的url匹配模式。
前文root模式中,考虑了没有根的斜杠(~ static/stc.jpgs?)这种情况,alias情况下会很难捕捉错误。如果locaion配置如下:
1 |
|
替换置换的文件路径应该为 /vagrant/pro/upload/up.png,可是实际测试中,这样配置alias,会一直导致一个301的重定向,如果alias目录没有打开autoindex,则会抛出一个403错误。具体情况尚未知晓,不知道是不是nginx的bug。为了避免这种情况,使用alias的时候,尽量不要配置location为 ^~ upload/的模式,并且不从根指定url,还是显得不伦不类。
alise作为别名,比起root的一大好处就是不一定要url上的路径和文件路径一样,因为alise并不是替换host,而是替换匹配部分的host。修改配置如下:
1 |
|
访问 http://192.168.33.10/upload/stc.jpg 或者 http://192.168.33.10/upload/flask/m.png 都能正确的访问到static目录下的文件,尽管url上是upload。
替换规则也很简单,/upload/ == /vagrant/pro/static/ 得到 /vagrant/pro/static/ + stc.jpg 或 /vagrant/pro/static/ + flask/m.png。
nginx的静态文件配置中,root和alias指令都能实现。为了避免混淆,尽量不要写没有根路径的url模式,即避免 static/这样的开头,根路径的斜杠需要保留,没有根路径其实也很奇怪。
root和alias的区别主要在于替换的部分,root模式中,会把root配置的路径替换匹配后的url中的host。alias则把他指定的路径,替换url中匹配的部分。指令中的斜杠对于root指令没有影响,对于alise则按照替换规则匹配即可。\
index指令
在前后端分离的基础上,通过Nginx配置,指定网站初始页。
如果包括多个文件,Nginx会根据文件的枚举顺序来检查,直到查找的文件存在;
文件可以是相对路径也可以是绝对路径,绝对路径需要放在最后;
文件可以使用变量$来命名;
1 |
|
该指令拥有默认值,index index.html ,即,如果没有给出index,默认初始页为index.html
核心内容(中文文档没有或一笔带过,而官方文档作详细解释);
Nginx给了三种方式来选择初始页,三种方式按照顺序来执行;\
ngx_http_random_index_module
模块,从给定的目录中随机选择一个文件作为初始页,而且这个动作发生在ngx_http_index_module
之前,注意:这个模块默认情况下没有被安装,需要在安装时提供配置参数--with-http_random_index_module
ngx_http_index_module
模块,根据index指令规则来选择初始页ngx_http_autoindex_module
模块,可以使用指定方式,根据给定目录中的文件列表自动生成初始页,这个动作发生在ngx_http_index_module
之后,即只有通过index指令无法确认初始页,此时启用后的自动生成模块才会被使用。
切记,index指令并不是查到文件之后,就直接拿来用了。它的实际工作方式是:
如果文件存在,则使用文件作为路径,发起内部重定向。直观上看上去就像再一次从客户端发起请求,Nginx再一次搜索location一样。
既然是内部重定向,域名+端口不发生变化,所以只会在同一个server下搜索。
同样,如果内部重定向发生在proxy_pass反向代理后,那么重定向只会发生在代理配置中的同一个server。
1 |
|
上面的例子中,如果你使用example.org或www.example.org直接发起请求,那么首先会访问到“/”的location,结合root与index指令,会先判断/data/www/index.html是否存在,如果不,则接着查看\
/data/www/index.php ,如果存在,则使用/index.php发起内部重定向,就像从客户端再一次发起请求一样,Nginx会再一次搜索location,毫无疑问匹配到第二个~ .php$,从而访问到/data/www/test/index.php。\
1 |
|
当用户请求 http://localhost/example 时,这里的 $uri 就是 /example。
try_files 会到硬盘里尝试找这个文件。如果存在名为 /$root/example(其中 $root 是项目代码安装目录)的文件,就直接把这个文件的内容发送给用户。
显然,目录中没有叫 example 的文件。然后就看 $uri/,增加了一个 /,也就是看有没有名为 /$root/example/ 的目录。
又找不到,就会 fall back 到 try_files 的最后一个选项 /index.php,发起一个内部 “子请求”,也就是相当于 nginx 发起一个 HTTP 请求到 http://localhost/index.php。
error_page指令
nginx指令error_page的作用是当发生错误的时候能够显示一个预定义的uri,比如:
1 |
|
这样实际上产生了一个内部跳转(internal redirect),当访问出现502、503的时候就能返回50x.html中的内容。
同时我们也可以自己定义这种情况下的返回状态吗,比如:
1 |
|
这样用户访问产生502 、503的时候给用户的返回状态是200,内容是50x.html。
当error_page后面跟的不是一个静态的内容的话,比如是由proxyed server或者FastCGI/uwsgi/SCGI server处理的话,server返回的状态(200, 302, 401 或者 404)也能返回给用户。
1 |
|
也可以设置一个named location,然后在里边做对应的处理。
1 |
|
同时也能够通过使客户端进行302、301等重定向的方式处理错误页面,默认状态码为302。
1 |
|
同时error_page在一次请求中只能响应一次,对应的nginx有另外一个配置可以控制这个选项:
1 |
|
默认为false,作用是控制error_page能否在一次请求中触发多次。
一点说明
上面列举了Nignx中全局块、event块和http块的一些配置指令,但是Nginx的指令远远不止这些。其实这边最主要的还是讲解整个配置文件的结构,如果大家要看比较全的指令介绍、模块介绍的话,建议去Nginx的官网。
一个配置文件的列子
1 |
|