在linux系统下使用nginx作为web应用服务,用来提升网站访问速度的经验已五年多了,今天在此对nginx的使用做一简单总结。
一、nginx服务简介Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。Nginx已经因为它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名了。
使用Nginx前必须了解的事项:1)目前官方Nginx并不支持Windows,您只能在包括Linux、UNIX、BSD系统下安装和使用;2)Nginx本身只是一个HTTP和反向代理服务器,它无法像Apache一样通过安装各种模块来支持不同的页面脚本,例如PHP、CGI等;3)Nginx支持简单的负载均衡和容错;4)支持作为基本HTTP服务器的功能,例如日志、压缩、Byteranges、Chunkedresponses、SSL、虚拟主机等等,应有尽有。
Nginx工作原理:Nginx由内核和一系列模块组成,内核提供web服务的基本功能,如启用网络协议,创建运行环境,接收和分配客户端请求,处理模块之间的交互。Nginx的各种功能和操作都由模块来实现。Nginx的模块从结构上分为核心模块、基础模块和第三方模块。1)核心模块:HTTP模块、EVENT模块和MAIL模块2)基础模块:HTTPAccess模块、HTTPFastCGI模块、HTTPProxy模块和HTTPRewrite模块3)第三方模块:HTTPUpstreamRequestHash模块、Notice模块和HTTPAccessKey模块及用户自己开发的模块这样的设计使Nginx方便开发和扩展,也正因此才使得Nginx功能如此强大。Nginx的模块默认编译进nginx中,如果需要增加或删除模块,需要重新编译Nginx,这一点不如Apache的动态加载模块方便。如果有需要动态加载模块,可以使用由淘宝网发起的web服务器Tengine,在nginx的基础上增加了很多高级特性,完全兼容Nginx,已被国内很多网站采用。
Nginx处理连接过程:nginx不会为每个连接派生进程或线程,而是由worker进程通过监听共享套接字接受新请求,并且使用高效的循环来处理数千个连接。Nginx不使用仲裁器或分发器来分发连接,这个工作由操作系统内核机制完成。监听套接字在启动时就完成初始化,worker进程通过这些套接字接受、读取请求和输出响应。
master:当nginx在启动后,会有一个master进程和多个worker进程。master进程主要用来管理worker进程,master要做的就是:接收来自外界的信号,向各worker进程发送信号,监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动重新启动新的worker进程。主要完成如下工作:1)读取并验证配置信息;2)创建、绑定及关闭套接字;3)启动、终止worker进程及维护worker进程的个数;4)无须中止服务而重新配置工作;5)控制非中断式程序升级,启用新的二进制程序并在需要时回滚至老版本;6)重新打开日志文件;7)编译嵌入式perl脚本
worker:对于基本的网络事件,则是放在worker进程中来处理了。多个worker进程之间是对等的,他们同等竞争来自客户端的请求,各进程互相之间是独立的。一个请求,只可能在一个worker进程中处理,一个worker进程,不可能处理其它进程的请求(一对一)。然而nginx没有专门地仲裁或连接分布的worker,这项工作是由操作系统内核机制完成的。在启动时,创建一组初始的监听套接字,HTTP请求和响应之时,worker连续接收、读取和写入套接字。worker进程主要完成的任务包括:1)接收、传入并处理来自客户端的连接;2)提供反向代理及过滤功能;3)nginx任何能完成的其它任务
也许有个疑问,那就是nginx采用多worker的方式来处理请求,每个worker里面只有一个主线程,那能够处理的并发数很有限啊,多少个worker就能处理多少个并发,何来高并发呢?然而,这就是nginx的高明之处,nginx采用了异步非阻塞的方式来处理请求,也就是说,nginx是可以同时处理成千上万个请求的。
二、nginx相对于传统的apache服务的优缺点nginx相对比apache,实在有太多的优势。可以说,现在Nginx才是Web服务器的首选!!1)nginx相对于apache的优点:轻量级,同样起web服务,比apache占用更少的内存及资源;抗并发,nginx处理请求是异步非阻塞的,而apache则是阻塞型的,在高并发下nginx能保持低资源低消耗高性能;高度模块化的设计,编写模块相对简单;社区活跃,各种高性能模块出品迅速;当然apache相对于nginx也有它自身的优点:rewrite比nginx的rewrite强大;模块超多,基本想到的都可以找到;少bug,nginx的bug相对较多;超稳定;apache有自带php解析功能(apache环境部署好后,不需要再启动php服务,apache自动解析php文件,机器上只要有php命令即可;但是nginx不行,nginx必须结合php服务才能解析php文件,两则服务都要启动)
存在就是理由,一般来说,需要性能的web服务,用nginx。如果不需要性能只求稳定,那就用apache。后者的各种功能模块实现得比前者,例如ssl的模块就比前者好,可配置项多。这里要注意一点,epoll(freebsd上是kqueue)网络IO模型是nginx处理性能高的根本理由,但并不是所有的情况下都是epoll大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache的select模型或许比epoll更高性能。当然,这只是根据网络IO模型的原理作的一个假设,真正的应用还是需要实测了再说的。
常用的Nginx参数和控制程序运行参数Nginx安装后只有一个程序文件,本身并不提供各种管理程序,它是使用参数和系统信号机制对Nginx进程本身进行控制的。Nginx的参数包括有如下几个:-c
---------------------------------------------------------------------------------------------当一台服务器中启用多个实例的nginx时(即开启不同端口的nginx),那么启动nginx的时候就要根据各自的nginx配置文件进行启动了,比如:/data/nginx/sbin/nginx-c/data/nginx/conf/nginx.conf/data/nginx1.9/sbin/nginx-c/data/nginx1.9/conf/nginx.conf/opt/nginx/sbin/nginx-c/opt/nginx/conf/nginx.conf
有两种方式来通过这些信号去控制Nginx:第一是通过logs目录下的nginx.pid查看当前运行的Nginx的进程ID,通过kill–XXX
配置Nginx先来看一个实际的配置文件:
NginxStatus显示的内容意思如下:activeconnections–当前Nginx正处理的活动连接数。serveracceptshandledrequests--总共处理了14553819个连接,成功创建14553819次握手(证明中间没有失败的),总共处理了19239266个请求(平均每次握手处理了1.3个数据请求)。reading--nginx读取到客户端的Header信息数。writing--nginx返回给客户端的Header信息数。waiting--开启keep-alive的情况下,这个值等于active-(reading+writing),意思就是Nginx已经处理完正在等候下一次请求指令的驻留连接。
静态文件处理通过正则表达式,我们可让Nginx识别出各种静态文件,例如images路径下的所有请求可以写为:location~^/images/{root/opt/webapp/images;}而下面的配置则定义了几种文件类型的请求处理方式。location~\.(htm|html|gif|jpg|jpeg|png|bmp|ico|css|js|txt)${root/opt/webapp;expires24h;}对于例如图片、静态HTML文件、js脚本文件和css样式文件等,我们希望Nginx直接处理并返回给浏览器,这样可以大大的加快网页浏览时的速度。因此对于这类文件我们需要通过root指令来指定文件的存放路径,同时因为这类文件并不常修改,通过expires指令来控制其在浏览器的缓存,以减少不必要的请求。expires指令可以控制HTTP应答中的“Expires”和“Cache-Control”的头标(起到控制页面缓存的作用)。您可以使用例如以下的格式来书写Expires:expires1January,1970,00:00:01GMT;expires60s;expires30m;expires24h;expires1d;expiresmax;expiresoff;
Nginx的location语法规则:location[=|~|~*|^~]/uri/{…}=开头表示精确匹配^~开头表示uri以某个常规字符串开头,理解为匹配url路径即可。nginx不对url做编码,因此请求为/static/20%/aa,可以被规则^~/static//aa匹配到(注意是空格)。~开头表示区分大小写的正则匹配~*开头表示不区分大小写的正则匹配!~和!~*分别为区分大小写不匹配及不区分大小写不匹配的正则/通用匹配,任何请求都会匹配到。
多个location配置的情况下匹配顺序为(参考资料而来,还未实际验证,试试就知道了,不必拘泥,仅供参考):首先匹配=,其次匹配^~,其次是按文件中顺序的正则匹配,最后是交给/通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
示例说明:有如下匹配规则:location=/{#规则A}location=/login{#规则B}location^~/static/{#规则C}location~\.(gif|jpg|png|js|css)${#规则D}location~*\.png${#规则E}location!~\.xhtml${#规则F}location!~*\.xhtml${#规则G}location/{#规则H}
尽管Nginx整个程序包只有500多K,但麻雀虽小、五脏俱全。Nginx官方提供的各种功能模块应有尽有,结合这些模块可以完整各种各样的配置要求,例如:压缩、防盗链、集群、FastCGI、流媒体服务器、Memcached支持、URL重写等等,更关键的是Nginx拥有Apache和其他HTTP服务器无法比拟的高性能。甚至可以在不改变原有网站的架构上,通过在前端引入Nginx做负载均衡来提升网站的访问速度。
-------------------------------------------------------下面对Nginx的一些特殊设置做一说明-------------------------------------------------------
1.rewrite跳转规则,有以下四种flag标记:last基本上都用这个Flag,表示rewrite。break中止Rewirte,不在继续匹配。就是说本条规则匹配完成后,终止匹配,不再匹配后面的规则。redirect返回临时重定向的HTTP状态302;浏览器地址会显示跳转后的URL地址。permanent返回永久重定向的HTTP状态301;浏览器地址会显示跳转后的URL地址。1)下面是可以用来判断的表达式:-f和!-f用来判断是否存在文件-d和!-d用来判断是否存在目录-e和!-e用来判断是否存在文件或目录-x和!-x用来判断文件是否可执行
先来看几个小例子说明
root/var/www/html;indexindex.htmlindex.phpindex.htm;access_log/usr/local/nginx/logs/image.log;}
}
以上的配置也适用于:(前提是这些目录要真是存在于站点目录/var/www/html/中,并且权限要正确)将/wangshibopc/指向/ops/wangshibo/将/guohuihuipc/指向/ops/guohuihui/将/hahapc/指向/ops/haha/......
6)其他的rewrite跳转规则的例子:
[root@test-huanqiu~]#cat/var/www/html/ops/index.htmlnginx的目录对换的跳转测试
location~.*\.(js|css)${expires10d;}
location~*\.(js|css|jpg|jpeg|gif|png|swf)${if(-f$request_filename){expires1h;break;}}
location~\.(wma|wmv|asf|mp3|mmf|zip|rar|swf|flv)${root/var/www/upload/;expiresmax;}
6.禁止访问某个文件或目录1)禁止访问以txt或doc结尾的文件location~*\.(txt|doc)${root/data/www/wwwroot/linuxtone/test;denyall;}
2)nginx禁止访问所有.开头的隐藏文件设置location~*/.*{denyall;}
3)nginx禁止访问目录location^~/path{denyall;}
4)禁止访问扩展名为bat的文件location~*/.bat{denyall;}
5)禁止访问configs目录,以及其下所有子目录或文件location^~/configs/{denyall;}注意上述configs后面的斜杠不能少,否则所有以configs开头的目录或文件都将禁止访问。
6)禁止访问多个目录location~^/(cron|templates)/{denyall;break;}
7)禁止访问以/data开头的文件location~^/data{denyall;}
8)禁止访问以.sh,.flv,.mp3为文件后缀名的文件location~.*\.(sh|flv|mp3)${return403;}
9)或者以=符号形式location=/config/{return404;}location=/config.ini{return404;}
10)禁止htaccesslocation~/\.ht{denyall;}
return指令语法:returncode;使用环境:server,location,if;该指令用于结束规则的执行并返回状态码给客户端。
例如:访问的URL以".sh"或".bash"结尾,则返回403状态码location~.*\.(sh|bash)${return403;}
7.禁止IP访问只允许域名访问当别人通过ip或者未知域名访问你的网站的时候,你希望禁止显示任何有效内容,可以给他返回500.目前国内很多机房都要求网站主关闭空主机头,防止未备案的域名指向过来造成麻烦。为了避免网站遭受恶意IP攻击,需要禁止IP访问,只能使用域名访问站点!
listen行加上default(或default_server)参数,表示这个是默认虚拟主机。所以,禁止ip访问,只能使用域名访问的正确配置是:server{listen80default;server_name_;return500;}
server{listen80;server_nameweb01.wangshibo.cn;root/var/www/html;indexindex.htmlindex.phpindex.htm;access_log/usr/local/nginx/logs/image.log;}
注意:如果在上面的server_name配置中指定域名的同时,也指明了ip访问,比如server_name103.110.186.17web01.wangshibo.cn那么尽管上面已经做了返回500设置,也禁止不了ip访问!也就是说,只要server_name一行指明了ip访问,那么就禁止不了了。
下面列出其他的一些细节导致的不同效果:1)将ip和域名访问统统禁止,返回403(或者配置return500)错误页server{listen80default;server_name_;return403;
下面的配置,指明了使用域名或ip都可以访问配置中的站点。(使用ip访问只限于只有一个vhost虚拟主机配置的情况,如果是多个,那么指明ip访问就会混淆)server{listen80;server_name103.110.186.17web01.wangshibo.cn;
3)下面两个的配置后,都能使用域名或ip访问配置中的站点。server{listen80default;server_nameweb01.wangshibo.cn;
server{listen80default;server_name103.110.186.17web01.wangshibo.cn;
======================================================================nginx配置只能通过域名禁止ip访问
示例说明:server{listen80;server_nameops.wangshibo.com;location/ops/{root/home/www/html;limit_rate_after5m;limit_rate20k;}}
修改配置之前,速率没有限制:
修改配置之后,可见由于传输量大于5m,超出部分的传输速率已经被限制在20k/s:
可以发现配置之后,刚开始的时候传输速度很高,因为,传输量大于设定值的部分才会受到限制。这就说明,我们两个命令都发挥了作用!
解决办法:在论坛服务器上修改:1)首先限制并发数[root@server_web~]#vim/etc/sysconfig/iptables.....-AINPUT-ptcp--dport80-mlimit--limit6/s-jACCEPT[root@server_web~]#/etc/init.d/iptablesrestart
上面将每个用户限制在每秒6个请求,但效果不明显。
[root@server_web~]#vim/usr/local/nginx/conf/vhost/forum.confserver{listen80;server_nameforum.wangshibo.com;root/var/www/html;limit_connperip10;//这里调用上面的perip,需要写在server里面;即每个ip最多有10个并发连接limit_rate10k;//限制每个连接的带宽,可以单独写这条,与连接数无关;}}
[root@server_web~]#/usr/local/nginx/sbin/nginx-sreload
示例说明:server{listen80;server_nameforum.wangshibo.com;root/var/www/html;location/{deny192.168.1.1;allow192.168.1.0/24;allow10.1.1.0/16;allow103.10.67.56;denyall;}}规则按照顺序依次检测,直到匹配到第一条规则。在这个例子里,只有10.1.1.0/16、192.168.1.0/24和103.10.67.56允许访问,但192.168.1.1除外。
-------------------------------------------------------------------------------------------------------上面也用到了nginx的用户认证的配置,其中:auth_basic认证时的提示信息auth_basic_user_file认证时存放用户名和密码的文件
#htpasswd-c/usr/local/nginx/htpasswdwangshibo//第一次设置认证的用户#htpasswd/usr/local/nginx/htpasswdguohuihui//追加认证的用户,后面再次追加认证用户时,不要加-c参数,否则就会覆盖之前添加的用户!
下面顺便看几个认证部分的配置:
配置说明(上一部分解释过的就不再解释):定义一个名为one的limit_req_zone用来存储session,大小是10M内存,以$binary_remote_addr为key,限制平均每秒的请求为20个,1M能存储16000个状态,rete的值必须为整数,rate=20r/s表示限制频率为每秒20个请求;如果限制两秒钟一个请求,可以设置成30r/m。限制每ip每秒不超过20个请求,漏桶数burst为5brust的意思就是,如果第1秒、2,3,4秒请求为19个,第5秒的请求为25个是被允许的。但是如果你第1秒就25个请求,第2秒超过20的请求返回503错误。nodelay,如果不设置该选项,严格使用平均速率限制请求数,第1秒25个请求时,5个请求放到第2秒执行,设置nodelay,25个请求将在第1秒执行。
geo模块定义了一个默认值是1的变量whiteiplist,当在ip在白名单中,变量whiteiplist的值为0,反之为1.对上面设置的逻辑关系解释:如果在白名单中-->whiteiplist=0-->$limit=""-->不会存储到10m的会话状态(one或者addr)中-->不受限制;反之,不在白名单中-->whiteiplist=1-->$limit=二进制远程地址-->存储进10m的会话状态中-->受到限制。
(4)动手测试DDOS预防配置下面来测一下上面说到的配置是否起到了作用。安装nginx+php环境写一个测试的PHP文件,修改nginx配置文件,使其能正常访问。在/home/shiyanlou目录下写一个test.php,内容如下:[root@server_web1~]#vim/home/shiyanlou/test.php
nginx配置文件修改:
最后展示:
使ab命令进行测试,比较修改nginx配置文件前后(连接数和请求数分开测试)的测试结果。
修改之前:
测试结果为:
14.Nginx下禁止指定目录运行php脚本文件
非常简单,直接通过location条件匹配定位后进行权限禁止。在server配置段中增加下面的的配置:1)如果是单个目录location~*^/uploads/.*\.(php|php5)${denyall;}2)如果是多个目录location~*^/(attachments|uploads)/.*\.(php|php5)${denyall;}注意:这段配置文件一定要放在下面配置的前面才可以生效。location~\.php${fastcgi_pass127.0.0.1:9000;fastcgi_indexindex.php;fastcgi_paramSCRIPT_FILENAME$document_root$fastcgi_script_name;includefastcgi_params;}配置完后记得重启Nginx生效。------------------------------------------------------------------------------如果是Apache下禁止指定目录运行PHP脚本,在虚拟主机配置文件中增加php_flagengineoff指令即可,配置如下"/website/uploads">OptionsFollowSymLinksAllowOverrideNoneOrderallow,denyAllowfromallphp_flagengineoff15.Nginx下开启gzip压缩功能,大幅提高页面加载速度
将静态资源放在A主机的一个目录上,将动态程序放在B主机上,同时在A上安装Nginx并且在B上安装Tomcat。配置Nginx,当请求的是html、jpg等静态资源时,就访问A主机上的静态资源目录;当用户提出动态资源的请求时,则将请求转发到后端的B服务器上,交由Tomcat处理,再由Nginx将结果返回给请求端。
提到这,可能会有疑问,动态请求要先访问A,A转发访问B,再由B返回结果给A,A最后又将结果返回给客户端,这是不是有点多余。初看的确多余,但是这样做至少有2点好处。第一,为负载均衡做准备,因为随着系统的发展壮大,只用一台B来处理动态请求显然是是不够的,要有B1,B2等等才行。那么基于图2的结构,就可以直接扩展B1,B2,再修改Nginx的配置就可以实现B1和B2的负载均衡。第二,对于程序开发而言,这种结构的程序撰写和单台主机没有区别。我们假设只用一台Tomcat作为服务器,那么凡是静态资源,如图片、CSS代码,就需要编写类似这样的访问代码: