Nginx基础应用配置小结 - 运维笔记

 

在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
先来看一个实际的配置文件:

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

比如访问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用来判断文件是否可执行

先来看几个小例子说明

例如下面这段设定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;
}

再接着看下面的实例说明

#直接匹配网站根,通过域名访问网站首页比较频繁,使用这个会加速处理,官网如是说。  
#这里是直接转发给后端应用服务器了,也可以是一个静态首页  
# 第一个必选规则  
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;
}

================================================================================
访问一个主域名,自动添加www前缀。比如访问http://kevin.com自动跳转http://www.kevin.com

1) 首先要保证不加www和加www的域名都要解析出来。
在DNS里添加kevin.com和www.kevin.com的解析,比如解析到111.110.11.18
@                             IN      A       111.110.11.18
www                         IN      A       111.110.11.18

解释:
A记录解析kevin.com到111.110.11.18地址上,前面加@或者留空(留空默认就是@)
A记录解析www.kevin.com到111.110.11.18地址上,前面加www

2)nginx配置不加www自动跳转到www的域名访问(80或443都一样),有下面两种方法实现:

方法一:
在conf/vhost/kevin.conf文件中配置:

server {
        listen       80;
        server_name  www.kevin.com kevin.com;

        index index.jsp index.html index.php index.htm;
        root   /var/www/html;
 
       access_log  /data/nginx/logs/www.kevin.com-access.log main;
       error_log  /data/nginx/logs/www.kevin.com-error.log;
 

        if ($host = "kevin.com") {
             rewrite ^/(.*)$ http://www.kevin.com permanent;
        }

}


方法二(官方推荐这一种nginx的301跳转方法)
在conf/vhost/kevin.conf文件中配置:

server {
          listen       80;
          server_name  kevin.com;
          return       301 http://www.kevin.com$request_uri;
}
          
server {
         listen      80;
         server_name www.kevin.com;

        index index.jsp index.html index.php index.htm;
        root   /var/www/html;
 
       access_log  /data/nginx/logs/www.kevin.com-access.log main;
       error_log  /data/nginx/logs/www.kevin.com-error.log;
}

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跳转规则的例子:

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

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

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不变的例子--------------------------------------

需要特别注意的是:
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"

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/

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

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;
}

其他配置实例

如果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访问

为什么要禁止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      用来限制同一时间连接数,即并发限制

其中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

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参数,否则就会覆盖之前添加的用户!

下面顺便看几个认证部分的配置:

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脚本文件

非常简单,直接通过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  

15.Nginx下开启gzip压缩功能,大幅提高页面加载速度

如果发现如上配置后,访问页面时,gzip压缩没有生效。一般原因就是该页面的相应的gzip_type类型没有加进去。
 
检查一个页面的gzip是否生效:
[root@uatinner-lb01 ~]# curl -I -H "Accept-Encoding: gzip, deflate" "http://www.kevin.com/blog/plugins/bo-coolings/bo-coolings.css"
HTTP/1.1 200 OK
Date: Fri, 14 Sep 2018 09:10:38 GMT
Content-Type: text/html
Connection: keep-alive
Set-Cookie: __cfduid=da2267d06a7d8364c8d4c9193627d56f91536916238; expires=Sat, 14-Sep-19 09:10:38 GMT; path=/; domain=.slyar.com; HttpOnly
CF-Cache-Status: EXPIRED
Expires: Tue, 19 Mar 2019 09:10:38 GMT
Cache-Control: public, max-age=16070400
Vary: Accept-Encoding
Server: cloudflare
CF-RAY: 45a1b8bb26712132-LAX
Content-Encoding: gzip
 
如果发现访问如上的http://www.kevin.com/blog/plugins/bo-coolings/bo-coolings.css页面时,gzip没有生效。
就注意查看下上面结果中的Content-Type类型的内容(如上是text/html)是否加到了nginx.conf文件中gzip配置区域里。如果没有,就加上,并reload nginx服务即可!

16.Nginx使用非root用户启动

在linux系统里, 监听端口在1024以下的服务必须使用root用户启动, 1024以上端口的应用服务可以使用非root用户启动.

比如, nginx默认端口是80, 必须使用root用户启动. 考虑到安全问题, 采用非root用户启动, 比如app用户.
[root@web ~]# cat /data/nginx/conf/nginx.conf
user  app;
 
然后切换到app用户下启动
[root@web ~]# su - app
[app@web ~]$ /data/nginx/sbin/nginx

非root用户在检查nginx配置文件或启动nginx的时候,会出现告警信息:
nginx: [warn] the "app" directive makes sense only if the master process runs with super-user privileges, ignored in 
/data/nginx/conf/nginx.conf:2

这是因为:
- 在非root账户下启动时,nignx的master和worker进程的owner都将是这个账户(这里是app用户),
- 在root账户下启动时 nignx的master进程是的owner是rootworker的owner在conf已配置用户的情况下,owner是配置的用户,否则将是nobody,
  而且也可能导致nginx的一些文件的owner也是nobody

所以出现了上面那个warn告警信息, 可以忽略, 不影响

[app@web ~]$ ps -ef|grep nginx
app       8837     1  0 16:02 ?        00:00:00 nginx: master process /data/nginx/sbin/nginx
app       8838  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8839  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8840  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8841  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8842  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8843  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8844  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8845  8837  0 16:02 ?        00:00:00 nginx: worker process 
app       8846  8837  0 16:02 ?        00:00:00 nginx: cache manager process

17. Nginx实现404错误页面跳转的几种方法

Nginx作为常用网站的web服务器, 出现404错误页面的跳转实现方式主要有以下几种: 

