nginx web服务优化
nginx基本安全优化
1. 调整参数隐藏nginx软件版本号信息
软件的漏洞和版本有关,我们应尽量隐藏或消除web服务对访问用户显示各类敏感信息(例如web软件名称及版本号等信息),这样恶意的用户就很难猜到他攻击的服务器所用的是否有特定漏洞的软件,或者是否有对应漏洞的某一特定版本,从而加强web服务的安全性。
要了解服务器使用的软件版本号,对于linux客户端
[root@Poppy conf]# curl -i bbs.joker.com HTTP/1.1 200 OK Server: nginx/1.6.3 Date: Fri, 15 Jun 2018 02:18:23 GMT Content-Type: text/html Content-Length: 4 Last-Modified: Thu, 07 Jun 2018 10:06:23 GMT Connection: keep-alive ETag: "5b19039f-4" Accept-Ranges: bytes bbs 浏览器上访问如果出现404的时候,会显示软件和版本号。
我们来访问下百度看看是否可以隐藏版本
[root@Poppy conf]# curl -i baidu.com HTTP/1.1 200 OK Date: Fri, 15 Jun 2018 02:23:35 GMT Server: Apache 软件更改成了apache,还隐藏了版本号 Last-Modified: Tue, 12 Jan 2010 13:48:00 GMT ETag: "51-47cf7e6ee8400" Accept-Ranges: bytes Content-Length: 81 Cache-Control: max-age=86400 Expires: Sat, 16 Jun 2018 02:23:35 GMT Connection: Keep-Alive Content-Type: text/html <html> <meta http-equiv="refresh" content="0;url=http://www.baidu.com/"> </html>
通过修改配置文件nginx.conf中的http标签段内加入“server_tokens off”;参数
[root@Poppy conf]# cat nginx.conf worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # 访问日志,main就是读http里面的main日志变量 access_log logs/www_access.log main; server_tokens off; include extra/bbs.conf; }
再来访问看看
[root@Poppy conf]# curl -i bbs.joker.com HTTP/1.1 200 OK Server: nginx Date: Fri, 15 Jun 2018 02:27:21 GMT Content-Type: text/html Content-Length: 4 Last-Modified: Thu, 07 Jun 2018 10:06:23 GMT Connection: keep-alive ETag: "5b19039f-4" Accept-Ranges: bytes bbs
语法格式为
server_tokens off; off 为关闭 on为开启 (默认开启安)
存放的位置可以是http,server,location
2. 更改源码隐藏nginx软件名称及版本号
隐藏了nginx版本号后,更近一步,我们可以通过一些手段把web服务软件的名称也隐藏起来,或者更改为其他web服务软件名以迷惑黑客。由于商业及品牌的展示原因等,软件提供商不希望使用者把软件名字隐藏起来。因此,如果要修改软件名称就只能更改nginx源代码
我们不做修改
3. 更改nginx服务默认用户
为了让web服务更安全,要尽可能的改掉软件默认的所有配置,包括端口,用户等
nginx服务的默认用户是nobody,即使是注释或者不配置默认用户都是nobody
[root@Poppy conf]# grep "#user" nginx.conf.default #user nobody;
#1 为nginx服务建立新用户的操作过程如下
useradd www -s /sbin/nologin -M
不需要有系统登录权限,应当禁止其登录行为
#2 配置nginx服务,让其使用刚建立的nginx用户
第一种方法是直接修改配置文件,将默认的#user nobody改为 user nginx; 第二种方法是直接在编译nginx软件时指定编译的用户和组 ./configure --user=nginx --group=nginx 检查更改用户的效果 [root@Poppy conf]# ps -ef|grep nginx root 9032 1 0 Jun14 ? 00:00:00 nginx: master process /application/nginx/sbin/nginx www 10609 9032 0 10:27 ? 00:00:00 nginx: worker process 可以看到worker process进程对应的用户都变成了nginx。上述2种方法都可以设置nginx的worker进程运行的用户,当然,nginx的主进程还是以root身份运行的。
根据参数优化nginx服务器性能
优化nginx服务的worker进程个数
在高并发,高访问量的web服务场景,需要事先启动好更多的nginx进程,以保证快速响应并处理大量并发用户的请求
这类似于开饭店,在营业前,需要事先招聘一定数量的服务员准备接待顾客,但这里就有个问题,如果饭店对客流没有正确评估,就会导致一些问题发生,例如;服务员人数招聘多了,但是客流很少,那么服务员就可能很闲,没事干,饭店的成本也就高了;如果客流很大,而服务员人数少了,可能就接待不过来顾客,导致顾客吃饭体验差。因此,饭店要根据客户的流量及并发量来调整接待的服务人员数量,然后根据监测顾客量变化及时调整到最佳的配置。
nginx服务就相当于饭店,网站用户就相当于顾客,nginx的进程就相当于服务员
1. 优化nginx进程对应的配置
优化nginx的进程反应nginx服务的配置参数如下
worker_processes 1;指定了nginx要开启的进程数,结尾的数字就是进程个数
调整的是nginx服务的worker进程数,nginx有master进程和worker进程之分,master是管理进程,worker是工作处理进程
2. 优化nginx进程个数的策略
如何设置worker_processes树木,官方建议我们起始为cpu的核数,这样起始提供服务时就不会出现因为访问量快速增加而临时启动新进程提供服务的问题,缩短了系统的瞬间开销和提供服务的时间,提升了服务用户的速度。高流量高并发场合也可以考虑将进程数提高至cpu核数具体情况根据实际业务来选择,因为这个参数除了要和cpu核数匹配外,也和硬盘存储的数据及系统的负载有关。
3. 查看web服务器cpu硬件资源信息
[root@Poppy conf]# grep -c processor /proc/cpuinfo 1 一颗cpu一核 [root@Poppy conf]# grep 'physical id' /proc/cpuinfo|sort|uniq|wc -l 1 一颗cpu
4. 实践修改nginx配置
服务器cpu颗数为1颗,核数为4核,则初始的配置可通过查看默认的nginx.conf里的work_process了解,命令如下
[root@Poppy conf]# grep worker_processes nginx.conf worker_processes 1;
我们修改将其修改为4,然后重启nginx
[root@Poppy conf]# grep worker_processes nginx.conf worker_processes 4;
我们通过ps -ef,来查看下nginx进程
[root@Poppy conf]# ps -ef|grep nginx root 9032 1 0 Jun14 ? 00:00:00 nginx: master process /application/nginx/sbin/nginx www 10862 9032 0 14:02 ? 00:00:00 nginx: worker process www 10863 9032 0 14:02 ? 00:00:00 nginx: worker process www 10864 9032 0 14:02 ? 00:00:00 nginx: worker process www 10865 9032 0 14:02 ? 00:00:00 nginx: worker process
可知,worker的进程数为4个,ngxin master主进程不包含在这个参数内,nginx master的主进程为管理进程,负责调度和管理worker进程。
优化绑定不同的nginx进程到不同的cpu上
默认情况下,nginx的多个进程有可能跑在某一个cpu或cpu的某一核上,导致nginx进程使用硬件的资源不均,如何尽可能地分配不同的nginx进程给不同的cou处理,达到充分有效利用硬件的多cpu多核资源的目的
四核cpu服务器参数配置参考
worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000; worker_cpu_affinity就是配置nginx进程与cpu亲和力的参数,即把不同的进程分给不同的cpu处理,这里0001 0010 0100 1000是掩码,分别代表第1,2,3,4核cpu,由于worker_processes进程数位4,因此,上述配置会把每个进程分配一核cpu处理,默认情况下进程不会绑定人和cpu,参数位置为main段
八核cpu服务器参数配置参考
worker_cpu_affinity 0001 0010 0100 1000 0001 0010 0100 1000
worker_cpu_affinity 00000001 00000002 00000003 00000004 00000005 00000006 00000007 00000008
其语法就是
worker_cpu_affinity cpumask; cpumask是掩吗
worker_cpu_affinity的作用是绑定不同的worker进程数到一组cpu上
压力测试 。webbench -c 2000 -t 180 http://www.joker.com/
nginx事件处理模式优化
nginx的链接处理机制在不同的操作系统会采用不同的i/o模型,在linux下,nginx使用epoll的i/o多路复用模型,具体配置如下
events{
events 指令是设定nginx的工作模式及连接数上限
user epoll;
use是一个事件模块指令,用来指定nginx的工作模式。
}
nginx的工作模式
nginx的工作模式有select,poll,kqueue,epoll,rtsig和/dev/poll。其中select,poll都是标准的工作模式,kqueue和epoll是高效的工作模式,不同的是epoll用来linux平台上,而kqueue用来bsd系统中。对于linux系统linux 2.6+的内核,推荐选择epoll工作模式,这是高性能高并发的设置。
nginx官方文档建议,我们可以不指定事件处理模型,nginx会自动选择最佳的事件处理模型服务
调整nginx单个进程允许的客户端最大连接数
调整nginx单个进程允许的客户端最大连接数,这个控制连接数的参数为worker_connections
worker_connections的值要根据具体服务器性能和程序的内存使用量来执行(一个进程启动使用的内存根据程序确定),如下
events{ events指令是设定nginx的工作模式及连接数上限 worker_connections 20480; worker_connections也是个事件模块指令,用于定义nginx每个进程的最大连接数,默认是1024。最大客户端连接数由worker_processes和worker_connections决定,即max_client=worker_processes*worker_connections。进程的最大连接数接受linux系统接受linux系统进程的最大打开文件数限制,在执行操作系统命令“ulimit -Hsn 65535”或配置相应文件后,worker_connections的设置才能生效 } worker_connections用来设置一个worker process支持的最大并发连接数
配置nginx worker进程最大打开文件数
调整配置nginx worker进程最大打开文件数,这个控制连接数的参数为worker_rlimit_nofile。
worker_rlimit_nofile 65535;
最大打开文件数,可设置为系统优化后的ulimit -HSn的结果
优化服务器域名的散列表大小
先要将确切名字和通配符名字存储在散列表中,散列表和监听端口关联,每个端口最多关联到三张表;确切名字的散列表,以星号起始的通配符名字的散列表和以星号结束的通配符名字的散列表。散列表的尺寸在配置阶段进行了优化,可以以最小的cpu缓存命中失败来找名字。nginx首先会搜索确切名字的散列表,如果没有找到,则搜索以星号起始的通配符名字的散列表,如果还是没有找到,继续搜索以星号结束的通配符名字的散列表。
[root@Poppy extra]# cat bbs.conf server { listen 80; server_name bbs.joker.com *.joker.com; 很明显*.joker.com效率低 location / { root html/bbs; index index.html; } }
如果你要想定义大量的名字,或者定义非常长的名字,就需要在http配置块中调整server_names_hash_max_size和server_names_hash_bucket_size的值。server_names_hash_max_size的默认值可能是32或64,也可能是其他值,这取决于cpu的缓存行的长度。那么定义“wwwwwwwwwwwwwwwwwwwwww.joker.com”作为虚拟主机名就会失败,此时会显示下面的错误信息;
could not build the server_name_hash; you should increase server_names_hash_bucket_size:32
出了这种情况,就需要将server_names_hash_max_size扩大一倍。
http{ server_names_hash_max_size 64 ....... }
如果定义了大量名字,会得到如下另外一个错误消息;
could not build the server_name_hash; you should increase server_names_hash_max_size:512 # 默认512kb,一般查看系统给出确切的值,cpu l1的4倍到5倍 or server_names_hash_bucket_size; 32
我们应该修改server_names_hash_max_size的值,此值差不多等于名字列表的名字总量。
注意:后面不能带单位
开启高效文件传输模式
1. 设置参数sendfile on;
sendfile参数用于开启文件的高效传输模式,同时将tcp_nopush和tcp_nodelay俩个指令设置为on,可防止网络及磁盘i/o阻塞,提升nginx工作效率
在http ,server,location,if in location字段标签里面可以设置
http {
sendfile on; 默认是off
}
激活sendfile功能,sendfile()是作用于俩个文件描述符之间的数据拷贝函数,这个拷贝操作是在内核之中的,被称为“零拷贝”,sendfile()比read和write函数要高效很多,因为,read和write函数要把数据拷贝到应用层在进行操作。
2. 设置参数tcp_nopush
在http,server,location字段标签里面可以设置
http {
sendfile on;
tcp_nopush on; 默认是off
}
激活linux上传递tcp_cork socket选项,此选项仅仅当开启sendfile时才生效,激活这个,tcp_nopush参数可以允许把http response header和文件的开始部分放在一个文件里发布,其积极的作用是减少网络报文段的数量。
优化nginx链接参数,调整链接超时时间
1. 链接超时的定义
当服务器建立的链接没有接收处理请求时,可在指定的时间内就让它超时自动退出。还有当nginx和fastcgi服务无法给nginx返回数据,此时可以通过配置nginx服务参数使其不会死等,因为前面用户还等着它返回数据呢。
2. 链接超时的作用
- 将无用的链接设置为尽快超时,可以保护服务器的系统资源(cpu,内存,磁盘)
- 链接很多时,及时断掉那些已经建立好的但又长时间不做事的链接,以减少其占用的服务器资源,因为服务器维护链接也是消耗资源的
- 黑客或恶意用户攻击网站,就会不断地和服务器建立多个链接,消耗连接数,但是啥也不干,大量消耗服务器资源,此时就应该及时断掉这些恶意占用资源的链接
- lnmp环境中,如果用户请求了动态服务,则nginx就会建立链接,请求fastcgi服务以及后端mysql服务,此时这个nginx链接就要设定一个超时时间,在用户容忍的时间内返回数据,或者再多等一会后端服务返回数据。
简单地说,链接超时是服务的一种自我管理,自我保护的重要机制。
3. 链接超时带来的问题,以及不同程序链接设定知识
服务器建立链接是要消耗资源的,超时设置的太短而并发很大,就会导致服务器瞬间无法响应用户的请求,导致用户体验下降。
php程序站点会希望设置成短链接,因为php程序建立链接消耗资源和时间相对要少些。而对于java程序站点来说,建议设置长链接,因为java程序建立链接消耗的资源和时间更多。
4. nginx链接超时的参数设置
(1)设置参数;keepalive_timeout 60;
用于设置客户端保持链接会话超时时间为60秒。超过这个时间,服务器会关闭该链接
keepalive_timeout 60;
可设置在http,server,location字段标签中,默认是75s
keep-alive可以使客户端到服务器端已经建立的链接一直工作不退出,当服务器有持续请求时,keep-alive会使用已经建立的链接提供服务,从而避免服务器重新建立新链接处理请求。
(2)设置参数:tcp_nodelay on;
用于激活tcp_nodelay功能,提高i/o性能,可以设置在http,server,location字段标签里
http {
sendfile on;
tcp_nodelay on; 默认是on
}
当数据发送时,内核不会马上发送,可能会等待更多的字节组成一个数据包,这样可以提高i/o性能。但是,在每次只发送很少字节的业务场景汇总,使用tcp_nodelay功能,等待时间会比较长。
(3)设置参数;client_header_timeout 15;
读取客户端请求头数据的超时时间
可以设置在http,server字段标签里
http {
sendfile on;
client_header_timeout 60s; 默认是60s
}
如果超过这个时间,客户端还没有发送完整的header数据,服务器端将返回"Request timo out(408)"错误。
(4) 设置参数;client_body_timeout 15;
用于设置读取客户端请求主体的超时时间,默认值是60
http {
sendfile on;
client_bodyr_timeout 60s; 默认是60s
}
仅仅为俩次成功的读取操作之间的一个超时,非请求整个主体数据的超时时间。如果在这个超时时间内,客户端没有发 人和数据,nginx将返回"Request timo out(408)"错误。
(5) 设置参数;send_timeout 25;
用于指定响应客户端的超时时间。这个超时仅限于2个链接活动之间的时间,如果超过这个时间,客户端没有人和活动,nginx将会关闭链接,默认值为60秒。
http { sendfile on; send_timeout 25; 默认是60s }
服务器传送http响应信息到客户端的超时时间,这个超时仅仅为俩次成功握手后的一个超时,非请求整个响应数据的超时时间,如果在这个超时时间内,客户端没有接收任何数据,链接将被关闭。
备注,细节可以参考http://nginx.org/en/docs/http/ngx_http_core_module模块
上传文件大小的限制(动态应用)
可设置在http,server,location字段标签里
http {
sendfile on;
client_max_body_size 8m; 默认是1m
}
设置最大允许客户端请求主体的大小,post请求
配置nginx gzip压缩实现性能优化
nginx gzip压缩模块提供了压缩文件内容的功能,用户请求内容在发送用户客户端之前,nginx服务器会根据一些具体的策略实施压缩,已节约网站出口带宽,同时加快传输效率,来提升用户访问体验
nginx gzip压缩的优点
- 提升网站用户体验,发送给用户的内容小了,用户访问单位大小的页面就加快了
- 节约网站带宽成本,数据是压缩传输的,因此节省了网站的带宽流量成本,不过压缩时会稍微消耗一些cpu资源
需要和不需要压缩的对象
- 纯文本内容压缩比很高,因此,纯文本的内容最好进行压缩,例如html,js,css,xml,shtml等格式文件
- 被压缩的纯文本文件必须要大于1kb,由于压缩算法的特殊原因,极小的文件压缩后可能发呢变大
- 图片,视频等文件尽量不要压缩,因为这些文件大多都是经过压缩的,如果在压缩很可能不会减小或减小很少,或者有可能增大,同时压缩时还会消耗大量cpu,内存
功能依赖于ngx_http_gzip_module模块,默认已安装
这个模块主要是负责Gzip功能的开启和设置,对响应数据进行在线实时压缩。指令如下
语法 | 说明 |
---|---|
是否开启压缩 gzip on | off |
该指令用于开启或者关闭Gzip功能, 默认情况下该指令设置为off,只有为on时,下面指令才有效 |
压缩需要申请的空间 gzip_buffers number size |
number:指定Nginx服务器需要向系统申请缓存空间的个数 size :指定缓存空间的大小; 根据该配置,nginx在对响应输出数据经压缩时需要向系统申请number*size 大小的空间用来存储压缩数据. 默认大小是128,其中size的值是取系统内存页一页的大小,为4kb或者8kb 即: gzip_buffers 32 4k | 16 8k |
压缩等级 gzip_comp_level level |
该指令用于设置Gzip压缩程度,包括级别1-9, 级别1表示压缩程度最低效率最高, 级别9表示 压缩程度最高,效率最低 。 默认值是1 |
根据客户端类型动态开启压缩 gzip_disabel regex… |
针对不同的客户端的请求,可以选择性的开启和关闭Gzip的功能 ,Nginx服务器在响应这种种类的客户端请求时,不使用Gzip功能缓存响应输出数据。regex根据客户端的浏览器标志(User-Agent,UA)设置,支持正则表达式。 例如 gzip_disable MSIE [4-6] 表示MSIE4、MSIE5、MSIE6、这些客户端请求后,nginx不进行Gzip压缩返回 |
根据浏览器版本是否开启压缩 gzip_http_version version |
早期的浏览器也许不支持Gzip的自解压,因此客户端有可能会看到乱码,所以针对不同的HTTP协议版本,需要选择性地开启或者关闭Gzip功能。 默认设置为1.1版本,即只有客户端1.1及以上版本的HTTP协议,才使用Gzip压缩功能,目前来看大部分浏览器都支持Gzip自解压,所以使用默认值即可。 |
根据响应数据大小是否开启压缩 gzip_min_length length |
Gzip压缩功能对大数据的压缩效果明显,但是如果压缩的数据很小,就可能数据越压缩越大,因此我们也应该有选择的压缩。当响应页面的大小大于该值才开启Gzip压缩功能。响应页面的大小通过HTTP响应头部中的Content-Length指令获取,如果我们使用了Chunk编码压缩,Content-Length或不存在或被忽略,这条指令这不起作用。 默认值是20,设置为0表示不管页面多大都要压缩。建议大于1kb的压缩;比如:gzip_min_length 1024 |
根据响应头部是否开启压缩 gzip_proxied off|expired |no-cache | no-store | private | no_last_modified | no_etag | auth | any …; |
off:表示关闭Nginx服务器对后端服务器返回结果的压缩,这是默认设置 expired:表示当后端服务器响应页头部包含用于指示响应数据过期时间的expired头域时,启用对响应数据的Gzip压缩 no-cache:表示当后端服务器响应页头部包含用于通知缓存机制是否缓存的Cache-Control头域,且其指令值为no-cache时,启用对响应数据的Gzip压缩 no-store:表示当后端服务器响应页头部包含用于通知缓存机制是否缓存的Cache-Control头域,且其指令值为no-store时,启用对响应数据的Gzip压缩 private:表示当后端服务器响应页头部包含用于通知缓存机制是否缓存的Cache-Control头域,且其指令值为private时,启用对响应数据的Gzip压缩 no_last_modified:表示当后端服务器响应页头部不包含用于指明获取数据最后修改时间的Last-Modified头域时,启动对响应数据的Gzip压缩 no_etag:表示当后端服务器响应页头部不包含用于标示被请求变量的实体值的ETag头域时,启动对响应数据的Gzip压缩 auth:表示当后端服务器响应页头部包含用于标示HTTP授权证书的Authorization头域时时,启动对响应数据的Gzip压缩 any:无条件启动对响应数据的Gzip压缩 |
根据响应页的MIME类型开启是否压缩 gzip_types mime-type …; |
这个mime-type的默认值是text/html,实际上当gzip设置为on的时候,Nginx服务器会对所有的text/html类型的页面进行Gzip压缩,该变量还可以取值“*”,表示对所有的MIME类型页面进行压缩,一般我们如下设置: gzip_types text/plain application/x-javascript text/css text/html application/html; |
用与设置Gzip功能是否发送带有“Vary:Accept-Encoding”头域的响应头部 gzip_vary on | off |
该头域的主要功能主要是告诉接收方发送的数据时通过压缩处理,开启后的效果是在响应头部添加Accept-Encoding:gzip.这对于本身不止Gzip压缩的客户端浏览器是很有用的。 默认是off的,当然我也可以通过nginx配置的add_header指令强制Nginx服务器在响应头部添加“Vary:Accept-Encoding”头域: add_header Vary Accept-Encoding gzip; |
参考如下
gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
配置nginx expires缓存实现性能优化
就是本地浏览器缓存的有效期,配置参数如下
(1)根据文件扩展名进行判断,添加expires功能,server字段标签中
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${
expires 3650d;
}
(2) 根据url中的路径(目录)进行判断,添加expires功能
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
expires 360d;
}
(3) 单个文件添加expires功能
下面的命令会给robots.txt机器人文件设置过期时间
location ~ (robots.txt) { expires 70d; break; }
不记录不需要的访问日志
对于负载均衡器健康节点检查或某些特定文件(比如图片,js,css)的日志,因为在统计pv时时按照页面计算的,而且日志写入太频繁会消耗大量磁盘i/o,降低服务的性能
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)${
access_log off;
}
日志权限不要设为nginx,www用户读或写许可。
压力测试ab参数
ab -c 1 -n 10 http://1.1.1.1/ -c 并发数,-n请求总数,1.1.1.1为nginx的ip地址
try_files
server { listen port; server_name localhost; root html/a; index index.php; location / { #try_files $uri $uri/ /index.php =404; try_files $uri $uri/ /index.php =500; } error_page 404 /404.html; error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } location ~ \.php$ { try_files $uri = 404; fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
用户请求 http://localhost/example 时,这里的 $uri 就是 /example。
try_files 会到硬盘里尝试找这个文件。如果存在名为 /$root/example(其中 $root 是项目代码安装目录html/a)的文件,就直接把这个文件的内容发送给用户。
显然,目录中没有叫 example 的文件。然后就看 $uri/,增加了一个 /,也就是看有没有名为 /$root/example/ 的目录。
又找不到,就会 fall back 到 try_files 的最后一个选项 /index.php,发起一个内部 “子请求”,也就是相当于 nginx 发起一个 HTTP 请求到 http://localhost/index.php。
这个请求会被 location ~ .*\.(php|php5)?$ { ... } catch 住,也就是进入 FastCGI 的处理程序。而具体的 URI 及参数是在 REQUEST_URI 中传递给 FastCGI 和 PHP 程序的,因此不受 URI 变化的影响。