在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 服务器的功能,例如日志、压缩、Byte ranges、Chunked responses、SSL、虚拟主机等等,应有尽有。
Nginx工作原理:
Nginx由内核和一系列模块组成,内核提供web服务的基本功能,如启用网络协议,创建运行环境,接收和分配客户端请求,处理模块之间的交互。Nginx的各种功能和操作都由模块来实现。Nginx的模块从结构上分为核心模块、基础模块和第三方模块。
1)核心模块: HTTP模块、EVENT模块和MAIL模块
2)基础模块: HTTP Access模块、HTTP FastCGI模块、HTTP Proxy模块和HTTP Rewrite模块
3)第三方模块: HTTP Upstream Request Hash模块、Notice模块和HTTP Access Key模块及用户自己开发的模块
这样的设计使Nginx方便开发和扩展,也正因此才使得Nginx功能如此强大。Nginx的模块默认编译进nginx中,如果需要增加或删除模块,需要重新编译Nginx,这一点不如Apache的动态加载模块方便。如果有需要动态加载模块,可以使用由淘宝网发起的web服务器Tengine,在nginx的基础上增加了很多高级特性,完全兼容Nginx,已被国内很多网站采用。
Nginx处理连接过程:
nginx不会为每个连接派生进程或线程,而是由 worker 进程通过监听共享套接字接受新请求,并且使用高效的循环来处理数千个连接。Nginx 不使用仲裁器或分发器来分发连接,这个工作由操作系统内核机制完成。监听套接字在启动时就完成初始化,worker 进程通过这些套接字接受、读取请求和输出响应。
Nginx的工作模式很简单,就是采用一个master进程和多个worker工作进程:
其中master进程的作用也是很明确的就是负责管理worker进程,同时监听连接请求,当连接请求到来之后将连接放入worker进程中去处理具体的业务请求,比如说http请求。 Nginx能够处理高并发的原因在于对socket的管理方式是异步非阻塞的,使用select/poll/epoll/kqueue 来实现对大量socket描述符的管理,每个worker进程有一个主线程,而没有其他的线程这样的好处就在于不需要进行线程间的切换,这样就节省了资源。所以总的来说:Nginx能够实现支持高并发的同时运行效率还很低的关键在于整个系统内部只有有限的几个工作进程和一个监听进程,而每个进程内部只有一个主线程,这样就不会引起很多的线程切换,从而降低了系统开销,同时每个线程内部使用异步非阻塞的方式来管理描述符这样就可以管理大量的描述符,当描述符多的时候也只是会占用较多的内存而已,而不会造成占用大量cpu时间。以上说的就是Nginx的进程模型和事件模型,事件模型中处理的情况主要有三种,分别是网络事件,如HTTP请求等,网络事件使用异步非阻塞模式就可以很好的解决;还有信号,定时器,信号和定时器还不是很明白。Nginx处理进程间争夺系统资源的方式:也就是进程间存在的惊群现象。
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任何能完成的其它任务
举例说明一个完整请求如何通过互相协作来实现的:
既然worker进程之间是平等的,每个进程,处理请求的机会也是一样的。当我们提供80端口的http服务时,一个连接请求过来,每个进程都有可能处理这个连接。那么问题来了,到底最后怎样处理,是由什么决定的呢?首先,每个 worker 进程都是从 master 进程 fork 过来,在 master 进程里面,先建立好需要 listen 的 socket(listenfd)之后,然后再 fork 出多个 worker 进程。所有 worker 进程的 listenfd 会在新连接到来时变得可读,为保证只有一个进程处理该连接,所有 worker 进程会在注册 listenfd 读事件前抢 accept_mutex,抢到互斥锁的那个进程注册 listenfd 读事件,然后在读事件里调用 accept 接受该连接。当一个 worker 进程在 accept 这个连接之后,就开始读取请求、解析请求、处理请求。产生数据后,再返回给客户端,最后才断开连接,这样一个完整的请求就是这样的了。我们可以看到:一个请求,完全由 worker 进程来处理,而且只在一个 worker 进程中处理。
也许有个疑问,那就是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 模型的原理作的一个假设,真正的应用还是需要实测了再说的。
2)作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。在高连接并发的情况下,Nginx是Apache服务器不错的替代品: Nginx在美国是做虚拟主机生意的老板们经常选择的软件平台之一. 能够支持高达 50,000 个并发连接数的响应, 感谢Nginx为我们选择了 epoll and kqueue 作为开发模型.
Nginx作为负载均衡服务器: Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务, 也可以支持作为 HTTP代理 服务器对外进行服务. Nginx采用C进行编写, 不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多.
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器), Last.fm 描述了成功并且美妙的使用经验.
Nginx 是一个安装非常的简单 , 配置文件非常简洁(还能够支持perl语法), Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够不间断服务的情况下进行软件版本的升级 .
3)Nginx 配置简洁,Apach复杂;Nginx静态处理性能比Apache高3倍以上;Apache对PHP支持比较简单,Nginx需要配合其他后端用;Apache的组件比Nginx多;
4)最核心的区别在于apache是同步多进程模型,一个连接对应一个进程;nginx是异步的,多个连接(万级别)可以对应一个进程
5)nginx处理静态文件好,耗费内存少.但apache目前也有它的优势,有很多丰富的特性.所以还需要搭配着来.当然如果能确定nginx就适合需求,那么使用nginx会是更经济的方式.
6)从个人过往的使用情况来看,nginx的负载能力比apache高很多。最新的服务器也改用nginx了。而且nginx改完配置能-t测试一下配置有没有问题,apache重启的时候发现配置出错了,会很崩溃,改的时候都会非常小心翼翼现在看有好多集群站,前端nginx抗并发,后端apache集群,配合的也不错。
7)nginx处理动态请求是鸡肋,一般动态请求要apache去做,nginx只适合静态和反向。
8)从个人经验来看,nginx是很不错的前端服务器,负载性能很好,linux服务器上运营nginx,用webbench模拟10000個个静态文件请求毫不吃力。apache对php等语言的支持很好,此外apache有強大的支持网路,反正时间相对nginx更久,bug少,但是apache有先天不支持多核心处理负载鸡肋的缺点,所以建议使用nginx做前端,后端用apache。大型网站建议用nginx自代的集群功能!
9)Nginx优于apache的主要两点还体现在:Nginx本身就是一个反向代理服务器;Nginx支持7层负载均衡;其他的当然,Nginx可能会比apache支持更高的并发;Aapche因为其成熟的技术和开发社区,总体来说也有非常不错的性能,很多大公司而言还比较青睐apache。
10)你对web server的需求决定你的选择。大部分情况下nginx都优于apache,比如说静态文件处理、PHP-CGI的支持、反向代理功能、前端Cache、维持连接等等。在Apache+PHP(prefork)模式下,如果PHP处理慢或者前端压力很大的情况下,很容易出现Apache进程数飙升,从而拒绝服务的现象。
11)对于nginx,我喜欢它配置文件写的很简洁,正则配置让很多事情变得简单运行效率高,占用资源少,代理功能强大,很适合做前端响应服务器
12)Apache在处理动态有优势,Nginx并发性比较好,CPU内存占用低,如果rewrite频繁,那还是Apache更好。
三、在 Linux 下安装 Nginx
为了确保能在Nginx中使用正则表达式进行更灵活的配置,安装之前需要确定系统是否安装有PCRE(Perl Compatible Regular Expressions)包。
您可以到ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/下载最新的PCR 源码包,使用下面命令下载编译和安装 PCRE 包:
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-7.7.tar.gz
# tar zxvf pcre-7.7.tar.gz
# cd pcre-7.7
# ./configure
# make
# make install
接下来安装 Nginx,Nginx 一般有两个版本,分别是稳定版和开发版,您可以根据您的目的来选择这两个版本的其中一个,下面是把 Nginx 安装到 /opt/nginx 目录下的详细步骤:
# wget http://sysoev.ru/nginx/nginx-0.6.31.tar.gz
# tar zxvf nginx-0.6.31.tar.gz
# cd nginx-0.6.31
# ./configure –with-http_stub_status_module –prefix=/opt/nginx
# make
# make install
其中参数 –with-http_stub_status_module 是为了启用 nginx 的 NginxStatus 功能,用来监控 Nginx 的当前状态。
安装成功后/opt/nginx 目录下有四个子目录分别是:conf、html、logs、sbin 。
其中Nginx的配置文件存放于conf/nginx.conf,Nginx只有一个程序文件位于sbin目录下的nginx文件。
确保系统的80端口没被其他程序占用,运行sbin/nginx命令来启动Nginx,打开浏览器访问此机器的 IP,如果浏览器出现 Welcome to nginx! 则表示 Nginx 已经安装并运行成功。
常用的 Nginx 参数和控制
程序运行参数
Nginx 安装后只有一个程序文件,本身并不提供各种管理程序,它是使用参数和系统信号机制对 Nginx 进程本身进行控制的。 Nginx 的参数包括有如下几个:
-c <path_to_config>:使用指定的配置文件而不是 conf 目录下的 nginx.conf 。
-t:测试配置文件是否正确,在运行时需要重新加载配置的时候,此命令非常重要,用来检测所修改的配置文件是否有语法错误。
-v:显示 nginx 版本号。
-V:显示 nginx 的版本号以及编译环境信息以及编译时的参数。
例如我们要测试某个配置文件是否书写正确,我们可以使用以下命令
sbin/nginx – t – c conf/nginx2.conf
———————————————————————————————
当一台服务器中启用多个实例的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 进行控制
Nginx 支持下表中的信号:
有两种方式来通过这些信号去控制Nginx:
第一是通过logs目录下的nginx.pid查看当前运行的Nginx的进程ID,通过 kill – XXX <pid> 来控制 Nginx,其中 XXX 就是上表中列出的信号名。
如果系统中只有一个Nginx进程,那也可以通过 killall 命令来完成,例如运行 killall – s HUP nginx 来让 Nginx 重新加载配置。
配置 Nginx
先来看一个实际的配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
user nobody; # 工作进程的属主 worker_processes 4; # 工作进程数,一般与 CPU 核数等同 #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { use epoll; #Linux 下性能最好的 event 模式 worker_connections 2048; # 每个工作进程允许最大的同时连接数 } http { include mime.types; default_type application /octet-stream ; #log_format main '$remote_addr - $remote_user [$time_local] $request ' # '"$status" $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"'; #access_log off; access_log logs /access .log; # 日志文件名 sendfile on; #tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; include gzip .conf; # 集群中的所有后台服务器的配置信息 upstream tomcats { server 192.168.0.11:8080 weight=10; server 192.168.0.11:8081 weight=10; server 192.168.0.12:8080 weight=10; server 192.168.0.12:8081 weight=10; server 192.168.0.13:8080 weight=10; server 192.168.0.13:8081 weight=10; } server { listen 80; #HTTP 的端口 server_name localhost; charset utf-8; #access_log logs/host.access.log main; location ~ ^ /NginxStatus/ { stub_status on; #Nginx 状态监控配置 access_log off; } location ~ ^/(WEB-INF)/ { deny all; } location ~ \.(htm|html|asp|php|gif|jpg|jpeg|png|bmp|ico|rar|css|js| zip|java|jar|txt|flv|swf|mid|doc|ppt|xls|pdf|txt|mp3|wma)$ { root /opt/webapp ; expires 24h; } location / { proxy_pass http: //tomcats ; # 反向代理 include proxy.conf; } error_page 404 /html/404 .html; # redirect server error pages to the static page /50x.html # error_page 502 503 /html/502 .html; error_page 500 504 /50x .html; location = /50x .html { root html; } } } |
Nginx 监控
上面是一个实际网站的配置实例,其中#号后面的文字为配置说明。
上述配置中,首先我们定义了一个 location ~ ^/NginxStatus/,这样通过 http://localhost/NginxStatus/ 就可以监控到 Nginx 的运行信息,显示的内容如下:
Active connections: 70
server accepts handled requests
14553819 14553819 19239266
Reading: 0 Writing: 3 Waiting: 67
NginxStatus 显示的内容意思如下:
active connections – 当前 Nginx 正处理的活动连接数。
server accepts handled requests — 总共处理了 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;
expires 24h;
}
对于例如图片、静态 HTML 文件、js 脚本文件和 css 样式文件等,我们希望 Nginx 直接处理并返回给浏览器,这样可以大大的加快网页浏览时的速度。因此对于这类文件我们需要通过 root 指令来指定文件的存放路径,同时因为这类文件并不常修改,通过 expires 指令来控制其在浏览器的缓存,以减少不必要的请求。 expires 指令可以控制 HTTP 应答中的“ Expires ”和“ Cache-Control ”的头标(起到控制页面缓存的作用)。您可以使用例如以下的格式来书写 Expires:
expires 1 January, 1970, 00:00:01 GMT;
expires 60s;
expires 30m;
expires 24h;
expires 1d;
expires max;
expires off;
动态页面请求处理
Nginx 本身并不支持现在流行的 JSP、ASP、PHP、PERL 等动态页面,但是它可以通过反向代理将请求发送到后端的服务器,例如 Tomcat、Apache、IIS 等来完成动态页面的请求处理。前面的配置示例中,我们首先定义了由 Nginx 直接处理的一些静态文件请求后,其他所有的请求通过 proxy_pass 指令传送给后端的服务器(在上述例子中是 Tomcat)。最简单的 proxy_pass 用法如下:
location / {
proxy_pass http://localhost:8080;
proxy_set_header X-Real-IP $remote_addr;
}
这里我们没有使用到集群,而是将请求直接送到运行在 8080 端口的 Tomcat 服务上来完成类似 JSP 和 Servlet 的请求处理。
当页面的访问量非常大的时候,往往需要多个应用服务器来共同承担动态页面的执行操作,这时我们就需要使用集群的架构。 Nginx 通过 upstream 指令来定义一个服务器的集群,最前面那个完整的例子中我们定义了一个名为 tomcats 的集群,这个集群中包括了三台服务器共 6 个 Tomcat 服务。而 proxy_pass 指令的写法变成了:
location / {
proxy_pass http://tomcats;
proxy_set_header X-Real-IP $remote_addr;
}
在 Nginx 的集群配置中,Nginx 使用最简单的平均分配规则给集群中的每个节点分配请求。一旦某个节点失效时,或者重新起效时,Nginx 都会非常及时的处理状态的变化,以保证不会影响到用户的访问。
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
}
产生的效果如下:
访问根目录/, 比如http://localhost/ 将匹配规则A
访问http://localhost/login 将匹配规则B,http://localhost/register 则匹配规则H
访问http://localhost/static/a.html 将匹配规则C
访问http://localhost/a.gif, http://localhost/b.jpg 将匹配规则D和规则E,但是规则D顺序优先,规则E不起作用, 而 http://localhost/static/c.png 则优先匹配到 规则C
访问http://localhost/a.PNG 则匹配规则E, 而不会匹配规则D,因为规则E不区分大小写。
访问http://localhost/a.xhtml 不会匹配规则F和规则G,http://localhost/a.XHTML不会匹配规则G,因为不区分大小写。规则F,规则G属于排除法,符合匹配规则但是不会匹配到,所以想想看实际应用中哪里会用到。
访问http://localhost/category/id/1111 则最终匹配到规则H,因为以上规则都不匹配,这个时候应该是nginx转发请求给后端应用服务器,比如FastCGI(php),tomcat(jsp),nginx作为方向代理服务器存在。
所以实际使用中,至少有三个匹配规则定义,如下:
直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。
这里是直接转发给后端应用服务器了,也可以是一个静态首页
第一个必选规则
location = / {
proxy_pass http://tomcat:8080/index
}
第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项
有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用
location ^~ /static/ {
root /webroot/static/;
}
location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ {
root /webroot/res/;
}
第三个规则就是通用规则,用来转发动态请求到后端应用服务器
非静态文件请求就默认是动态请求,自己根据实际把握
毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了
location / {
proxy_pass http://tomcat:8080/
}
尽管Nginx整个程序包只有500多K,但麻雀虽小、五脏俱全。 Nginx官方提供的各种功能模块应有尽有,结合这些模块可以完整各种各样的配置要求,例如:压缩、防盗链、集群、FastCGI、流媒体服务器、Memcached 支持、URL 重写等等,更关键的是Nginx拥有Apache和其他HTTP服务器无法比拟的高性能。甚至可以在不改变原有网站的架构上,通过在前端引入Nginx做负载均衡来提升网站的访问速度。
——————————————————-下面对Nginx的一些特殊设置做一说明——————————————————-
nginx的全局变量
——————————————————————————–
remote_addr 客户端ip,如:192.168.4.2
binary_remote_addr 客户端ip(二进制)
remote_port 客户端port,如:50472
remote_user 已经经过Auth Basic Module验证的用户名
host 请求主机头字段,否则为服务器名称,如:dwz.stamhe.com
request 用户请求信息,如:GET /?_a=index&_m=show&count=10 HTTP/1.1
request_filename 当前请求的文件的路径名,由root或alias和URI request组合而成,如:/webserver/htdocs/dwz/index.php
status 请求的响应状态码,如:200
body_bytes_sent 响应时送出的body字节数数量。即使连接中断,这个数据也是精确的,如:40
content_length 请求头中的Content-length字段
content_type 请求头中的Content-Type字段
http_referer 引用地址
http_user_agent 客户端agent信息,如:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11
args 如:_a=index&_m=show&count=10
document_uri 与$uri相同,如:/index.php
document_root 针对当前请求的根路径设置值,如:/webserver/htdocs/dwz
hostname 如:centos53.localdomain
http_cookie 客户端cookie信息
cookie_COOKIE cookie COOKIE变量的值
is_args 如果有$args参数,这个变量等于”?”,否则等于””,空值,如?
limit_rate 这个变量可以限制连接速率,0表示不限速
query_string 与$args相同,如:_a=index&_m=show&count=10
realpath_root 如:/webserver/htdocs/dwz
request_body 记录POST过来的数据信息
request_body_file 客户端请求主体信息的临时文件名
request_method 客户端请求的动作,通常为GET或POST,如:GET
request_uri 包含请求参数的原始URI,不包含主机名,如:”/foo/bar.php?arg=baz”。不能修改。如:/index.php?_a=index&_m=show&count=10
scheme HTTP方法(如http,https),如:http
uri 如:/index.php
request_completion 如果请求结束,设置为OK. 当请求未结束或如果该请求不是请求链串的最后一个时,为空(Empty),如:OK
server_protocol 请求使用的协议,通常是HTTP/1.0或HTTP/1.1,如:HTTP/1.1
server_addr 服务器地址,在完成一次系统调用后可以确定这个值,如:192.168.4.129
server_name 服务器名称,如:dwz.stamhe.com
server_port 请求到达服务器的端口号,如:80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
比如访问https: //www .wangshibo.com /HouseGroup/index .html,跳转到https: //www .wangshibo.com /index .php?r=houseGroup /index rewrite ^/(.*) /index .html https: //www .wangshibo.com /index .php?r=$1 /index ; if ($request_uri ~* "/(jkhwpc|jkhw|jkhwadmin).php" ) { rewrite ^/(.*)$ http: //www .jikehaiwai.com/$1 last; } if ($request_uri ~* "/(qjspc|qjsmob|qjsadmin).php" ) { rewrite ^/(.*)$ http: //www .qianjins.com/$1 last; } -----------可以参考下面nginx的rewrite伪静态设置--------- rewrite ^(.*) /equip (d+).html$ $1 /index .php?m=content&c=index&a=lists&catid=$2 last; # nginx rewrite rule rewrite ^(.*) /archiver/ ((fid|tid)-[w-]+.html)$ $1 /archiver/index .php?$2 last; rewrite ^(.*) /forum- ([0-9]+)-([0-9]+).html$ $1 /forumdisplay .php?fid=$2&page=$3 last; rewrite ^(.*) /thread- ([0-9]+)-([0-9]+)-([0-9]+).html$ $1 /viewthread .php?tid=$2&extra=page%3D$4&page=$3 last; rewrite ^(.*) /profile- (username|uid)-(.+).html$ $1 /viewpro .php?$2=$3 last; rewrite ^(.*) /space- (username|uid)-(.+).html$ $1 /space .php?$2=$3 last; rewrite ^(.*) /tag- (.+).html$ $1 /tag .php?name=$2 last; rewrite ^/(.*)\.(asp|aspx|asa|asax|dll|jsp|cgi|fcgi|pl)(.*)$ /404 .php last; rewrite ^/(.*)/(admin|cache|editor| file |include|lang|module|skin|template)/(.*)\.php(.*)$ /404 .php last; rewrite ^/(.*)-htm-(.*)$ /$1.php?$2 last; rewrite ^/(.*) /show- ([0-9]+)([\-])?([0-9]+)?\.html$ /$1 /show .php?itemid=$2&page=$4 last; rewrite ^/(.*) /list- ([0-9]+)([\-])?([0-9]+)?\.html$ /$1 /list .php?catid=$2&page=$4 last; rewrite ^/(.*) /show/ ([0-9]+)/([0-9]+)?([/])?$ /$1 /show .php?itemid=$2&page=$3 last; rewrite ^/(.*) /list/ ([0-9]+)/([0-9]+)?([/])?$ /$1 /list .php?catid=$2&page=$3 last; rewrite ^/(.*)/([A-za-z0-9_\-]+)-c([0-9]+)-([0-9]+)\.html$ /$1 /list .php?catid=$3&page=$4 last; rewrite ^/(.*)/([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /$1 /index .php?moduleid=$2&catid=$3&itemid=$4&page=$5 last; rewrite ^(.*)/([a-z]+)/(.*)\.shtml$ $1/$2 /index .php?rewrite=$3 last; rewrite ^/(com)/([a-z0-9_\-]+)/([a-z]+)/(.*)\.html$ /index .php?homepage=$2& file =$3&rewrite=$4 last; rewrite ^/(com)/([a-z0-9_\-]+)/([a-z]+)([/])?$ /index .php?homepage=$2& file =$3 last; rewrite ^/(com)/([a-z0-9_\-]+)([/])?$ /index .php?homepage=$2 last; |
——————————————————————————–
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用来判断文件是否可执行
先来看几个小例子说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
例如下面这段设定nginx将某个目录下面的文件重定向到另一个目录,$2对应第二个括号(.*)中对应的字符串: location /download/ { rewrite ^( /download/ .*) /m/ (.*)\..*$ $1 /nginx-rewrite/ $2.gz break ; } ----------------------------------------------------------------------------------- 例如当用户输入 www.a.com.cn 自动跳转到www.a.com 这个域名: rewrite ^/(.*)$ http: //www .a.com/$1 permanent; ----------------------------------------------------------------------------------- 例如下面设定nginx在用户使用ie的使用重定向到 /nginx-ie 目录下: if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /nginx-ie/ $1 break ; } ----------------------------------------------------------------------------------- 例如当用户访问testxqsjapi.xqshijie.com域名时跳转到本机的9501端口 upstream lb-9501 { server 127.0.0.1:9501; } server { listen 80; server_name testxqsjapi.xqshijie.com; root /var/www/vhosts/testxqsjapi .xqshijie.com/; location / { proxy_pass http: //lb-9501 ; } } ---------------------------------------------------------------------------------- 例如下面一例:nginx rewrite 实现二级域名跳转 当访问http: //abc .wangshibo.com跳转到http: //www .wangshibo.com /wangshibo/abc/ 方法一:这种方法浏览器地址会变www.wangshibo.com /wangshibo/abc server { listen 80; server_name www.wangshibo.com; location / { root /data/wangshibo ; index index.html; } } server { listen 80; server_name *.wangshibo.com; if ( $http_host ~* "^(.*)\.wangshibo\.com$" ) { set $domain $1; rewrite ^(.*) http: //www .wangshibo.com /wangshibo/ $domain/ break ; } } 方法二:当访问http: //abc .wangshibo.com跳转到http: //www .wangshibo.com /wangshibo/abc/ server { listen 80; server_name *.wangshibo.com; root /usr/local/www ; #这是里可以加多个目录,如果不加目录,会无法访问到abc.wangshibo.com/目录下的文件,如图片目录/images location ~ ^/(wangshibo|images|styles)/ { proxy_redirect off; proxy_set_header Host www.wangshibo.com; proxy_pass http: //192 .168.1.2:8080; } location / { set $domain default; if ( $http_host ~* "^(.*)\.wangshibo\.com$" ) { set $domain $1; } rewrite ^/(.*) /wangshibo/ $domain/$1 last; } access_log off; } |
再接着看下面的实例说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。 #这里是直接转发给后端应用服务器了,也可以是一个静态首页 # 第一个必选规则 location = / { proxy_pass http: //tomcat :8080 /index } # 第二个必选规则是处理静态文件请求,这是nginx作为http服务器的强项 # 有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用 location ^~ /static/ { root /webroot/static/ ; } location ~* \.(gif|jpg|jpeg|png|css|js|ico)$ { root /webroot/res/ ; } #第三个规则就是通用规则,用来转发动态请求到后端应用服务器 #非静态文件请求就默认是动态请求,自己根据实际把握 #毕竟目前的一些框架的流行,带.php,.jsp后缀的情况很少了 location / { proxy_pass http: //tomcat :8080/ } |
2)实例说明
1)访问A站跳转(重定向)到B站
server {
listen 80;
server_name www.wangshibo.com ;
rewrite ^(.*) http://www.huanqiu.com$1 permanent;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
访问wangshibo.com跳转到www.wangshibo.com server { listen 80; server_name www.wangshibo.com wangshibo.com; index index.jsp index.html index.php index.htm; root /var/www/html ; access_log /usr/local/nginx/logs/image .log; if ($host = "wangshibo.com" ) { rewrite ^/(.*)$ http: //www .wangshibo.com permanent; } } |
2)多域名绑定一个目录,并且全部301跳转到其中一个域名(注意:多域名都要解析到本机ip上)
server {
listen 80;
server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
if ($host != ‘www.wangshibo.com’) {
rewrite ^/(.*)$ http://www.wangshibo.com/$1 permanent;
}
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
上面说明访问http://web01.wangshibo.com、http://hehe.wangshibo.com、http://wangshibo.com的时候都会自动跳转到
http://www.wangshibo.com,并且浏览器地址会显示跳转后的URL地址。
如果是上面多域名访问后都重定向跳转到http://hehe.wangshibo.com,则配置修改如下:
server {
listen 80;
server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
if ($host != ‘hehe.wangshibo.com’) {
rewrite ^/(.*)$ http://hehe.wangshibo.com/$1 permanent;
}
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
如下配置:多域名中的某个域名访问时发生跳转,其他域名访问时不跳转
server {
listen 80;
server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com;
if ($host = ‘hehe.wangshibo.com’) {
rewrite ^/(.*)$ http://www.huanqiu.com/$1 permanent;
}
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
3)将多级目录下的文件转成一个文件,增强seo效果
比如将/wang-123-456-789.html指向wang/123/456/wangshow_789.html
[root@test-huanqiu ~]# cat /usr/local/nginx/conf/vhosts/test.conf
server {
listen 80;
server_name www.wangshibo.com;
rewrite ^/wang-([0-9]+)-([0-9]+)-([0-9]+)\.html$ http://www.wangshibo.com/wang/$1/$2/wangshow_$3.html last;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
这样访问http://www.wangshibo.com/wang-123-456-789.html就会跳转到http://www.wangshibo.com/wang/123/456/wangshow_789.html
4)访问的目标文件和目录资源不存在的时候重定向跳转
如下配置,当访问http://www.wangshibo.com/后面的访问资源(文件或目录)不存在时,统统跳转到http://www.wangshibo.com/sorry.html页面
server {
listen 80;
server_name www.wangshibo.com;
if (!-e $request_filename) {
rewrite ^/ http://www.wangshibo.com/sorry.html ;
}
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
5)将站点根目录下某个目录指向二级目录
例如将/huanqiupc/指向/ops/huanqiu/,配置如下:
server {
listen 80;
server_name www.wangshibo.com;
rewrite ^/([0-9a-z]+)pc/(.*)$ http://www.wangshibo.com/ops/$1/$2 last;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
这样,访问http://www.wangshibo.com/huanqiupc的时候就会跳转到http://www.wangshibo.com/ops/huanqiu/
注意:上面的配置中的last修改为permanent或redirect都可以
以上的配置也适用于:(前提是这些目录要真是存在于站点目录/var/www/html/中,并且权限要正确)
将/wangshibopc/指向/ops/wangshibo/
将/guohuihuipc/指向/ops/guohuihui/
将/hahapc/指向/ops/haha/
……
6)其他的rewrite跳转规则的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
server { listen 80; server_name www.wangshibo.com; root /var/www/html ; index index.html index.htm; rewrite ^ /site/resource/ (.*)$ https: //www .wangshibo.com /resource/ $1 last; rewrite ^ /active/Ymf .html$ https: //www .wangshibo.com /project/detail .html?project_id=1 last; rewrite ^ /active/Ysyg .html$ https: //www .wangshibo.com /project/detail .html?project_id=7 last; if ($host ~* "^wangshibo.com$" ) { rewrite ^/(.*)$ https: //www .wangshibo.com/ permanent; } location / { rewrite /abc http: //www .huanqiu.com break ; #本机站点目录下并不需要真实存在abc这个目录,对虚拟目录的访问都重写到http://www.huanqiu.com } #即访问http://www.wangshibo.com/abc,跳转到http://www.huanqiu.com location /text { rewrite / http: //china .huanqiu.com break ; #本机站点目录下需要真实存在text目录,对其的访问都重写到http://china.huanqiu.com } #即访问http://www.wangshibo.com/text,跳转到http://china.huanqiu.com } |
下面一例:访问http://www.wangshibo.com/g/4HG45SkZ 实际访问地址跳转为 http://110.10.88.99:8081/qun/share/view?code=4HG45SkZ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
upstream g_server { keepalive 64; server 110.10.88.99:8081 max_fails=2 fail_timeout=5 weight=100; } server { listen 80; server_name www.wangshibo.com; rewrite ^/bcloud.(swf|html|js)(.*)$ http: //hehe.wangshibo.com/bcloud.$1$2 last; root /home/web/www; location ~ \.apk$ { max_ranges 0; } location ^~ /g { proxy_redirect off; proxy_set_header Host $host; # proxy_set_header Host $host:$remote_port; # proxy_set_header REMOTE_PORT $remote_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; client_max_body_size 1G; client_body_buffer_size 256k; proxy_connect_timeout 30; proxy_send_timeout 30; proxy_read_timeout 600; proxy_buffer_size 16k; proxy_buffers 4 32k; proxy_temp_file_write_size 64k; proxy_pass http: //g_server; #rewrite "/g/(.*$)" www.wangshibo.com/qun/share/view?code=$1 break; rewrite "/g/(.*$)" /qun/share/view?code=$1 break ; } } |
另外注意:
$1表示第一个变量,即前面rewrite后第一个()内设置的变量
$2表示第二个变量,即前面rewrite后第二个()内设置的变量
再看一例:
访问http://www.wangshibo.com/thumb/transcode 实际访问地址为 http://120.170.190.99:28080/transcode/thumb/transcode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
upstream thumb { keepalive 64; server 120.170.190.99:28080 max_fails=2 fail_timeout=5 weight=100; } server { listen 80; server_name www.wangshibo.com ; root /home/web/www; location ^~ /thumb { proxy_pass http: //thumb; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for; client_max_body_size 1G; client_body_buffer_size 256k; proxy_connect_timeout 30; proxy_send_timeout 30; proxy_read_timeout 60; proxy_buffer_size 16k; proxy_buffers 4 32k; proxy_temp_file_write_size 64k; rewrite "^/(.*)$" /transcode/$1 break ; } } |
—————————-再看一个访问nginx跳转后的url不变的例子————————————–
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
需要特别注意的是: proxy_pass 反向代理,可以实现只改变跳转后的内容,而跳转后的原url保持不变! rewrite 重写跳转后会进行重定向,很难实现跳转后的原url不变的需求。 看看之前踩过的坑; 要求访问http: //wx2 .xqshijie.com /apiwx2/xqsj .php?r=houseGroup%2FgetToken,内容跳转到http: //m .xqshijie.com /xqsj .php?r=houseGroup%2FgetToken,但是跳转后的url保持不变! 这是根据path路径进行反向代理的配置,即要求访问http: //wx2 .xqshijie.com /apiwx2/ $1 跳转到http: //m .xqshijie.com/$1,跳转后的url不变! 配置如下: [root@fangfull_web1 vhosts] # cat wx2.xqshijie.com.conf server { listen 80; server_name wx2.xqshijie.com; root /Data/app/xqsj_wx2/dist ; index index.html; #if ($http_x_forwarded_for !~ ^(124.65.197.154|103.10.86.28|103.10.86.8)) { # rewrite ^.*$ /maintence.php last; #} location /apiwx2/ { proxy_pass https: //m .xqshijie.com/; } access_log /var/log/betawx2 .log main; location / { try_files $uri $uri/ @router; index index.html; } #rewrite ^(.+)$ /index.html last; location @router { rewrite ^.*$ /index .html last; } } 根据上面配置后,就可以实现访问http: //wx2 .xqshijie.com /apiwx2/xqsj .php?r=houseGroup%2FgetToken,实际显示的是https: //m .xqshijie.com /xqsj .php?r=houseGroup%2FgetToken的内容,但是跳转后的原来的url不变! 如果采用rewrite重写规则,即将: location /apiwx2/ { proxy_pass https: //m .xqshijie.com/; } 改为 location /apiwx2/ { rewrite ^ /apiwx2 (.*)$ https: //m .xqshijie.com.$1 last; } 那么,访问http: //wx2 .xqshijie.com /apiwx2/xqsj .php?r=houseGroup%2FgetToken,实际显示的是https: //m .xqshijie.com /xqsj .php?r=houseGroup%2FgetToken的内容,但是跳转后的url已经变了! 上面碰到过的坑: 由于访问http: //m .xqshijie.com就会自动跳转到https: //m .xqshijie.com,所以如果将上面的配置改为(即将https: //m .xqshijie.com改为http: //m .xqshijie.com): location /apiwx2/ { proxy_pass http: //m .xqshijie.com/; } 这样,访问http: //wx2 .xqshijie.com /apiwx2/xqsj .php?r=houseGroup%2FgetToken,实际显示的是https: //m .xqshijie.com /xqsj .php?r=houseGroup%2FgetToken的内容,但是跳转后的原来的url已经变了! 原因是因为这里经过了两次跳转,即rewrite->http->https,所以跳转后的url变了。 解决办法:就是直接rewrite跳转到https,即proxy_pass https: //m .xqshijie.com/; |
—————————-下面的跳转规则表示—————————————
访问http://www.wangshibo.com/wangshibo/ops就会跳转到http://www.wangshibo.com/ops/wangshibo
访问http://www.wangshibo.com/wangshibo/beijing就会跳转到http://www.wangshibo.com/beijing/wangshibo
……
即由”wangshibo/变量”–>”变量/wangshibo”
1
2
3
4
5
6
7
8
|
server { listen 80; server_name www.wangshibo.com; rewrite ^/wangshibo/(.*)$ http: //www.wangshibo.com/$1/wangshibo last; root / var /www/html; index index.html index.php index.htm; access_log /usr/local/nginx/logs/image.log; } |
访问http://www.wangshibo.com/ops/web 跳转到 http://www.wangshibo.com/web/ops/web/
1
2
3
4
5
6
7
8
|
server { listen 80; server_name www.wangshibo.com; rewrite ^ /ops/ (.*)$ http: //www .wangshibo.com/$1 /ops/ $1 break ; root /var/www/html ; index index.html index.php index.htm; access_log /usr/local/nginx/logs/image .log; } |
访问http://www.wangshibo.com/wang/123 实际访问地址跳转为 http://www.hehe.com/qun/share/view?code=123
1
2
3
4
5
6
7
8
|
server { listen 80; server_name www.wangshibo.com; rewrite ^ /wang/ (.*)$ http: //www .hehe.com /qun/share/view ?code=$1 last; root /var/www/html ; index index.html index.php index.htm; access_log /usr/local/nginx/logs/image .log; } |
其他配置实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
如果nginx在用户使用IE浏览器访问情况下,则重定向到 /nginx-ie 目录下 配置如下: if ($http_user_agent ~ MSIE) { rewrite ^(.*)$ /nginx-ie/ $1 break ; } 多目录转成参数 abc.domian.com /sort/2 => abc.domian.com /index .php?act= sort &name=abc& id =2 配置如下: if ($host ~* (.*)\.domain\.com) { set $sub_name $1; rewrite ^ /sort \/(\d+)\/?$ /index .php?act= sort &cid=$sub_name& id =$1 last; } 目录自动加 "/" ,前提是访问目录存在 配置如下: if (-d $request_filename){ rewrite ^/(.*)([^/])$ http: // $host/$1$2/ permanent; } 三级域名跳转 配置如下: if ($http_host ~* “^(.*)\.i\.beijing\.com$”) { rewrite ^(.*) http: //www .wangshibo.com$1/; break ; } 针对站点根目录下的某个子目录作镜向 配置如下:就会把http: //www .huanqiu.com的内容(即首页)镜像到 /var/www/html 下的ops目录下了 server { listen 80; server_name www.wangshibo.com; root /var/www/html ; location ^~ /ops { rewrite ^.+ http: //www .huanqiu.com/ last; break ; } index index.html index.php index.htm; access_log /usr/local/nginx/logs/image .log; } 域名镜像(其实就是域名跳转) server { listen 80; server_name www.wangshibo.com; root /var/www/html ; rewrite ^/(.*) http: //www .huanqiu.com/$1 last; index index.html index.php index.htm; access_log /usr/local/nginx/logs/image .log; } 其他: rewrite ^/(space|network)-(.+)\.html$ /$1.php?rewrite=$2 last; rewrite ^/(space|network)\.html$ /$1.php last; rewrite ^/([0-9]+)$ /space .php?uid=$1 last; rewrite ^(.*) /archiver/ ((fid|tid)-[\w\-]+\.html)$ $1 /archiver/index .php?$2 last; rewrite ^(.*) /forum- ([0-9]+)-([0-9]+)\.html$ $1 /forumdisplay .php?fid=$2&page=$3 last; rewrite ^(.*) /thread- ([0-9]+)-([0-9]+)-([0-9]+)\.html$ $1 /viewthread .php?tid=$2&extra=page\%3D$4&page=$3 last; rewrite ^(.*) /profile- (username|uid)-(.+)\.html$ $1 /viewpro .php?$2=$3 last; rewrite ^(.*) /space- (username|uid)-(.+)\.html$ $1 /space .php?$2=$3 last; rewrite ^(.*) /tag- (.+)\.html$ $1 /tag .php?name=$2 last; |
目录对换:/1234/xxx —–>xxx?id=1234
配置如下:
[root@test-huanqiu ~]# vim /usr/local/nginx/conf/vhosts/test.conf
server {
listen 80;
server_name www.wangshibo.com;
root /var/www/html;
rewrite ^/(\d+)/(.+)/ /$2?id=$1 last;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
[root@test-huanqiu ~]# cat /var/www/html/ops/index.html
nginx的目录对换的跳转测试
如上配置后,那么:
访问http://www.wangshibo.com/?id=567567567567567 的结果就是http://www.wangshibo.com/的结果
访问http://www.wangshibo.com/ops/?id=wangshibo 的结果就是http://www.wangshibo.com/ops的结果
访问http://www.wangshibo.com/wang/?id=123111 的结果就是http://www.wangshibo.com/wang的结果
…….
2.反向代理(proxy_pass)
简单测试nginx反向代理和负载均衡功能的操作记录(1)—–http代理
简单测试nginx反向代理和负载均衡功能的操作记录(2)—–https代理
3.缓存设置
nginx反向代理+缓存开启+url重写+负载均衡(带健康探测)的部署记录
nginx缓存配置的操作记录梳理
4.防盗链。关于Nginx防盗链具体设置,可参考:Nginx中防盗链(下载防盗链和图片防盗链)的操作记录
location ~* \.(gif|jpg|swf)$ {
valid_referers none blocked start.igrow.cn sta.igrow.cn;
if ($invalid_referer) {
rewrite ^/ http://$host/logo.png;
}
}
下面设置文件反盗链并设置过期时间:
location ~*^.+\.(jpg|jpeg|gif|png|swf|rar|zip|css|js)$ {
valid_referers none blocked *.wangshibo.com*.wangshibo.net localhost 218.197.67.14;
if ($invalid_referer) {
rewrite ^/ http://img.wangshibo.net/leech.gif;
return 412;
break;
}
access_log off;
root /opt/lampp/htdocs/web;
expires 3d;
break;
}
这里的return 412 是自定义的http状态码,默认为403,方便找出正确的盗链的请求
“rewrite ^/ http://img.wangshibo.net/leech.gif;”显示一张防盗链图片
“access_log off;”不记录访问日志,减轻压力
“expires 3d”所有文件3天的浏览器缓存
5.根据文件类型设置过期时间
1)expires起到控制页面缓存的作用,合理的配置expires可以减少很多服务器的请求;
2)对于站点中不经常修改的静态内容(如图片,JS,CSS),可以在服务器中设置expires过期时间,控制浏览器缓存,达到有效减小带宽流量,降低服务器压力的目的。
3)Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。
要配置expires,可以在http段中或者server段中或者location段中加入;
如下:控制图片等过期时间为30天,如果图片文件不怎么更新,过期可以设大一点;如果频繁更新,则可以设置得小一点,具体视情况而定
location ~ \.(gif|jpg|jpeg|png|bmp|swf|ico)$ {
root /var/www/img/;
expires 30d;
}
location ~ .*\.(js|css)$ {
expires 10d;
}
location ~* \.(js|css|jpg|jpeg|gif|png|swf)$ {
if (-f $request_filename) {
expires 1h;
break;
}
}
location ~ \.(wma|wmv|asf|mp3|mmf|zip|rar|swf|flv)$ {
root /var/www/upload/;
expires max;
}
expires 指令可以控制 HTTP 应答中的“ Expires ”和“ Cache-Control ”的头标(起到控制页面缓存的作用)
语法:expires [time|epoch|max|off]
默认值:off
expires指令控制HTTP应答中的“Expires”和“Cache-Control”Header头部信息,启动控制页面缓存的作用
time:可以使用正数或负数。“Expires”头标的值将通过当前系统时间加上设定time值来设定。
time值还控制”Cache-Control”的值:
负数表示no-cache
正数或零表示max-age=time
epoch:指定“Expires”的值为 1 January,1970,00:00:01 GMT
max:指定“Expires”的值为31 December2037 23:59:59GMT,”Cache-Control”的值为10年。(即设置过期时间最最长)
-1:指定“Expires”的值为当前服务器时间-1s,即永远过期。
off:不修改“Expires”和”Cache-Control”的值
expires使用了特定的时间,并且要求服务器和客户端的是中严格同步。
而Cache-Control是用max-age指令指定组件被缓存多久。
对于不支持http1.1的浏览器,还是需要expires来控制。所以最好能指定两个响应头。但HTTP规范规定max-age指令将重写expires头。
如何检测nginx中设置的expires网页过期时间是否生效?
方法:
打开webkaka的网站速度诊断工具(http://pagespeed.webkaka.com/),输入你的网页地址,检测后,立即可以看到设置是否生效了。如下图所示:
上图可以看到,被检测网页的js文件过期时间为1天(12h)。
6.禁止访问某个文件或目录
1)禁止访问以txt或doc结尾的文件
location ~* \.(txt|doc)${
root /data/www/wwwroot/linuxtone/test;
deny all;
}
2)nginx禁止访问所有.开头的隐藏文件设置
location ~* /.* {
deny all;
}
3)nginx禁止访问目录
location ^~ /path {
deny all;
}
4)禁止访问扩展名为bat的文件
location ~* /.bat {
deny all;
}
5)禁止访问configs目录,以及其下所有子目录或文件
location ^~ /configs/ {
deny all;
}
注意上述configs后面的斜杠不能少,否则所有以configs开头的目录或文件都将禁止访问。
6)禁止访问多个目录
location ~ ^/(cron|templates)/ {
deny all;
break;
}
7)禁止访问以/data开头的文件
location ~ ^/data {
deny all;
}
8)禁止访问以.sh,.flv,.mp3为文件后缀名的文件
location ~ .*\.(sh|flv|mp3)$ {
return 403;
}
9)或者以=符号形式
location = /config/ {
return 404;
}
location =/config.ini{
return 404;
}
10)禁止htaccess
location ~/\.ht {
deny all;
}
return指令
语法:returncode ;
使用环境:server,location,if;
该指令用于结束规则的执行并返回状态码给客户端。
例如:访问的URL以”.sh”或”.bash”结尾,则返回403状态码
location ~ .*\.(sh|bash)?$ {
return 403;
}
7.禁止IP访问 只允许域名访问
当别人通过ip或者未知域名访问你的网站的时候,你希望禁止显示任何有效内容,可以给他返回500.
目前国内很多机房都要求网站主关闭空主机头,防止未备案的域名指向过来造成麻烦。
为了避免网站遭受恶意IP攻击,需要禁止IP访问,只能使用域名访问站点!
listen行加上default(或default_server)参数,表示这个是默认虚拟主机。
所以,禁止ip访问,只能使用域名访问的正确配置是:
server {
listen 80 default;
server_name _;
return 500;
}
server {
listen 80;
server_name web01.wangshibo.cn;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
注意:
如果在上面的server_name配置中指定域名的同时,也指明了ip访问,比如server_name 103.110.186.17 web01.wangshibo.cn
那么尽管上面已经做了返回500设置,也禁止不了ip访问!也就是说,只要server_name一行指明了ip访问,那么就禁止不了了。
以上设置,可以将ip访问禁用,这样的话,使用ip访问的流量就会丢失。
如果想把这部分流量收集起来,导入到自己的网站,只要做以下跳转设置就可以:
server {
listen 80 default;
rewrite ^(.*) http://www.wangshibo.com permanent;
}
server {
listen 80;
server_name web01.wangshibo.cn;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
下面列出其他的一些细节导致的不同效果:
1)将ip和域名访问统统禁止,返回403(或者配置return 500)错误页
server {
listen 80 default;
server_name _;
return 403;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
2)下面的配置:
指明了只能使用域名,即http://web01.wangshibo.cn访问配置中的站点(/var/www/html)
不能使用ip,即http://103.110.186.17访问配置中的站点。但是可以使用ip方式访问nginx默认的根目录下的内容(比如/usr/local/nginx/html)
server {
listen 80 ;
server_name web01.wangshibo.cn;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
下面的配置,指明了使用域名或ip都可以访问配置中的站点。(使用ip访问只限于只有一个vhost虚拟主机配置的情况,如果是多个,那么指明ip访问就会混淆)
server {
listen 80 ;
server_name 103.110.186.17 web01.wangshibo.cn;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
3)下面两个的配置后,都能使用域名或ip访问配置中的站点。
server {
listen 80 default;
server_name web01.wangshibo.cn;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
server {
listen 80 default;
server_name 103.110.186.17 web01.wangshibo.cn;
root /var/www/html;
index index.html index.php index.htm;
access_log /usr/local/nginx/logs/image.log;
}
======================================================================
nginx配置只能通过域名禁止ip访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
为什么要禁止ip访问页面呢,这样做是为了避免其他人把未备案的域名解析到自己的服务器IP,而导致服务器被断网, 可以通过禁止使用ip访问的方法,防止此类事情的发生。 Nginx的默认虚拟主机在用户通过IP访问,或者通过未设置的域名访问(比如有人把他自己的域名指向了你的ip)的时候 生效最关键的一点是,在server的设置里面添加这一行: listen 80 default; 后面的default参数表示这个是默认虚拟主机。这个设置非常有用。 比如别人通过ip或者未知域名访问你的网站的时候,你希望禁止显示任何有效内容,可以给他返回500。 网站主关闭空主机头,防止未备案的域名指向过来造成麻烦。就可以这样设置: server { listen 80 default; return 500; } 也可以把这些流量收集起来,导入到自己的网站,只要做以下跳转设置就可以: server { listen 80 default; rewrite ^(.*) http: //www .xxx.com permanent; } -----------------特别注意------------------- 按照如上设置后,确实不能通过IP访问服务器了,但是在应该用中出现当server_name后跟多个域名时, 其中一个域名怎么都无法访问: 设置如下: 没更改之前,通过server_name 中的www.xxx.com kevin.com均可访问服务器,加入禁止IP访问的设置后,通过kevin.com无法访问服务器了,www.xxx.com可以访问 用 nginx -t 检测配置文件会提示warning: 最后通过在listen 80 default;后再加server_name _;解决,形式如下: #禁止IP访问(如果vhosts下面有很多域名的conf配置,那么只需要创建创建一个文件,比如deny.ip.conf,输入下面五行内容,这样就全局禁止了ip访问,只能使用域名访问了!) server{ listen 80 default; // 如果是禁止ip的8080端口访问,则将此处的80修改为8080 server_name _; return 500; } 或者 server { listen 80 dufault; server_name _; rewrite ^(.*) http: //www .xxx.com permanent; } 这样,通过xxx.com就能访问服务器了,问题解决了。 ===================================================================== 也可以使用如下设置:即在server段里插入如下内容即可 if ($host != 'www.kevin.com' ) { return 403; } ===================================================================== |
8.流量限制
对于提供下载的网站,肯定是要进行流量控制的,例如BBS、视频服务,还是其它专门提供下载的网站。在nginx中我们完全可以做到限流,由Nginx模块中的Core模块提供了limit_rate、limit_rate_after命令,我们只需要调用命令实现流量限制就行。
实现流量限制由两个指令limit_rate和limit_rate_after共同完成:
limit_rate
语法: limit_rate rate;
默认值: limit_rate 0;
作用域: http, server, location, location中的if字段
命令概述:限制向客户端传送响应的速率限制。参数 rate 的单位是字节/秒,设置为 0 将关闭限速。 nginx 按连接限速,需要明白的一点是该限制只是针对一个连接的设定,所以如果某个客户端同时开启了两个连接,那么客户端的整体速率是这条指令设置值的2倍。
limit_rate_after
语法: limit_rate_after size;
默认值: limit_rate_after 0;
作用域:http, server, location,location中的if字段
设置不限速传输的响应大小。当传输量大于此值时,超出部分将限速传送。
示例说明:
server {
listen 80;
server_name ops.wangshibo.com;
location /ops/{
root /home/www/html;
limit_rate_after 5m;
limit_rate 20k;
}
}
测试:
[root@test-huanqiu ~]# wget http://ops.wangshibo.com/ops/seven.mp4
修改配置之前,速率没有限制:
修改配置之后,可见由于传输量大于5m,超出部分的传输速率已经被限制在20k/s:
可以发现配置之后,刚开始的时候传输速度很高,因为,传输量大于设定值的部分才会受到限制。这就说明,我们两个命令都发挥了作用!
9.并发连接数限制
这个配置是基于ngx_http_limit_zone_module模块的,要简单完成并发限制,我们要涉及到limit_conn_zone和limit_conn 这两个指令:
limit_conn_zone
语法:limit_conn_zone zone_name $variable the_size
默认值:no
作用域:http
本指令定义了一个数据区,里面记录会话状态信息。 variable 定义判断会话的变量;the_size 定义记录区的总容量。
limit_conn
语法:limit_conn zone_name the_size
默认值:no
作用域:http, server, location
指定一个会话最大的并发连接数。 当超过指定的最发并发连接数时,服务器将返回 “Service unavailable” (503)。
示例说明:
http {
limit_conn_zone $binary_remote_addr zone=one:10m;
…….
…….
server {
listen 80;
server_name ops.wangshibo.com;
location /ops/ {
limit_conn one 1;
}
示例解释:
1)定义一个叫“one”的记录区,总容量为 10M,以变量$binary_remote_addr作为会话的判断基准(即一个地址一个会话)。
限制/ops/目录下,一个会话只能进行一个连接;简单来说,就是限制/ops/目录下,一个IP只能发起一个连接,多过一个,一律报错503。
2)这里使用的是$binary_remote_addr而不是 $remote_addr。$remote_addr的长度为7至15 bytes,会话信息的长度为32或64bytes;而 $binary_remote_addr的长度为4bytes,会话信息的长度为32bytes;$binary_remote_addr是限制同一客户端ip地址;当 zone 的大小为 1M 的时候,大约可以记录 32000 个会话信息(一个会话占用 32 bytes)。
下面分享一个限制流量和并发送的配置:
现象描述:
中间一段时间,网站访问有点慢,初步怀疑是机房交换机问题(之前出现过网站访问很慢,热插拔网卡/重启网卡就好了)
最后查看,发现机房流量很大!主要是论坛流量大,主站流量很小,应该是论坛人数访问一多,就把带宽占满了。
解决办法:
在论坛服务器上修改:
1)首先限制并发数
[root@server_web ~]# vim /etc/sysconfig/iptables
…..
-A INPUT -p tcp –dport 80 -m limit –limit 6/s -j ACCEPT
[root@server_web ~]# /etc/init.d/iptables restart
上面将每个用户限制在每秒6个请求,但效果不明显。
2)设置nginx的流量请求
[root@server_web ~]# vim /usr/local/nginx/conf/nginx.conf
http{
limit_conn_zone $binary_remote_addr zone=perip:10m;
# limit_req_zone $binary_remote_addr zone=one2:10m rate=5r/s;
# limit_req zone=one2 burst=5;
……….
……….
}
[root@server_web ~]# vim /usr/local/nginx/conf/vhost/forum.conf
server {
listen 80;
server_name forum.wangshibo.com;
root /var/www/html;
limit_conn perip 10; //这里调用上面的perip,需要写在server里面;即每个ip最多有10个并发连接
limit_rate 10k; //限制每个连接的带宽,可以单独写这条,与连接数无关;
}
}
[root@server_web ~]# /usr/local/nginx/sbin/nginx -s reload
======================Nginx下的限流配置=====================
limit_req_zone 用来限制单位时间内的请求数,即速率限制,采用的漏桶算法 “leaky bucket” #点击前面超链接可查看对应模块官方介绍
limit_req_conn 用来限制同一时间连接数,即并发限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
|
其中limit_req_conn模块可以根据源IP限制单用户并发访问的连接数或连接到该服务的总并发连接数 什么是漏桶算法? 我们假设系统是一个漏桶,当请求到达时,就是往漏桶里 "加水" ,而当请求被处理掉,就是水从漏桶的底部漏出。水漏出的速度是固定的,当 "加水" 太快, 桶就会溢出,也就是 "拒绝请求" 。从而使得桶里的水的体积不可能超出桶的容量。主要目的是控制数据注入到网络的速率,平滑网络上的突发流量。漏桶算 法提供了一种机制,通过它,突发流量可以被整形以便为网络提供一个稳定的流量。 示例一: http { limit_conn_log_level error; limit_conn_status 503; limit_conn_zone $binary_remote_addr zone=one:10m; limit_conn_zone $server_name zone=perserver:10m; limit_req_zone $binary_remote_addr zone=allips:100m rate=10r /s ; #其中$binary_remote_addr有时需要根据自己已有的log_format变量配置进行替换 server { ........ limit_conn one 100; limit_conn perserver 1000; limit_req zone=allips burst=5 nodelay; ....... } } 参数解释: Zone=one或allips 表示设置了名为 "one" 或 "allips" 的存储区,大小为10兆字节 rate=10r /s 意思是允许1秒钟不超过10个请求 burst=5 表示最大延迟请求数量不大于5。 如果太过多的请求被限制延迟是不需要的 ,这时需要使用nodelay参数,服务器会立刻返回503状态码。 limit_conn one 100表示最大并发连接数100 limit_conn perserver 1000表示该服务提供的总连接数不得超过1000,超过请求的会被拒绝 示例二: http { limit_req_zone $binary_remote_addr zone=one:100m rate=10r /m ; server { ....... limit_req zone=one burst=1 nodelay; ...... } } 解释: rate=10r /m 意思是允许1秒钟不超过1个请求,最大延迟请求数量不大于5。 如果请求不需要被延迟,添加nodelay参数,服务器会立刻返回503状态码。如果没有该字段会造成大量的tcp连接请求等待。 http{ limit_zone one $binary_remote_addr 10m; server { ...... limit_conn one 1; ...... } } 这里的 one 是声明一个 limit_zone 的名字,$binary_remote_addr是替代 $remore_addr 的变量,10m是会话状态储存的空间。 limit_conn one 1 ,限制客户端并发连接数量为1,allow only one connection per an IP address at a time (每次)。 按照字面的理解,lit_req_zone的功能是通过漏桶原理来限制用户的连接频率,(这个模块允许你去限制单个地址指定会话或特殊需要的请求数 ) 而 limit_zone 功能是限制一个客户端的并发连接数。(这个模块可以限制单个地址的指定会话或者特殊情况的并发连接数) 一个是限制并发连接一个是限制连接频率,表面上似乎看不出来有什么区别,那就看看实际的效果吧~~~ 在我的测试机上面加上这两个参数下面是我的部分配置文件 http{ limit_zone one $binary_remote_addr 10m; #limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s; server { ...... limit_conn one 1; #limit_req zone=req_one burst=120; ...... } } 解释一下 limit_zone one $binary_remote_addr 10m; 这里的 one 是声明一个 limit_zone 的名字,$binary_remote_addr是替代 $remore_addr 的变量,10m是会话状态储存的空间 limit_conn one 1 ,限制客户端并发连接数量为1 ============================================================================ limit_zone两种工作情况 a)limit_reqzone=one burst=10 ; 默认情况下是这样配置的,这样每个请求就会有一个delay时间, limit_req_zone$binary_remote_addr zone=one:100m rate=10r /m ; 就是每分钟有10个令牌供用户使用,按照a的配置情况,就会有一个delay,每个请求时间就是60 /10 ,那每个请求时间就是6s。 b)limit_reqzone=one burst=10 nodelay; - 添加nodelay配置,这样就是根据你的网络状况访问,一分钟访问够10次后,服务器直接返回503。 - limit_req_zone$binary_remote_addr zone=one:100m rate=10r /m ; 就是每分钟有10个令牌供用户使用,按照b的配置情况,就会根据网络情况访问url,如果一分钟超过10个令牌,服务器返回503, 等待下一个一分钟领取访问令牌。 rate=10r /m 的意思是每个地址每分钟只能请求10次,也就是说根据漏桶原理burst=1 一共有1块令牌,并且每分钟只新增10块 令牌,1块令牌发完后多出来的那些请求就会返回503。 加上nodelay之后超过 burst大小的请求就会直接返回503,如果没有该字段会造成大量的tcp连接请求等待。 例如: http{ ... #定义一个名为allips的limit_req_zone用来存储session,大小是10M内存, #以$binary_remote_addr 为key,限制平均每秒的请求为20个, #1M能存储16000个状态,rete的值必须为整数, #如果限制两秒钟一个请求,可以设置成30r/m limit_req_zone $binary_remote_addr zone=allips:10m rate=20r /s ; ... server{ ... location { ... #限制每ip每秒不超过20个请求,漏桶数burst为5 #brust的意思就是,如果第1秒、2,3,4秒请求为19个, #第5秒的请求为25个是被允许的。 #但是如果你第1秒就25个请求,第2秒超过20的请求返回503错误。 #nodelay,如果不设置该选项,严格使用平均速率限制请求数, #第1秒25个请求时,5个请求放到第2秒执行, #设置nodelay,25个请求将在第1秒执行。 limit_req zone=allips burst=5 nodelay; ... } ... } ... } 限制下载速度: location /download { limit_rate 128k; } #如果想设置用户下载文件的前10m大小时不限速,大于10m后再以128kb/s限速可以增加以下配内容,修改nginx.conf文件 location /download { limit_rate_after 10m; limit_rate 128k; } ==================================================================== nginx流量限制的使用场景 大家都知道服务器资源有限的,但是客户端来的请求是无限的(不排除恶意攻击), 为了保证大部分的请求能够正常响应,不得不放弃一些客户端来的请求, 所以我们会采用Nginx的限流操作, 这种操作可以很大程度上缓解服务器的压力, 使其他正常的请求能够得到正常响应。 如何使用Nginx实现基本的限流,比如单个IP限制每秒访问50次。通过Nginx限流模块,我们可以设置一旦并发连接数超过我们的设置,将返回503错误给客户端。 这样可以非常有效的防止CC攻击。再配合 iptables防火墙,基本上CC攻击就可以无视了。 配置实例: #统一在http域中进行配置 #限制请求 limit_req_zone $binary_remote_addr $uri zone=api_read:20m rate=50r /s ; #按ip配置一个连接 zone limit_conn_zone $binary_remote_addr zone=perip_conn:10m; #按server配置一个连接 zone limit_conn_zone $server_name zone=perserver_conn:100m; server { listen 80; server_name report.52itstyle.com; index login.jsp; location / { #请求限流排队通过 burst默认是0 limit_req zone=api_read burst=5; #连接数限制,每个IP并发请求为2 limit_conn perip_conn 2; #服务所限制的连接数(即限制了该server并发连接数量) limit_conn perserver_conn 1000; #连接限速 limit_rate 100k; proxy_pass http: //report ; } } upstream report { fair; server 192.168.10.12:8882 weight=1 max_fails=2 fail_timeout=30s; server 192.168.10.12:8881 weight=1 max_fails=2 fail_timeout=30s; } 配置503错误 默认情况,超出限制额度,将会报503错误,提示: 503 Service Temporarily Unavailable The server is temporarily unable to service your request due to maintenance downtime or capacity problems. Please try again later. Sorry for the inconvenience. Please report this message and include the following information to us. Thank you very much! 这样显示没毛病,但是不够友好,这里我们自定义503错误。 error_page 500 502 503 504 /50x .html; location = /50x .html { root html; #自定义50X错误 } 配置说明 limit_conn_zone 是针对每个IP定义一个存储session状态的容器。这个示例中定义了一个100m的容器,按照32bytes /session ,可以处理3200000个session。 limit_rate 300k; 对每个连接限速300k. 注意,这里是对连接限速,而不是对IP限速。如果一个IP允许两个并发连接,那么这个IP就是限速limit_rate×2。 burst=5; 这相当于在检查站req旁边放5个座位。如果某个请求当时超过速度限制被拦了,请他在空座位上坐着,等排队,如果检查站空了,就可以通过。 如果连座位都坐满了,那就抱歉了,请求直接退回,客户端得到一个服务器忙的响应。所以说burst跟request_rate一点关系都没有,设成10000, 就是1万个请求可以等着排队,而检查站还是1秒钟放行5个请求(龟速)。而且也不能一直排队,所以nginx还设了超时,排队超过一定时间, 也是直接退回,返回服务器忙的响应。 以上配置Nginx需要配置以下模块: ngx_http_limit_conn_module (static) ngx_http_limit_req_module (static) 执行命令 "nginx -V" 就可以检查到是否有安装。 =================================================================== 电商平台营销时候,经常会碰到的大流量问题,除了做流量分流处理,可能还要做用户黑白名单、信誉分析,进而根据用户ip信誉权重做相应的流量拦截、限制流量。 Nginx自身有的请求限制模块ngx_http_limit_req_module、流量限制模块ngx_stream_limit_conn_module基于令牌桶算法,可以方便的控制令牌速率,自定义 调节限流,实现基本的限流控制。 对于提供下载的网站,肯定是要进行流量控制的,例如软件下载站、视频服务等。它也可以减少一些爬虫程序或者DDOS的攻击。 limit_zone指令可以用limit_conn_zone替换 如何Nginx限制同一个ip的连接数,限制并发数目? 限流 1) 添加limit_zone和limit_req_zone 这个变量只能在http区域使用 : http { limit_zone one $binary_remote_addr 20m; limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r /s ; ...... } 2) 添加limit_conn 和limit_req 这个变量可以在http, server, location使用。如果限制nginx上的所有服务,就添加到http里面;如果限制部分服务,就添加到相应的server或者location里。 http { limit_zone one $binary_remote_addr 20m; limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r /s ; limit_conn one 10; limit_req zone=req_one burst=120; ...... } 参数详解(数值按具体需要和服务器承载能力设置): limit_zone,是针对每个变量(这里指IP,即$binary_remote_addr)定义一个存储session状态的容器。这个示例中定义了一个20m的容器,按照32bytes /session ,可以处理640000个session。 limit_req_zone 与limit_zone类似。rate是请求频率. 每秒允许12个请求。 limit_conn one 10 : 表示一个IP能发起10个并发连接数 limit_req: 与limit_req_zone对应。burst表示缓存住的请求数。 配置范例: http { limit_zone one $binary_remote_addr 20m; limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r /s ; limit_conn one 10; limit_req zone=req_one burst=120; server { listen 80; server_name status. test .kevin.com ; location / { stub_status on; access_log off; } } } ++++++++++++++++++++++++++++++++++++++++++++++++++++++ nginx白名单设置 以上配置会对所有的ip都进行限制,有些时候我们不希望对搜索引擎的蜘蛛或者某些自己的代理机过来的请求进行限制, 对于特定的白名单ip我们可以借助geo指令实现。 先在nginx的请求日志进行统计,查看那个ip的访问量比较大,运行: # cat access.log | grep "03/Jun" |awk '{print $1}'|sort |uniq -c|sort -nrk 1|head -n 10 #列出访问日志里面在6月3号这天前10个访问量最大的ip. 接下来就可以对这些IP进行分析了。看哪些需要进行白名单设置。 http{ geo $limited { # the variable created is $limited default 1; 127.0.0.1 /32 0; 10.12.212.63 0; } map $limited $limit { 1 $binary_remote_addr; 0 "" ; } limit_zone one $binary_remote_addr 20m; limit_req_zone $limit zone=req_one:20m rate=20r /s ; limit_conn one 10; limit_req zone=req_one burst=120; } 上面两个需要用到map和geo模块,这是nginx自带的模块,有的运维喜欢把他们关闭,自己. /sbin/nginx -V 留意一下。 把配置的--whithout-XXX-module 去掉重新编译一下就可以了。 上面这段配置的意思是: a)geo指令定义了一个白名单limited变量,默认值为1,如果客户端ip在上面的范围内,limited变量,默认值为1,如果客户端ip在上面的范围内, limited的值为0 b)使用map指令映射搜索引擎客户端的ip为空串,如果不是搜索引擎就显示本身真实的ip,这样搜索引擎ip就不能存到limit_req_zone内存session中, 所以不会限制搜索引擎的ip访问 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 获取客户端的真实IP? 顺带一提,为了获取客户端的真实IP。该模块需要安装read_ip模块,运维应该默认有安装。没有的话也可自行安装: 配置方式相当简单,重新编译Nginx 加上 --with-http_realip_module 参数,如: # ./configure --prefix=/opt/nginx --with-http_stub_status_module --with-pcre=../pcre-6.6 --with-http_realip_module # make # make install 在server中增加: set_real_ip_from 192.168.1.0 /24 ; set_real_ip_from 192.168.2.1; real_ip_header [X-Real-IP|X-Forwarded-For]; 需要说明的地方就是设置IP源的时候可以设置单个IP,也可以设置IP段,另外是使用X-Real-IP还是X-Forwarded-For,取决于前面的服务器有哪个头。 set_real_ip_from 设置的IP端可以让运维查看日志,看下你的请求是来自哪些ip段。 重新加载一下服务,差不多就OK了。 再查看日志的话,应该可以看到客户端的真实IP了。 注意:如果未安装该模块的话你的获取到的IP端可能是来自前端代理(如squid)的IP,结果就是多个用户被当成单个用户对待,导致应用不能响应。 ------自测: 有条件的自己可以用ab或者webben自测一下-------- 未安装前压测的话,因为有大量请求,所以access.log会有大量日志,而error.log日志没有变化。 [root@kevin ~] # webbench -c 30 -t 30 http://test.kevin.com Webbench - Simple Web Benchmark 1.5 Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. Benchmarking: GET http: //test .kevin.com 30 clients, running 30 sec. Speed=193468 pages /min , 1254317 bytes /sec . Requests: 96734 susceed, 0 failed. 安装后会发现很多超出的请求会返回503,所以access.log日志变化不快,error.log有大量记录,提示limit_reque缓住了多少请求。 kevin ~ webbench -c 30 -t 30 http: //test .kevin.com Webbench - Simple Web Benchmark 1.5 Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software. Benchmarking: GET http: //test .kevin.com 30 clients, running 30 sec. Speed=120 pages /min , 778 bytes /sec . Requests: 60 susceed, 0 failed. |
10.nginx的访问控制及DDOS预防
1)访问控制配置
基于各种原因,Ningx有时要进行访问控制。
比如说,一般网站的后台都不能让外部访问,所以要添加 IP 限制,通常只允许公司的IP访问。
访问控制就是指只有符合条件的IP才能访问到这个网站的某个区域。
涉及模块:ngx_http_access_module
模块概述:允许限制某些 IP 地址的客户端访问。
对应指令:
allow
语法: allow address | CIDR | unix: | all;
默认值: —
作用域: http, server, location, limit_except
允许某个 IP 或者某个 IP 段访问。如果指定 unix,那将允许 socket 的访问。注意:unix 在 1.5.1 中新加入的功能,如果你的版本比这个低,请不要使用这个方法。
deny
语法: deny address | CIDR | unix: | all;
默认值: —
作用域: http, server, location, limit_except
禁止某个 IP 或者一个 IP 段访问。如果指定 unix,那将禁止 socket 的访问。注意:unix 在 1.5.1 中新加入的功能,如果你的版本比这个低,请不要使用这个方法。
示例说明:
server {
listen 80;
server_name forum.wangshibo.com;
root /var/www/html;
location / {
deny 192.168.1.1;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 103.10.67.56;
deny all;
}
}
规则按照顺序依次检测,直到匹配到第一条规则。
在这个例子里,只有 10.1.1.0/16 、192.168.1.0/24和103.10.67.56允许访问,但 192.168.1.1 除外。
如下实例:
1)先是多域名绑定一个目录后的301跳转至同一个域名
2)针对网站访问做来源ip白名单设置,并加上密码。(即用户认证配置)
[root@test-huanqiu vhosts]# cat test.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
server { listen 80; server_name www.wangshibo.com web01.wangshibo.com hehe.wangshibo.com wangshibo.com; if ($host != 'www.wangshibo.com' ) { rewrite ^/(.*)$ http: //www .wangshibo.com/$1 permanent; } root /var/www/html ; index index.html index.php index.htm; access_log /usr/local/nginx/logs/image .log; allow 192.168.1.0 /24 ; allow 124.65.197.154; deny all; auth_basic "C1G_ADMID" ; auth_basic_user_file /usr/local/nginx/htpasswd ; } |
[root@test-huanqiu vhosts]# htpasswd -c /usr/local/nginx/htpasswd wangshibo
New password:
Re-type new password:
Adding password for user wangshibo
访问站点http://www.wangshibo.com,效果如下:
ngx_http_access_module 配置允许的地址能访问,禁止的地址被拒绝。这只是很简单的访问控制,而在规则很多的情况下,使用 ngx_http_geo_module 模块变量更合适。
这个模块大家下来可以了解 : ngx_http_geo_module
——————————————————————————————————-
上面也用到了nginx的用户认证的配置,其中:
auth_basic 认证时的提示信息
auth_basic_user_file 认证时存放用户名和密码的文件
# htpasswd -c /usr/local/nginx/htpasswd wangshibo //第一次设置认证的用户
# htpasswd /usr/local/nginx/htpasswd guohuihui //追加认证的用户,后面再次追加认证用户时,不要加-c参数,否则就会覆盖之前添加的用户!
下面顺便看几个认证部分的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
location /admin/ { auth_basic "Admin Auth." ; auth_basic_user_file /usr/local/nginx/htpasswd ; } location /wangshibo/ { proxy_pass http: //www .guohuihui.com /heng/ ; auth_basic "Test Auth." ; auth_basic_user_file /usr/local/nginx/htpasswd ; } location ^~ /auth/ { location ~ .*.(php|php5)?$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; } auth_basic "Authorized users only" ; auth_basic_user_file /usr/local/nginx/htpasswd ; } |
2)DDOS预防配置
DDOS的特点是分布式,针对带宽和服务攻击,也就是四层流量攻击和七层应用攻击,相应的防御瓶颈四层在带宽,七层的多在架构的吞吐量。
对于七层的应用攻击,还是可以做一些配置来防御的,使用nginx的http_limit_conn和http_limit_req模块通过限制连接数和请求数能相对有效的防御。
其中:
ngx_http_limit_conn_module 可以限制单个 IP 的连接数
ngx_http_limit_req_module 可以限制单个 IP 每秒请求数
配置方法:
(1)限制每秒请求数,即ip访问频率限制
涉及模块:ngx_http_limit_req_module
通过漏桶原理来限制单位时间内的请求数,一旦单位时间内请求数超过限制,就会返回 503 错误。
配置范例:
http {
limit_req_zone $binary_remote_addr zone=one:10m rate=20r/s;
…
server {
…
location ~ \.php$ {
limit_req zone=one burst=5 nodelay;
}
}
}
配置说明(上一部分解释过的就不再解释):
定义一个名为one的limit_req_zone用来存储session,大小是10M内存,
以$binary_remote_addr 为key,限制平均每秒的请求为20个,
1M能存储16000个状态,rete的值必须为整数,
rate=20r/s表示限制频率为每秒20个请求;如果限制两秒钟一个请求,可以设置成30r/m。
限制每ip每秒不超过20个请求,漏桶数burst为5
brust的意思就是,如果第1秒、2,3,4秒请求为19个,
第5秒的请求为25个是被允许的。
但是如果你第1秒就25个请求,第2秒超过20的请求返回503错误。
nodelay,如果不设置该选项,严格使用平均速率限制请求数,
第1秒25个请求时,5个请求放到第2秒执行,
设置nodelay,25个请求将在第1秒执行。
(2)限制IP连接数(上面已经说明,这里直接写配置)
http {
limit_conn_zone $binary_remote_addr zone=addr:10m; //上面讲过
…
server {
…
location /ops/ {
limit_conn addr 1;
}
}
}
总的来说:如何设置能限制某个IP某一时间段的访问次数是一个让人头疼的问题,特别面对恶意的ddos攻击的时候。其中CC攻击(Challenge Collapsar)是DDOS(分布式拒绝服务)的一种,也是一种常见的网站攻击方法,攻击者通过代理服务器或者肉鸡向向受害主机不停地发大量数据包, 造成对方服务器资源耗尽,一直到宕机崩溃。
cc攻击一般就是使用有限的ip数对服务器频繁发送数据来达到攻击的目的。
nginx可以通过Http LimitReq Modul和Http LimitZone Module配置来限制ip在同一时间段的访问次数来防cc攻击。
1)Http LimitReq Modul用来限制连单位时间内连接数的模块,使用limit_req_zone和limit_req指令配合使用来达到限制。一旦并发连接超过指定数量,就会返回503错误。
2)Http LimitConn Modul用来限制单个ip的并发连接数,使用limit_zone和limit_conn指令
配置示例:
Http LimitReq Modul限制某一段时间内同一ip访问数
http{
……
limit_req_zone $binary_remote_addr zone=allips:10m rate=20r/s;
……
server{
…
location {
……
limit_req zone=allips burst=5 nodelay;
……
}
……
}
……
}
Http LimitZone Module 限制并发连接数实例
limit_zone只能定义在http作用域,limit_conn可以定义在http server location作用域
http{
…
limit_conn_zone one $binary_remote_addr 10m;
……
server{
……
location {
……
limit_conn one 20;
limit_rate 500k;
……
}
……
}
……
}
(3)限速白名单设置(可参考:nginx利用geo模块做限速白名单以及geo实现全局负载均衡的操作记录)
http_limit_conn和 http_limit_req模块限制了单IP单位时间内的连接和请求数,但是如果Nginx前面有lvs或者haproxy之类的负载均衡或者反向代理,nginx 获取的都是来自负载均衡的连接或请求,这时不应该限制负载均衡的连接和请求,就需要 geo 和 map 模块设置白名单:
geo $whiteiplist {
default 1;
10.11.15.1610;
}
map $whiteiplist$limit {
1 $binary_remote_addr;
0 “”;
}
limit_req_zone $limit zone=one:10m rate=10r/s;
limit_conn_zone $limit zone=addr:10m;
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
<?php
phpinfo ();
?>
nginx 配置文件修改:
最后展示:
使ab命令进行测试,比较修改nginx配置文件前后(连接数和请求数分开测试)的测试结果。
修改之前:
测试结果为:
对nginx配置做修改(添加http和php配置如下的红线内容),重启,然后再进行测试
测试结果为:
11.访问白名单
参考:nginx访问白名单设置以及根据$remote_addr分发
12.nginx的上传下载设置
参考:nginx限制上传大小和超时时间设置说明/php限制上传大小
13.nginx目录浏览及其验证功能
参考:nginx下目录浏览及其验证功能配置记录
14.Nginx下禁止指定目录运行php脚本文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
非常简单,直接通过location条件匹配定位后进行权限禁止。 在server配置段中增加下面的的配置: 1)如果是单个目录 location ~* ^ /uploads/ .*\.(php|php5)$ { deny all; } 2)如果是多个目录 location ~* ^/(attachments|uploads)/.*\.(php|php5)$ { deny all; } 注意:这段配置文件一定要放在下面配置的前面才可以生效。 location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } 配置完后记得重启Nginx生效。 ------------------------------------------------------------------------------ 如果是Apache下禁止指定目录运行PHP脚本,在虚拟主机配置文件中增加php_flag engine off指令即可,配置如下 "/website/uploads" > Options FollowSymLinks AllowOverride None Order allow,deny Allow from all php_flag engine off |