第一种情况: Nginx自己的错误页面
Nginx访问一个静态的html 页面,当这个页面没有的时候,Nginx抛出404,那么如何返回给客户端404呢?
看下面的配置,这种情况下不需要修改任何参数,就能实现这个功能。
[root@localhost ~]# cat /data/nginx/conf/nginx.conf
.........
http {
    proxy_intercept_errors on;                          //如果nginx不做代理, 不代理到后面的tomcat服务器, 只是自己的静态页访问, 则这一行加不加都可以实现;

[root@localhost ~]# cat /data/nginx/conf/test.conf
server {
      listen      80;
      server_name localhost;
    
      access_log  /data/nginx/logs/access.log main;
      error_log  /data/nginx/logs/error.log;
    
   location / {
        root /data/web;
        index index.php index.html index.htm; 
        }

       #定义错误页面码,如果出现相应的错误页面码,转发到那里。
       error_page  404 403 500 502 503 504  /404.html;
   
       #承接上面的location。
       location = /404.html {
       #放错误页面的目录路径。
           root /data/web;
        }
}

------------------------------------------------------------------------------------------
需要注意:
如果是跳转到其他url, 则配置改为:
       #定义错误页面码,如果出现相应的错误页面码,转发到那里。
       error_page  404 403 500 504  http://www.haha.com;
------------------------------------------------------------------------------------------
需要注意:
或是可以设置多种类型的错误页面
      # 这里的错误码可以是多个
      error_page   500 502 503 504  /50x.html;
      location = /50x.html {
            root   /data/web;
        }
        
     error_page   404  /404.html;
     location = /404.html {
            root   /data/web;
        }

然后在定义的/data/web目录下编写50x.html和404.html错误页面内容
-----------------------------------------------------------------------------------------

到定义的错误页面存放目录下编辑404错误页面内容:
[root@localhost vhosts]# ll /data/web/
total 8
-rw-r--r-- 1 root root 50 Dec 19 16:04 404.html
-rw-r--r-- 1 root root 21 Dec 19 15:59 index.html

[root@localhost vhosts]# cat /data/web/404.html 
Sorry, sir, this page does not exist! Excuse me ~

重启nginx服务
[root@localhost vhosts]# /data/nginx/sbin/nginx -t
nginx: the configuration file /data/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /data/nginx/conf/nginx.conf test is successful
[root@localhost vhosts]# /data/nginx/sbin/nginx -s reload

然后访问nginx的地址, 当访问一个错误页面时, 就会出现定义的404错误页面内容: "Sorry, sir, this page does not exist! Excuse me ~"

============================================
第二种:反向代理的错误页面 (nginx代理的后端是tomcat页面, 使用proxy_intercept_errors on参数, 该参数可以放在http区域, 也可以访问server或location区域)

如果后台Tomcat处理报错抛出404,想把这个状态叫Nginx反馈给客户端或者重定向到某个连接.
比如在自己的Linux服务器上部署了tomcat的一个项目,使用Nginx进行的代理,访问项目不存在的页面时,出现的是Nginx默认的404页面,
现在要配置自己定义的404页面进行提示

配置如下:
[root@localhost ~]# cat /data/nginx/conf/vhost/test.conf
upstream tomcat {
ip_hash;
server 127.0.0.1:8080  weight=20 max_fails=2 fail_timeout=30s;
}

server {
      listen      80;
      server_name www.test.com;
    
      access_log  /data/nginx/logs/access.log main;
      error_log  /data/nginx/logs/error.log;
 

     location / {

        # 即把www.test.com的首页设定为index.html (默认情况下tomcat的首页是index.jsp, 这里在tomcat下的webapp/ROOT下加了index.html)
         if ($request_uri ~* '^/$') {
             rewrite .*   http://www.test.com/index.html redirect;
        }

        #关键参数(比如加下面这一行的参数配置):这个变量开启后,我们才能自定义错误页面,当后端返回404,nginx拦截错误定义错误页面
        proxy_intercept_errors on;

       proxy_pass      http://tomcat;
       proxy_set_header HOST   $host;
       proxy_set_header X-Real-IP      $remote_addr;
       proxy_set_header X-Forwarded-FOR $proxy_add_x_forwarded_for;
       }

       error_page    404  /404.html;
       location = /404.html {
       root   /mnt/error;
       }
}

配置解释:
if ($request_uri ~* "^/$")   表示url中只有域名,后面不跟任何东西,比如www.test.com。
if ($request_uri ~* "test")   表示域名后面那串儿只要包含test这个关键词,就可匹配成功。比如www.test.com/pan/beta/test3

上面的配置表示:
当访问http://www.test.com 时(即url只有一个完整的域名) 时, 页面跳转到tomcat跟下的index.html (即tomcat的webapp/ROOT/index.html, tomcat的默认首页一般是webapp/ROOT/index.jsp)
也就是访问http://www.test.com, 显示为http://www.test.com/index.html, 这个index.html是tomcat的webapp/ROOT/index.html
当访问http://www.test.com/* 时, 跳转到http://127.0.0.1:8080/*  , 比如访问 http://www.test.com/index.jsp, 跳转到http://127.0.0.1:8080/index.jsp,
当访问http://www.test.com/* 的页面时, 页面不存在, 则显示404错误页面, 错误页面文件为/mnt/error/404.html

[root@localhost ~]# ll /usr/local/tomcat8/webapps/ROOT/index.html 
-rw-r--r-- 1 root root 21 Dec 19 16:32 /usr/local/tomcat8/webapps/ROOT/index.html

[root@localhost ~]# ll /usr/local/tomcat8/webapps/ROOT/index.jsp 
-rw-r--r-- 1 root root 12513 Jun 29 10:44 /usr/local/tomcat8/webapps/ROOT/index.jsp

[root@localhost ~]# ll /mnt/error/404.html 
-rw-r--r-- 1 root root 31 Dec 19 17:12 /mnt/error/404.html

[root@localhost ~]# /data/nginx/sbin/nginx -s reload

-------------------------------------------------------------------------------------------------------------------
这里注意下: 看下面这个情况的错误页面本地跳转配置
[root@localhost ~]# cat /data/nginx/conf/nginx.conf
..........
http {
    proxy_intercept_errors on;

[root@localhost ~]# cat /data/nginx/conf/vhosts/test.conf
  server {
      listen      80;
      server_name www.test.com;

      access_log  /data/nginx/logs/access.log main;
      error_log  /data/nginx/logs/error.log;

      location / {
          proxy_pass http://127.0.0.1:8080;
          proxy_set_header   REMOTE-HOST $remote_addr;
          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    20m; 
          }

      location /upload {
            root   /data/web;
            index  index.html index.htm;
        }

    #error_page  404  /404.html;
    error_page   500 502 503 504  /404.html;
    error_page   404  /404.html;
    location = /404.html {
            root  /data/web/error;
        }
}


[root@localhost ~]# cat /data/web/error/404.html 
Sorry, sir, this page does not exist! Excuse me ~

[root@localhost ~]# /data/nginx/sbin/nginx -s reload

当8080端口的tomcat服务没有开启时, 访问http://www.test.com , 则会出现定义在/data/web/error/404.html错误页面内容
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

================================================
第三种:反向代理的错误页面 (nginx代理的后端是php解析的页面, 使用fastcgi_intercept_errors on参数, 该参数可以放在http区域, 也可以访问server或location区域)
Nginx解析php代码的错误页面, 如果后端是php解析的,需要加一个变量fastcgi_intercept_errors on进行错误页面提示, 否则php页面则显示为空白页!
在http段中加一个变量 fastcgi_intercept_errors on 就可以了。
[root@localhost ~]# vim /data/nginx/conf/nginx.conf
.........
http {
    fastcgi_intercept_errors on;

接着指定一个错误页面
[root@localhost ~]# vim /data/nginx/conf/vhosts/test.conf
........
    error_page    404  /404.html;
    location = /404.html {
    root   /mnt/error;
}

错误页面404.html 放在/mnt/error下面

如果指定404错误时跳转到其他的一个错误页面, 配置为
[root@localhost ~]# vim /data/nginx/conf/vhosts/test.conf
........
     error_page 404  /404.html;
     error_page 404 = http://www.test.com/error.html;

=================================================================
温馨提示:
配置proxy_intercept_errors on时, 配置的错误页面表示的是当服务器返回的状态码为我们配置的状态码时,才进行的页面跳转。
如:服务器中没有xxxx.do接口时,访问了这个接口,配置了proxy_intercept_errors on则也会进行页面跳转

如果服务器中没有开启服务,则配置proxy_intercept_errors on无用,则需要再添加fastcgi_intercept_errors on配置, 
这样的话,出现页面错误时也会进行跳转

总结:
=====什么是404页面======
如果碰巧网站出了问题,或者用户试图访问一个并不存在的页面时,此时服务器会返回代码为404的错误信息,此时对应页面就是404页面。
404页面的默认内容和具体的服务器有关。如果后台用的是NGINX服务器,那么404页面的内容则为:404 Not Found 

NGINX下如何自定义404页面
1) 更改nginx.conf在http定义区域加入: proxy_intercept_errors或者fastcgi_intercept_errors
2) 更改nginx.conf,在server 区域加入: error_page 404  /404.html  或者 error_page 404 =http://www.xxx.com/404.html
3) 更改后重启nginx,,测试nginx.conf正确性

