Linux学习106 nginx配置文件全面讲解
一、回顾:IO模型,nginx
1、IO模型
a、阻塞式
b、非阻塞式
c、复用型IO(select,poll)
d、事件驱动型IO (epoll,Kqueue,/dev/poll)
e、AIO
f、IO阶段:等待数据准备完成(从磁盘到内核内存),复制(从内核内存至进程内存)
g、mmap
2、nginx:master/worker
a、master:配置文件分析和加载,管理worker,平滑升级
b、worker:处理用户请求
c、cache loader,cache manager:缓存加载和缓存管理
d、高度模块化:
HTTP module
Standard HTTP Module
Optional HTTP Module
Mail Module
Stream Module
e、nginx.conf
main block:主配置段,也即全局配置段
event{
…
}:事件驱动相关的配置
http {
…
}:http/https协议相关的配置段
mail {
…
}
stream {
…
}
http {
…
…:各server的公共配置,就不用在server中重复写
server {
…
listen
server_name
root :指定站点根目录
alias :路径别名
location [OPERATOR] URL {
…
if CONDITION {
…
}
}:location用来指明对某一个或某一类URL的资源访问属性的定义。并且还可以基于条件来做。
}
}
二、Nginx(2)
1、main配置段常见的配置指令
a、分类:
(1)、正常运行必备的配置
(2)、优化性能相关的配置
(3)、用于调试及定位问题相关的配置
(4)、事件驱动相关的配置
b、正常运行必备的配置
(1)、user
Syntax: user uer [group];
Default:user nobody nobody;
Context:main
Defines user and group credentials used by worker processes,if group is omitted,a group whose name equals that of user is used
(2)、pid /PATH/TO/PID_FILE
指定存储nginx主进程进程号码的文件路径
(3)、include file | mask
指明包含进来的其它配置文件片段
(4)、load_module file;
指明要装载的动态模块
c、性能优化相关的配置
(1)、worker_processes number | auto;
worker进程的数量;通常应该为当前主机的cpu的物理核心数
(2)、worker_cpu_affinity cpumask …;即直接把进程绑定在某个CPU上。我们cpu有一级缓存二级缓存等,如果直接把一个进程绑定在一个cpu上那么他每次都能命中,这样的话就不用cpu来回切换调度也就不用加载其它cpu的缓存了。如果当前主机主要是为了运行nginx的他就非常有效,如果还运行了其它进程,比如mysql之类的就不要这样做了。
1)、worker_cpu_affinity auto [cpumask];
2)、CPU MASK:
00000001:0号CPU
00000010:1号CPU
….
3)、现在假如我们机器上有8颗cpu,我们现在只期望启动4个进程,把另外4颗cpu给留出来,我们这四个进程要绑定在8颗cpu的后面四个,这样我们就需要设置第4颗cpu到第8颗cpu
4)、我们现在来查看哪个nginx进程运行在哪个cpu上。我们可以看到我们的nginx进程都运行在第1颗cpu上。然后我们可以watch着然后做压测查看变化。
[root@node3 ~]# ps -axo comm,pid,psr |grep nginx nginx 5180 0 nginx 5561 0 nginx 5562 0
然后我们设置了worker_cpu_affinity 后发现无论怎么压测都不会变化。也可以设置为auto
(3)、worker_priority number
指定worker进程的nice值,设定worker进程优先级,默认进程的优先级都是0,我们可以设置优先级让其优先被调度。我们可以通过调整nice值来调整优先级,nice值从负20到正19,对应优先级从100到139,数值越大优先级越低,这是静态优先级,默认nice值为0因此我们的优先级默认的为120。
1)、首先我们来查看nice值,可以发现为0
[root@node3 ~]# ps -axo comm,pid,psr,nice |grep nginx nginx 5180 0 0 nginx 5561 0 0 nginx 5562 0 0
2)、现在我们来调整nice值为-5,即对应的优先级为115。
(4)、worker_rlimit_nofile number;
worker进程所能够打开的文件数量上限。我们这个值至少要大于我们worker_processes和events中worker_connections的乘积。即最大可以打开这么多但是不一定要打开这么多。
d、调试,定位问题
(1)、daemon on|off
是否以守护进程方式运行Nginx。在centos6上必须是on但是在centos7上可以不用,因为他托管在systemd上
(2)、master_process on|off
是否以master/worker模型运行nginx;默认为on。如果为off的话就一个nginx进程,即要处理配置文件又要处理用户请求,这么改的目的是为了调试,让相应日志打印在前台。
(3)、error_log file [level];定义错误日志,指明日志文件和相应级别,默认为warning
e、事件驱动相关的配置
(1)、events{…}
(2)、worker_connections number
每个worker进程所能够打开的最大并发连接数数量
worker_processes * worker_connections
(3)、use method
指明并发连接请求的处理方法
use epoll
(4)、accept_mutex on | off
处理新的连接请求的方法;on意味着由各worker轮流处理新请求,Off意味着每个新请求的到达都会通知所有的worker进程。mutex表示互斥锁,互斥锁的意思是这个资源必须是独占使用的,那么a进程拿到了b就得等着必须等a进程释放了b进程才能使用。这儿表示的是处理新的连接请求的方法,因为连接请求会有一个套接字文件,这个文件按照我们的配置假如有4个work进程,那么这4个work进程哪个来处理它呢?on意味着由各worker轮流处理新请求,Off意味着每个新请求的到达都会通知所有的worker进程,然后告诉他们不要来了,即谁先抢到谁处理。
那么哪种方式好呢?on表示起点公平,刚开始一人一个,不管谁忙谁不忙,即我有400个进程就一人分配100个,有可能过一会儿第一个还没有结束,其它四个早就结束了,再来400个请求的话又会给第一个分100个,这样的话就不公平了,因为他的响应很慢。即我们的on表示起点公平,而off表示结果公平。
f、http协议的相关配置
(1)
http {
……
server {
…
server_name
root
location [OPERATOR] /url/ {
…
}
}
server {
…
}
}
(2)、与套接字相关的配置
1)、server {…}
配置一个虚拟主机
server {
listen address [:PORT] | PORT;
server_name SERVER_NAME;
root /PATH/TO/DOCUMENT_ROOT; #如果要做反代的话就不要root
proxy_pass http://192.168.10.2;#这个是反代的配置,即将相应的请求反代至后端的服务。如果配置了此项就不要配置root。
}
2)、 listen PORT | address[:port] | unix:/PATH/TO/SOCKET_FILE
listen address[:port] [default_server] [ssl] [http2 | spdy] [backlog=number] [rcvbuf=size] [sndbuf=size]
default_server:设定为默认虚拟主机
ssl:限制仅能够通过ssl连接提供服务
backlog=number:后援队列长度,我们进程最大支持1024个并发连接,超过1024个就排队,能排多长就是它定义的
rcvbuf=size:接收缓冲区大小
sndbuf=size:发送缓冲区大小
3)、server_name name …;
指明虚拟主机的主机名称;后可跟多个由空白字符分隔的字符串。即如果两个虚拟主机端口都一样那么我们就要基于域名来匹配访问。
支持*通配任意长度的任意字符;server_name *.wohaoshuai.com www.wohaoshuai.*
支持~起始的字符做正则表达式模式匹配;,我们的正则匹配要以~起头,比如server_name ~^www\d+\.wohaoshuai\.com$ 表示以www开头,后面跟上任意至少一位的数字(\d和[1-9]一样),+表示匹配任意至少一个字符,\.表示匹配.本身,否则就表示单个字符,$表示以前面结尾的。
那么这儿就有一个问题,万一 第一个server_name用 *.wohaoshuai.com 这种方式来匹配,第二个server_name用 ~^www\d+\.wohaoshuai\.com$这种方式来匹配,然后你会发现我们访问www1.wohaoshuai.com的时候第一个也匹配第二个也匹配,如果我们把这两种模式放在不同的虚拟主机上他要怎么匹配呢?他就通过下面的匹配机制来匹配
匹配机制:
首先是字符串精确匹配:即假如我们访问www1.wohaoshuai.com刚好精确匹配到www1.wohaoshuai.com这台虚拟主机那么就是他了。
左侧*通配符:即假如第一个精确匹配没有,他就会再找左侧有*通配符的主机,如果有的话就匹配到他。
右侧*通配符:同理如果前两个没有匹配到,那么就找右侧通配符匹配。
正则表达式:同理如果前面三个没有被匹配到那么就找正则匹配。
练习:定义四个虚拟机,混合使用三种类型的虚拟主机,仅开放给来自于本地网络中的主机访问。
4)、tcp_nodelay on | off
在keepalived模式下的连接是否启用TCP_NODELAY选项。
5)、sendfile on | off
是否启用sendfile功能
6)、tcp_nopush on | off,即在sendfile模式下,是否启用TCP_CORK选项
仅使用sendfile为on的时候有用,这一项的作用有两个。第一个是把响应报文守护和整个文件的起始内容放在一个报文中发送。第二个是在一个报文中发送一个文件,即利用一个完整的报文来发送文件而不是把文件分开来发送。因为我们使用sendfile 来进行的时候他只会给你封装tcp守护不会给你封装应用层守护,因为我们http协议只有httpd或者nginx才能封装,内核是封装不了的。所以文件是分开发送的,即文件内容先发给你守护随后到达,我们一旦使用了tcp_nopush他就会一块儿发,即等待用户空间把守护送过来以后才打包成一个网络往外发。
7)、keepalive_timeout:保持连接的超时时间,默认为75秒。我们还有一个keepalive_requests,即保持连接的数量,默认为100秒。即在保持连接的连接之上你最多可以请求多少个资源。即在75秒之内用户请求了100个资源,那么就算没到时间都会断开。
8)、types_hash_max_size:设定保持类型的hash表的最大值。可以设置为2048。应该是2048项。
(3)、定义路径相关的配置
1)、root path
设置web资源路径映射;用于指明用户请求的url所定义的本地文件系统上的文档所在目录路径;可用的位置:http,server,location,if in location。用于http中的话表示所有的server都用于同一个设定,即同一个访问路径。这种方式一般不这么用。并且如果我们在server中又定义了root,那么他就可以覆盖全局设定。
2)、location [= | ~ | ~* | ^~] url {…} :我们定义一个根文件系统路径(即上面root定义的路径)以后这个文件系统基本上就和我们定义的url的根匹配映射起来了。那么我们这个资源到底允许谁能访问谁不能访问呢?我们在httpd中是在Director中配置的,即配置all deny from等等,而在我们nginx上可以基于location来设定。比如我们资源要做basic认证那么我们就在location中来做。他相当于是用来指明我们各种url访问属性的。
在一个server中location配置段可存在多个,用于实现从url到文件系统的路径映射;nginx会根据用户请求的URL来检查定义的所有location,并找出一个最佳匹配,而后应用其配置
=:对URL做精确匹配,
location = / {
…
}
location /表示以所有的以/起始的都匹配,而location = /表示精准匹配,即必须是/,例如,http://www.wohaoshuai.com/ 就能匹配上,http://www.wohaoshuai.com/index.html就匹配不了
~:对URL做正则表达式模式匹配,区分字符大小写。
~*:对URL做正则表达式模式匹配,不区分字符大小写
^~:对URL的左半部分做匹配检查,不区分字符大小写。他的检查机制可以理解为不是正则表达式模式的检查机制。即相应的url是从真正的访问的最左侧开始的。
不带符号:匹配起始于此url的所有的url
匹配优先级:=,^~,~/~*,不带符号
root /vhost/www/htdocs/
http://www.wohaoshuai.com/index.html –> /vhosts/www/htdocs/index.html
server {
root /vhosts/www/htdocs/
location /admin/ {
root /webapps/app1/data/
}
}
通过图中的示例我们可以看到,如果用户请求就是 / ,那么他能匹配配置A,也能匹配配置B,那么A和B到底以谁为准呢?肯定是A,因为A的优先级最高。如果用户请求的是/index.html,那么他能匹配B,因此应用B。如果用户请求的是/documents/document.html,那么B和C能匹配到,其它的匹配不到,那么以谁为准呢?肯定是以C为准的,因为匹配的长度越长优先级越高。同样的,如果用户请求的是/images/1.gif,那么B和D和E都匹配,那么要以谁为准呢?肯定是D的,因为他的优先级是仅次于精准匹配的。所以应该用到配置D。如果用户访问的是/documents/1.jpg,那么能匹配BCE,那么以谁为准呢?肯定是我们的E为准,因为我们的E优先级最高,如果没有E匹配的话B和C以谁为准呢?肯定是C,因为C匹配的最长。因此用户访问url时location只会用一次,他会自上而下基于优先级来检查。
i、现在我们在192.168.10.15上定义一个虚拟主机并设置location不期望192.168.10.14访问
[root@node3 ~]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { deny 192.168.10.14; allow all; } } [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload [root@node3 ~]#
然后我们发现192.168.10.14上就访问不了了。
ii、我们来定义访问我们定义的根下的图片的时候不允许192.168.10.14访问,其它内容的话就可以访问。然后我们就可以用正则表达式匹配,即如果我们的url是以 .jpg或.png结尾的才会收到限制,其它的话不会受到限制。然后我们在192.168.10.14上访问页面资源的时候就能正常访问,不过访问图片的时候就不会正常访问了。
[root@node3 ~]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } } [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload
iii、现在我们再来定义一个location
[root@node3 ~]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } } [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload
当我们用户访问www.wohaoshuai3.com/1.gpg的时候,两个都会匹配到,但是第二个会生效,因为他的优先级更高。
iiii、现在我们在location中加上一个root
[root@node3 ~]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } } [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload [root@node3 ~]# curl www.wohaoshuai3.com VHost2
我们可以看到我们vhost2这个文件生效了,这是因为我们如果在location中定义了root那么我们在匹配的时候生效的是在location中定义的。location之外的就被覆盖了。即他就不再继承server的root了。
iiiii、我们现在注释掉vhost2这个路径然后在/data/nginx/vhost1路径下再创建一个目录images,而后我们把相应的图片放进去
[root@node3 images]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { #root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } }
[root@node3 images]# pwd && ls -l /data/nginx/vhost1/images total 1520 -rw-r--r-- 1 root root 980265 Jun 12 16:40 morning.jpg -rw-r--r-- 1 root root 569714 Jun 12 16:40 night.jpg
此时我们的访问路径为 www.wohaoshuai3.com/images/night.jpg
然后我们重新定义一个location 然后访问/images/ 时就定向到自定义的root中
[root@node3 images]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { #root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location /images/ { root /data/pictures/; } }
那么现在就有个问题是他会在/data/pictures/下找images目录呢还是直接找文件呢?我们来验证一下
[root@node3 ~]# mkdir /data/pictures [root@node3 ~]# cp /data/nginx/vhost1/background.jpg /data/pictures/ [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload
然后我们来通过http://www.wohaoshuai3.com/images/background.jpg链接访问发现无法访问到我们的图片,会报404 not fund。因此我们定义的root /data/pictures/中这个/data/pictures才是我们location /images/ 中前面的 / ,因此我们需要这样来定义,即在 /data/pictures/中再创建一个images目录,然后将相应的图片移动至改目录下再访问,并且要在配置中调高我们该location的优先级
[root@node3 ~]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { #root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { root /data/pictures/; } }
[root@node3 ~]# mkdir /data/pictures/images [root@node3 ~]# mv /data/pictures/background.jpg /data/pictures/images/ [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload
然后我们访问http://www.wohaoshuai3.com/images/background.jpg发现就可以了。
3)、alias path;
定义路径别名,文档映射的另一种机制;仅能用于location上下文。
注意:location中使用root指令和alias指令的意义不同
root,给定的路径对应于location中的/url/左侧的/;
alias,给定的路径对应于location中的/url/右侧的/;
i、现在假如我们把上面的root换成alias,那么我们的/data/pictures/就会换到/images/的右边的/
[root@node3 ~]# mv /data/pictures/images/background.jpg /data/pictures/ [root@node3 ~]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { #root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } } [root@node3 ~]# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful [root@node3 ~]# nginx -s reload
然后我们访问http://www.wohaoshuai3.com/images/background.jpg发现就可以访问到了
4)、index file …
默认资源:http,server,location;
5)、error_page code … [=[response]] url;
Defines the URL that will be shown for the specified errors
[root@node3 ~]# cat /etc/nginx/nginx.conf |grep -Ev "^#|^$"|tail -17 server { #默认的虚拟主机 listen 80 default_server; #默认虚拟主机,即如果我们要基于主机名做虚拟主机,当你访问的主机名与任何一个定义的servername都不一样的时候要怎么办呢?那就会是你所有的虚拟主机的第一个 ,如果我们不想让第一个来响应而是我们自己认为有一个合适的当默认的那就设置默认虚拟主机,因此对于nginx来讲后面加一个default_server就表示所有匹配不到的虚拟主机都有我来响应。 listen [::]:80 default_server;#这是ipv6的地址和端口 server_name _; #对于默认的虚拟主机来讲他是下划线,可以用来匹配所有匹配不到的主机名 root /usr/share/nginx/html; #默认网页根路径 # Load configuration files for the default server block. include /etc/nginx/default.d/*.conf; location / { #用来指明我们的个人设置 } error_page 404 /404.html; #用来自定义404的错误页,即如果遇到404的时候去哪儿找 location = /40x.html { } error_page 500 502 503 504 /50x.html; #用来定义相应的状态码的错误页 location = /50x.html { } } }
i、我们来自定义错误页
[root@node3 conf.d]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { #root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } error_page 404 /notfound.html; location = /notfound.html { root /data/nginx/error_pages; } } [root@node3 conf.d]# mkdir /data/nginx/error_pages [root@node3 conf.d]# vim /data/nginx/error_pages/notfound.html [root@node3 conf.d]# cat /data/nginx/error_pages/notfound.html <h2>----------------------------<h2> <h3>============================<h3> [root@node3 conf.d]# nginx -s reload
然后我们随便访问一个不存在的资源就能看到我们定义的错误页了。
ii、我们还可以将404改成200状态码来响应,即客户端访问时直接响应成200
[root@node3 conf.d]# cat /etc/nginx/conf.d/vhost1.conf server { listen 80; server_name www.wohaoshuai3.com; root /data/nginx/vhost1; location / { #root /data/nginx/vhost2; allow all; } location ~*\.(jpg|png)$ { deny 192.168.10.14; allow all; } location ^~ /images/ { alias /data/pictures/; } error_page 404 =200 /notfound.html; location = /notfound.html { root /data/nginx/error_pages; } }
6)、try_files file … url
(4)、定义客户端请求的相关配置
1)、keepalive_timeout timeout [header_timeout];
设定保持连接的超时时长,0表示禁止长连接;默认为75s
2)、keepalive_requests number
在一次长连接上所允许请求的资源的最大数量,默认为100
3)、keepalive_disable none | browser …;
对哪种浏览器禁用长连接
4)、send_timeout time;
向客户端发送响应报文的超时时长,此处,是指两次写操作之间的间隔时长
5)、client_body_buffer_size size;
用于接收客户端请求报文的body部分的缓冲区大小;默认为16k;超出此大小时,其将被暂存到磁盘上的由client_body_temp_path指令所定义的位置
6)、client_body_temp_path path[level1 [level2 [level3]]]
设定用于存储客户端请求报文的body部分的临时存储路径及子目录结构和数量
16进制的数字
client_body_temp_path path /var/tmp/client_body 2 1 1
1:表示用一位16进制数字表示一级子目录:0-f
2:表示用2位16进制数字表示二级子目录:00-ff
2:表示用2位16进制数字表示三级子目录:00-ff
(5)、对客户端进行限制的相关配置
1)、limit_rate rate;
限制响应给客户端的传输速率,单位是bytes/second,0表示无限制
2)、limit_except method … {…}
限制对指定的请求方法之外的其它方法的使用客户端
limit_except GET {
allow 192.168.10.0/24;
deny all;
}