#502 等错误可以用同样的方法来配置。  配置如下:

error_page  500 502 503 504  /50x.html;
       location = /50x.html {
       root   /mnt/error;
       }

或是
error_page 500 501 502 503 504 @errpage;
    location @errpage {
      access_log logs/access.log maintry;
      proxy_pass url;
}

注意事项:
1) 要添加:fastcgi_intercept_errors on  或者  proxy_intercept_errors
默认: fastcgi_intercept_errors off
添加位置: http, server, location
默认情况下,nginx不支持自定义404错误页面,只有这个指令被设置为on,nginx才支持将404错误重定向
这个指令指定是否传递4xx和5xx错误信息到客户端,或者允许nginx使用error_page处理错误信息。你必须明确的在error_page中指定处理方法使这个参数有效

2) 不要出于省事或者提高首页权重的目的将首页指定为404错误页面,也不要用其它方法跳转到首页

3) 自定义的404页面必须大于512字节,否则可能会出现IE默认的404页面。例如,假设自定义了404.html,大小只有11个字节(内容为:404错误)

===== fastcgi_intercept_errors 参数===== 
语法:fastcgi_intercept_errors on|off 
默认值:fastcgi_intercept_errors off 
使用字段:http, server, location 
这个指令指定是否传递4xx和5xx错误信息到客户端,或者允许nginx使用error_page处理错误信息。
你必须明确的在error_page中指定处理方法使这个参数有效,正如Igor所说“如果没有适当的处理方法,nginx不会拦截一个错误,这个错误不会显示自己的默认页面,这里允许通过某些方法拦截错误。

===== f注意搞清楚下面情况===== f
404.html:上游服务器提供的特定404页面内容,当nginx:80访问上游服务器资源不存在(返回404),要求显示的内容页面。
404_default.html:上游服务器默认404页面。

配置如下:
       error_page    404  /404.html;
       location = /404.html {
       root   /mnt/error;
       }

       或者
       error_page    404  /404_default.html;
       location = /404_default.html {
       root   /mnt/error;
       }

50x.html:上游服务器提供的特定50x页面内容,当nginx:80访问上游服务器出现50x错误(包含500, 502, 503和504),要求显示的内容页面。
50x_default.html:上游服务器提供的处理50x的默认页面

配置如下:
       error_page    50x  /50x.html;
       location = /50x.html {
       root   /mnt/error;
       }

       或者
       error_page    50x  /50x_default.html;
       location = /50x_default.html {
       root   /mnt/error;
       }

18. nginx实现动静分离

将静态资源放在 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 代码,就需要编写类似这样的访问代码:<img src=”{address of A}/a.jpg”>,当静态资源过多,需要扩展出其他的服务器来安放静态资源时,访问这些资源就可能要编写这样的代码:<img src=”{address of C}/a.jpg”>、<img src=”{address of D}/a.jpg”>。可以看到,当服务器进行变更或扩展时,代码也要随之做出修改,对于程序开发和维护来说非常困难。而基于上面的结构,程序都只 要 <img src=”a.jpg”>,无需关心具体放置资源的服务器地址,因为具体的地址 Nginx 为帮您绑定和选择。

动静分离的nginx配置如下:

 # 转发的服务器,upstream 为负载均衡做准备
 upstream tomcat_server{ 
        server 172.16.50.60:8080 weight=1 max_fails=2  fail_timeout=2;
 } 

    server {
        listen       80;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   /data/web;
            index  index.html index.htm;
        }

        # 静态请求直接读取
       location ~ .*\.(html|htm|gif|jpg|jpeg|bmp|png|ico|js|css)$ {
          root   /data/web;
          expires    30d;          #缓存时间,即有效时间
       }

       # 动态请求的转发
        location ~ .*.jsp$ { 
            proxy_pass http://tomcat_server; 
            proxy_set_header Host $host; 
        } 
}


=============================================================
如果还有php文件, 则配置添加如下:
upstream php {
    server  172.16.50.15 weight=1 max_fails=2  fail_timeout=2;
    server  172.16.50.16 weight=1 max_fails=2  fail_timeout=2;
} 

.......

location ~* \.php$ {
    fastcgi_proxy  http://php;
    }
==================================================================

18. nginx配置中关于url的几个变量的区别 (如$request_uri , $uri 和 $document_uri )

$request_uri 
这个变量等于从客户端发送来的原生请求URI,包括参数。它不可以进行修改。$uri变量反映的是重写后/改变的URI。不包括主机名。
其实这个$request_uri变量指的就是完整url中刨去最前面$host剩下的部分.
比如http://www.baidu.com/pan/beta/test1?fid=3这个url地址,去掉www.baidu.com剩下的就是了,日志里会看到打印出来的$request_uri,
$request_uri其实指的就是/pan/beta/test1?fid=3

如下匹配规则:
if ($request_uri ~* "^/$") 表示url中只有域名,后面不跟任何东西,比如www.baidu.com。
if ($request_uri ~* "test") 表示域名后面那串儿只要包含test这个关键词,就可匹配成功。比如www.baidu.com/pan/beta/test3

$uri
这个变量指当前的请求URI,不包括任何参数。这个变量反映任何内部重定向或index模块所做的修改。
注意,这和request_uri不同,因$request_uri是浏览器发起的不做任何修改的原生URI。不包括协议及主机名。
比如http://www.baidu.com/pan/beta/test1?fid=3这个url地址,日志里会看到打印出来的$uri其实指的就是/pan/beta/test1

$document_uri
这个变量等同于$uri.
例如:"/pan/beta/test1"

总而言之:
$request_uri变量指的则是请求的整个字符串,包含了后面的query_string的。
$uri变量:  指的是请求的文件和路径,不包括"?"或者"#"之后的东西

例如, 访问http://www.kevin.com/stat.php?id=1585378&web_id=1585378
则这三个变量分别指的是:
$request_uri:     /stat.php?id=1585378&web_id=1585378
$uri:             /stat.php
$document_uri:    /stat.php
posted @ 2016-11-23 19:47  散尽浮华  阅读(9680)  评论(2编辑  收藏  举报