Nginx服务
1、Nginx基础Http协议
1. Http协议介绍
1.1 什么是URL
通常我们在访问一个网站页面时,请求到的内容通称为"资源"。而”资源“这一概念非常宽泛,它可以是一份文档,一张图片,或所有其他你能够想到的格式。每个资源都由一个 URI 来进行标识;
比如: http://file.ops.com/public/tt.jpg 这样的资源,我们会将该其称为URL地址;
百度百科解释:URL简称统一资源定位符,用来唯一地标识万维网中的某一个资源。URL由协议、主机名称、端口以及文件名几部分构成。
1.2 什么是HTML
Html简称Web Page,一个完整的Html页面可能会包含很多个URL的资源。(反之: 我们也可以理解一个HTML文件是由多个不同的URL资源拼接而成的。)
1.3 什么是HTTP
HTTP (Hyper Text Transfer Protocol) 中文名为超文本传输协议。
是一种能够获取如 HTML 这样网络资源的通讯协议。它是在 Web 上进行数据交换的基础。HTTP的概述参考URL 简单理解:HTTP协议就是将用户请求的HTML页面从一台Web服务器传输到客户端浏览器的一种协议。
1.4 URL、HTML、HTTP之间关系
一个完整的
HTML页面是由多个不同的Url资源组成的;而HTTP协议主要是用来传输这种HTML页面的;http://web.ops.com:80/image
https://web.ops.com:80/video SSL
2. Http工作原理
2.1 图解HTTP工作原理
我们详细的了解下HTTP的工作原理,我们到底是如何获取到服务器上的页面。

2.2 抓包分析HTTP原理
第一步:浏览器分析超链接中的URL
DNS
第二步:DNS请求
[root@ubuntu2204 ~]#ping baidu.comPC向DNS服务器223.5.5.5发出DNS QUERY请求,请求baidu.com的A记录
第三步:DNS回复
DNS服务器223.5.5.5回复DNS response,解析出baidu.com域名对应的一条A记录39.104.16.126
HTTP
第五步:Http请求
[root@ubuntu2204 ~]#curl www.baidu.comPC向 baidu.com 服务器发出GET请求,请求主页
第六步:Http响应
baidu.com 服务器回应HTTP/1.1 200 OK,返回主页数据包
第七步:连接断开
完成数据交互过程,四次挥手断开连接
2.3 HTTP工作原理总结
整个用户访问网站过程就是 DNS-TCP-HTTP (面试必须的协议)

3. Http请求Request
HTTP 请求的一个例子:

3.1 请求Method
客户端向服务端发送请求时,会根据不同的资源发送不同的请求方法Method:
GET:用于获取URI对应的资源;(比如看朋友圈) 99 100
POST:用于提交请求,可以更新或者创建资源,是非幂等的;(发布朋友圈)
PUT:用于向指定的URI传送更新资源,是幂等的;(更新朋友圈)
DELETE:用于向指定的URI删除资源;(比如删朋友圈)
HEAD:用于检查(仅获取Header部分的内容;)
一般创建对象时用POST,更新对象时用PUT;
PUT是幂等的,POST是非幂等的;
幂等:对于相同的输入,每次得到的结果都是相等的;
3.2 请求Header
:authority: www.baidu.com
:method: GET
:path: /
:scheme: https
Accept: text/html # 请求的类型
Accept-Encoding: gzip, deflate # 是否进行压缩
Accept-Language: zh-CN,zh;q=0.9 # 请求的语言
Cache-Control: max-age=0 # 缓存
Connection: keep-alive # TCP长连接
Host: www.baidu.com # 请求的域名
If-Modified-Since: Fri, 04 May 2024 08:13:44 GMT# 修改的时间
User-Agent: Mozilla/5.0 # 请求浏览器的工具
"=== 请求一个空行 ==="
"=== 请求内容主体 ==="3.3 请求Connection
Http请求中的长连接与短连接是什么:
http1.0 协议使用的是短连接:建立一次tcp的连接,发起一次http的请求,结束,tcp断开。
http1.1 协议使用的是长连接:建立一次tcp的连接,发起多次http的请求,结束,tcp断开。
HTTP协议版本参考URL、HTTP1.1与HTTP2.0速度对比

4. Http响应Response
4.1 响应Header
#服务端响应的头部信息
HTTP/1.1 200 OK # 返回服务器的http协议,状态码
Date: Fri, 14 Sep 2018 09:14:28 GMT # 返回服务器的时间
Server: Apache/2.4.6 # 返回服务器使用的软件Apache
Connection: Keep-Alive # TCP长连接
Keep-Alive: timeout=5, max=100 # 长连接的超时时间
"=== 返回一个空行 ==="
"=== 返回内容主体 ==="4.2 响应Status
http 响应状态码 Status-Code 以3位数字组成,用来标识该请求是否成功,比如是正常还是错误等,HTTP/1.1 中状态码可以分为五大类。
4.3 响应Code
以下是常见状态码
5. Http相关术语
5.1 什么是PV
PV即页面浏览量:比如用户访问一个网站算1个pv,刷新一次页面则累计pv+1,如果多次打开或刷新同一页面则浏览量累计。假设我们对一个网站的A页面和B页面分别刷新了10次,请问该用户总共产生了多少PV?
5.2 什么是UV
UV即独立访客,访问网站的一台电脑客户端为一个访客。可以理解成访问某网站的电脑的数量。比如电脑、手机算2个UV,无论访问多少次网站,最终UV数量就是2。
5.3 什么是IP
IP即独立公网IP数,是指1天内多少个独立的IP浏览了页面,比如你在家通过拨号上网访问某个网站,此时网站会记录你的公网IP地址。那如果你在公司和很多同事同时访问一个网站,那该网站会记录多少个公网IP呢? (看公司有多少个出口公网地址)
5.4 什么是并发
并发:指的是同时,我们可以理解为一段时间内(比如10秒),网站支持同时访问的人数,假设10s并发值如果为500时,一天能达到多少PV? 500 * 6 * 60 * 24 =4320000
5.5 扩展延伸
1.请计算如下题的 IP、PV、UV、并发
假设公司有一座大厦,大厦有100人,每个人有一台电脑和一部手机,上网都是通过NAT转换,每个人刷新网站10次,请问对应的 pv,uv,ip,并发分别是多少。PV:页面浏览量 100人 * 2设备 * 10次刷新 = 2000pvUV:独立的客户 100人 * 2设备 = 200UVIP:独立公网IP 100人--> NAT = 1个独立IP并发:单位时间内100人同时请求网站,200
2.面试题:上家公司的IP、PV,UV是多少?(运营)
小说网站 1分钟并发 50006024=720w (屌丝、通常一看一天)
教育网站 1分钟并发 100006024=1440w (努力青年、通常周末量大)
金融网站 1分钟并发 500*1440= 72w (有钱人、所以量不大、但交易额度高)
电商网站 1分钟并发 游戏网站 ------在线用户、日活跃数、月活跃数
需要注意的是: 这仅仅是参考值,因为不同的业务他们的pv都不一样。
3.面试题: 上家公司的IP、PV、UV是如何统计的?
方式一:使用awk提取IP,sort排序、uniq统计去重统计IP
方式二:第三方统计工具进行pv统计,比如:piwik、腾讯分析、百度统计、开发自研统计平台。
2、Nginx基础网络IO模型
1. IO基本概述
1.1 什么是IO
所谓
IO,无非就是输入输出,其实大家更多关注的是磁盘IO,事实上当我们在网络中传送一些数据时,他本质上也是一种IO。
1.2 什么是网络IO
那用户请求
Nginx这样的web服务器获取磁盘中的文件时,系统是如何处理的?

通过上面的例子,用户每一次请求都会发生一次IO操作:而每次IO,都要经由两个阶段:
第一步:将数据从磁盘加载至内核的内存空间(缓存区),等待数据准备完成,时间较长。
第二步:将数据从内核缓冲区复制到用户空间的进程内存(缓存区),时间较短。
第三步:Nginx封装数据为响应报文发送。
nginx下发指令给内核后,nginx是等待,还是不等待继续处理新的请求;
数据拷贝到内核缓存中了,通知nginx应用程序,阻塞;
2. IO网络模型
IO模型分为、同步、异步、阻塞、非阻塞
2.1 同步/异步
同步/异步( 关注的是消息通知机制 ) leader(等待)-->小弟-->任务-->漫长
同步:调用者发指令给被调用者,被调用者需要获取资源后在返回给调用者,那么此时调用者需要等待被调用者返回消息,也就意味着调用者啥也干不了。(举例:当我们将衣服扔进洗衣服,那么衣服洗完没洗完也不知道,那就需要过一段时间去看一下,对于调用者来说很繁忙。)
异步:调用者发指令给被调用者,被调用者需要获取资源后在返回给调用者,此时”被调用者“会主动将当前的运行状态通知给调用者。(举例:当我们将衣服扔进洗衣机,当洗衣机完成洗衣服之前我们可以做点别的事情,等洗完后洗衣机会通知,此时我在去晾衣服。)
2.2 阻塞/非阻塞
阻塞/非阻塞( 关注的是“调用者”在等待”被调用者“返回结果之前所处的状态 )
阻塞:指
IO操作需要彻底完成后才返回到用户空间,调用结果返回之前 ,调用者被挂起。(举例:将衣服仍给洗衣机,然后人一直在旁边等着,什么时候洗完什么时候执行下一步动作。)非阻塞:指
IO操作被调用后立即返回给用户进程一个状态值,无需等待IO操作彻底完成,在最终的调用结果返回之前,调用者不会被挂起。(举例:将衣服仍给洗衣机,然后可以去干其他的事情,等洗完后,在去处理。)
2.3 IO组合模型
同步阻塞:将衣服仍到洗衣机,然后守在洗衣机旁边,等待他什么时候洗完什么时候处理。
同步非阻塞:将衣服仍到洗衣机,然后可以去干别的事情,那是否洗完不知道,就需要时不时看一下。
异步阻塞:将衣服仍给洗衣机,还是会在旁边等着(阻塞),洗衣机洗完了会通知。
异步非阻塞:将衣服仍给洗衣机,可以去干其他事情,等待洗衣机洗完了会通知,然后在去取衣服。
3. 五种常见IO模型
3.1同步阻塞IO
1.当用户进程调用了recvfrom()这个系统调用,希望从磁盘获取数据。
2.kernel就开始了IO的第一个阶段,准备数据,如果数据需要很长时间 ,那么就需要一直等待。
3.当kernel数据准备好了,会将数据从kernel中拷贝到用户进程内存,然后kernel返回数据结果,用户进程才解除阻塞状态,可以做其他事情。
总结,同步阻塞IO的特点就是在IO执行的两个阶段都被阻塞了。那么也就意味着一个进程只能响应一个用户请求,剩下请求会被挂起,会造成每次只能响应一个请求。

举例:我和女友点在饭店完餐后,不知道什么时候能做好,只好坐在餐厅里面等,直到做好,然后吃完才离开。女友本来还想和我一起逛街,但是不知道饭能什么时候做好,只好和我一起在餐厅等,而不能去逛街,直到吃完饭才能去逛街,中间等待做饭的时间浪费掉了。这就是阻塞IO。
3.2 同步非阻塞IO
1.当用户进程调用了recvfrom()这个系统调用,希望从磁盘获取数据。
2.那么是否完成并不知道,需要一次一次的去问。
3.当kernel中的数据准备好了,此时用户进程再次发起系统调用,那么它马上将数据拷贝到了用户进程内存所以,非阻塞IO的特点是用户进程需要不断的主动询问kernel数据好了没有。
好处:用户进程可以处理其他任务;
坏处:任务完成的响应延迟增大了,因为每过一段时间才去轮询一次read操作;

举例:我女友不甘心傻等,又想去逛商场,又担心饭好了。所以我们逛一会,回来询问服务员饭好了没有,来来回回好多次,饭都还没吃都快累死了。这就是非阻塞。需要不断的询问,是否准备好了。
3.3 IO多路复用
1.当用户进程发起调用请求,不用直接与内核交互,而是找一个代理进程select,当用户进程调用select,那么整个进程会阻塞在select上(因为是由select与内核进行交互,需要等待select返回结果)
2.kernel会“监视”select负责的数据,当任何一个进程的数据准备好了,select就会返回。
3.当 select 用户进程返回结果后,用户程序会再次进行系统调用,将 kernel 数据拷贝到用户进程。总结,select代理进程,它这一个进程可以接收多个用户进程的请求。(类似于用户-->飞猪-->办理签证)

举例:与第二个方案差不多,餐厅安装了电子屏幕用来显示点餐的状态,这样我和女友逛街一会,回来就不用去询问服务员了,直接看电子屏幕就可以了。这样每个人的餐是否好了,都直接看电子屏幕就可以了,这就是IO多路复用。
3.4 信号驱动IO
1.当用户进程调用了 recvfrom() 这个系统调用,希望从磁盘获取数据。
2.磁盘文件中的数据如果还没有读取到内核缓冲区时,没关系,进程还可以继续运行并不阻塞。
3.当磁盘数据复制到内核中后,会通知用户进程数据准备就绪。
4.用户进程在发指定将内核中数据复制到用户进程中,此时进程会进入阻塞状态。

举例:我和女友通过手机点完餐后,系统会返回下单成功。此时我和女友就可以出去逛街一会,直到手机通知你的餐已经做好,我和女友在回来吃饭,但吃饭过程会被阻塞。
通知机制:
水平触发:多次通知;
边缘触发:只通知一次;
3.5 异步非阻塞IO
1.当用户进程调用了recvfrom()这个系统调用,希望从磁盘获取数据。
2.kernel收到后,会立刻返回,所以不会对用户进程产生任何阻塞。
3.kernel等待数据准备完成,并将内核数据拷贝到用户进程内存,当这一切都完成之后,kernel会给用户进程发送一个回调函数通知用户进程本次IO完成。
举例:女友不想逛街,餐厅又太吵了,准备回家好好休息一下。于是我们叫外卖,打个电话点餐,然后我和女友在家好好休息一下,饭好了,外卖会送到家里来。这就是异步非阻塞IO
3.6 IO模型对比

4. IO模型实现
4.1 几种网络IO模型实现
Select:对应,I/O复用模型,遍历,(1000 --O(500))
Poll:对应,I/O复用模型
Epoll:对应,IO复用模型,具有信号驱动I/O模型某些特性(O(1))
4.2 
无论是 select、poll、epoll 都可以面对多个用户进程的请求,它相当于一个代理人,收集很多用户进程的请求,收集完成后,它帮你从磁盘上获取数据,复制到内核中,那么这个数据准备没准备好,它的实现机制是不一样的。
通知方式:假设有一个用户数据准备好了,那么还有很多用户数据没准备好,那么如何通知呢?
1、select和poll是遍历扫描,效率低下。2、epoll采用回调机制,epoll会主动通知,效率会更高。
IO效率:假设100个用户发请求和1000个用户发请求,在遍历的时候的性能一样吗?
1、select和 poll用户的请求越多,所需要遍历的就越多,需要耗时就越长。2、epool采用的是回调方式,无论有多少用户,它发送的时间是一样的。
总结:1、nginx从最初设计时,就是使用的 epoll IO 模型,使用边缘触发机制。2、同时 nginx 还支持异步IO,用了近几年最新的服务端编程技术,来支持较好的并发。
3、Nginx Web快速入门
1. Nginx基本简述
1.1 什么是Nginx
Nginx是一个开源且高性能、可靠的Http Web服务、代理服务。
开源,体现在直接获取
Nginx的源代码(F5公司收购);高性能,体现在支持海量的并发;
高可靠,体现在服务稳定;
1.2 为什么选择Nginx
1.2.1 高性能、高并发
通常正常情况下,单次请求会得到更快的响应。另一方面在高峰期(如有数以万计的并发请求),Nginx可以比其他Web服务器更快地响应请求。
select:O(n)
epool:O(1)
1.2.2 高扩展性
Nginx官方、第三方,提供了非常多优秀的模块提供使用,这些模块都可以实现快速增加和减少。
nginx ---> uwsgi ---> python--> py脚本文件
1.2.3 高可靠性
所谓高可靠性,是指Nginx可以在服务器上持续不间断的运行,而很多web服务器往往运行几周或几个月就需要进行一次重启。windows的 IIS对于nginx这样的一个高并发、高性能的反向代理服务器而言,他往往运行网站架构的最前端,那么此时如果我们企业如果想提供9999、99999,对于nginx持续运行能够宕机的时间,一年可能只能以秒来计算,所以在这样的一个角色中,nginx的高可靠性为我们提供了非常好的保证。
1.2.4 热部署
热部署是指在不停服务的情况下升级nginx,这个功能非常的重要。
对于普通的服务,只需要kill掉进程在启动,但对于Nginx而言,如果Nginx有很多的客户端连接,那么kill掉Nginx。Nginx会像客户端发送tcp reset复位包,但很多客户端无法很好的理解reset包,就会造成异常。
由于Nginx的master管理进程与worker工作进程的分离设计,使得Nginx能够在7×24小时不间断服务的前提下,升级Nginx的可执行文件。当然,也支持不停止服务更新配置、更换日志文件等功能。
1.2.5 应用广泛
首先Nginx技术成熟,具备企业最常使用的功能,如代理、代理缓存、负载均衡、静态资源、动静分离、Https、lnmp、lnmt等等其次使用Nginx统一技术栈,降低维护成本,同时降低技术更新成本。
tengine\OpenResty 都是基于Nginx进行的二次开发;
1.2.6 网络模型
Nginx使用Epool网络模型,而常听到Apache采用的是Select网络模型。
Select:当用户发起一次请求,select模型就会进行一次遍历扫描,从而导致性能低下。
Epoll:当用户发起请求,epoll模型会直接进行处理,效率高效。
1.3 Nginx应用场景
Nginx的主要使用场景我归纳为三个,分为是静态资源服务、代理资源服务、安全服务,场景详细介绍如下
如下图是一个网站的基本架构,首先用户请求先到达nginx,然后在到 tomcat或php这样的应用服务器,然后应用服务器在去访问 redis、mysql这样的数据库,提供基本的数据功能。

1.3.1 负载均衡场景
那么这里有一个问题,我们的程序代码要求开发效率高,所以他的运行效率是很低的,或者说它并发是受限,所以我们需要很多应用服务组成一个集群,为更多用户提供访问。
而应用服务一但构成集群,则需要我们的nginx具有反向代理功能,这样可以将动态请求传倒给集群服务。
但很多应用构成集群,那么一定会带来两个需求。
1、应用服务器需要动态扩展。(手动扩展|自动扩展)
2、有些服务出问题需要做容灾。那么我们的反向代理必须具备负载均衡功能。

1.3.2 代理缓存场景
其次,随着我们网络链路的增长,用户体验到的时延则会增加。如果我们能把一段时间内不会发生变化的"动态"内容,缓存在Nginx,由Nginx直接向用户提供访问,那么这样用户请求的时延就会减少很多,所以在这里反向代理会演生出另外一个功能 "缓存",因为它能加速我们的访问。

1.3.3 静态资源场景
在很多时候我们访问docs、pdf、mp4、png等这样的静态资源时,是没有必要将这些请求通过Nginx交给后端的应用服务,我们只需要通过Nginx直接处理“静态资源”即可。这是Nginx的静态资源功能。

1.3.4 安全应用场景
当我们使用http网站时,可能会遭遇到篡改,如果使用https安全通讯协议,那么数据在传输过程中是加密的,从而能有效的避免黑客窃取或者篡改数据信息,同时也能避免网站在传输过程中的信息泄露。大大的提升我们网站安全。

1.4 Nginx组成部分
在这里我们将Nginx的组成架构比喻为一辆汽车:
这个汽车提供了基本的驾驶功能,但是还需要一个驾驶员控制这辆汽车开往哪个方向,同时该汽车行驶过的地方还会形成GPS轨迹,如果汽车在行驶的过程中出现了任何问题,我们需要一个黑匣子,分析是汽车本身的问题,还是驾驶人员的操作出现了问题。

第一个组成部分
Nginx二进制可执行文件:它是Nginx本身框架以及相关模块等构建的一个二进制文件,这个文件就相当于汽车本身,所有的功能都由它提供。第二个组成部分
Nginx.conf文件:它相当于驾驶人员,虽然二进制可执行文件已经提供了许多的功能,但是这些功能究竟有没有开启,或者开启后定义怎样的行为去处理请求,都是由nginx.conf这个文件决定的,所以他就相当于这个汽车的驾驶员,控制这个汽车的行为。第三个组成部分
access.log:它相当于这辆汽车经过所有地方形成的GPS轨迹,access.log会记录Nginx处理过的每一条HTTP的请求信息、响应信息。第四个组成部分
error.log:它相当于黑匣子,当出现了一些不可预期的问题时,可以通过error.log将问题定位出来。
Nginx组成部分小结:
Nginx的组成部分是相辅相成,Nginx二进制文件和Nginx.conf文件,它定义了Nginx处理请求的方式。
而如果我们想对Nginx服务做一些web的运营和运维,需要对access.log做进一步分析。
而如果出现了任何未知的错误,或者预期的行为不一致时,应该通过error.log去定位根本性的问题。
2. Nginx安装部署
2.1 安装Nginx方式
安装Nginx软件的方式有很多种,分为如下几种
1.源码编译=>Nginx (1.版本随意 2.安装复杂 3.升级繁琐)
2.epel仓库=>Nginx (1.版本较低 2.安装简单 3.配置不易读)
3.官方仓库=>Nginx (1.版本较新 2.安装简单 3.配置易读,强烈推荐)
2.2 安装Nginx依赖
[root@ops ~]# yum install -y gcc gcc-c++ autoconf pcre pcre-devel make automake httpd-tools vim2.3 配置Nginx源
[root@ops ~]# cat > /etc/yum.repos.d/nginx.repo <<'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
EOF2.4 安装Nginx服务
[root@ops ~]# yum install nginx -y
[root@ops ~]# systemctl enable --now nginx2.5 访问Nginx服务

2.6 检查Nginx版本
# 检查版本
[root@ops ~]# nginx -v
nginx version: nginx/1.20.1
# 检查编译参数
[root@ops ~]# nginx -V
[root@centos7 ~]# nginx -V
nginx version: nginx/1.26.1
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'3.Nginx目录结构
为了让大家更清晰的了解
Nginx软件的全貌,可使用rpm -ql nginx查看软件整体目录结构如下表格整理了
Nginx比较重要的配置文件
3.1 Nginx主配置文件
3.2 Nginx代理配置文件
3.3 Nginx编码配置文件
3.4 Nginx管理命令文件
3.5 Nginx日志相关文件
4.Nginx基本配置
Nginx主配置文件/etc/nginx/nginx.conf是一个纯文本类型的文件;Nginx整个配置文件是以区块的形式组织的。一般每个区块以一对大括号{}来表示开始与结束。
[root@ops ~]# cat /etc/nginx/nginx.conf
# 全局
user nginx; # nginx的运行身份为nginx用户;
worker_processes 2; # 启动的worker进程数量;
error_log /var/log/nginx/error.log warn;
# 错误日志的路径;从warning;
pid /var/run/nginx.pid;
# 存储进程的pid Number
# 4c * 16GB
events {
# 一个worker最大连接数
worker_connections 1024;
# worker_connections * worker_processes = 最大连接数
use epoll; # 默认是采用epoll网络IO模型;
}
# 主要负责接受与响应http请求
http {
include /etc/nginx/mime.types;
# 支持的类型;
default_type application/octet-stream;
# 默认类型(下载的方式)
# 1.提供下载包 zip
# 2.后端并没有将代码解析成功,所以直接成了下载;
# 定义日志的格式
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 /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#长连接超时时间;
#gzip on;
include /etc/nginx/conf.d/*.conf;
# 包含的子文件;
}
######
# 一个server就是一个站点
server {
listen 80; # 监听的端口
server_name www.ops.net; # 站点的域名
location / { #uri路径匹配的
root /usr/share/nginx/html; #root:定义网站的路径;
index index.html index.htm; #index:定义默认返回的页面;
# root+index =/usr/share/nginx/html/index.html;
}
}
# 一个server就是一个站点
server {
listen 80; # 监听的端口
server_name db.ops.net; # 站点的域名
location / { #uri路径匹配的
root /usr/share/nginx/html; #root:定义网站的路径;
index index.html index.htm; #index:定义默认返回的页面;
# root+index =/usr/share/nginx/html/index.html;
}
}4.1 Global全局模块
user www; #Nginx进程所使用的用户
worker_processes 1; #Nginx运行的work进程数量(建议与CPU数量一致或auto)
error_log /log/nginx/error.log #Nginx错误日志存放路径
pid /var/run/nginx.pid #Nginx服务运行后产生的pid进程号4.2 Events事件模块
events {
worker_connections 25535; #每个worker进程支持的最大连接数
use epoll; #事件驱动模型, epoll默认
}4.3 HTTP核心模块
http { #http层开始
...
#使用Server配置网站, 每个Server{}代表一个网站(简称虚拟主机)
'server' {
listen 80; #监听端口, 默认80
server_name ops.com; #提供的域名
access_log access.log; #该网站的访问日志
#控制网站访问的路径
'location' / {
root /usr/share/nginx/html;
#存放网站源代码的位置
index index.html index.htm;
#默认返回网站的文件
}
}
...
#第二个虚拟主机配置
'server' {
...
}
include /etc/nginx/conf.d/*.conf; #包含/etc/nginx/conf.d/目录下所有以.conf结尾的文件
#include作用是:简化主配置文件写太多造成臃肿,这样会让整体的配置文件更加的清晰。
} #http层结束4.4 核心模块总结
Nginx中的http、server、location之间的关系
http标签主要用来解决用户的请求与响应;server标签主要用来响应具体的某一个网站;location标签主要用于匹配网站具体URI路径;
http{}下允许有多个Server{},一个Server{}下又允许有多个location{}
5.Nginx构建游戏网站
5.1 增加Nginx配置
[root@ops ~]# cat /etc/nginx/conf.d/game.ops.net.conf
server {
listen 80;
server_name game.ops.net;
location / {
root /code;
index index.html;
}
}5.2 上传游戏代码
[root@ops conf.d]# mkdir /code && cd /code
[root@ops code]# unzip html5.zip
[root@ops code]# ls
ceshi game html5.zip img index.html readme.txt5.3 检查配置语法
[root@ops /code]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful5.4 重启服务生效
[root@ops code]# systemctl reload nginx5.5 浏览器访问

6.Nginx虚拟主机
6.1 Nginx虚拟主机概念
通常在企业中可能会有很多业务系统,那么多套业务服务如何使用Nginx配置?

如果使用如上方式部署,则需要多台服务器配置Nginx,但如果使用虚拟主机方式,则在同一个Nginx上运行多套单独服务,这些服务是相互独立的。
简单来说,看似多套业务系统,实则可以运行在一台Nginx服务上

6.2 Nginx配置虚拟主机方式
Nginx配置虚拟主机有如下三种方式
1、基于主机多
IP方式2、基于端口的配置方式
3、基于多个
hosts名称方式(多域名方式)
6.3 基于多IP虚拟主机实践
Nginx基于多IP虚拟主机具体配置如下
[root@ops ~]# cat /etc/nginx/conf.d/address.conf
server {
...
listen 10.0.0.10:80;
...
}
server {
...
listen 172.16.1.10:80;
...
}范例
[root@ops /etc/nginx/conf.d]# cat address.conf
server {
listen 192.168.10.137:80;
server_name game.ops.net;
location / {
root /code;
index index.html;
}
}
server {
listen 10.0.0.7:80;
server_name game.ops.net;
location / {
root /code;
index index.html;
}
}6.4 基于多端口虚拟主机实践
Nginx基于多端口虚拟主机具体配置如下
#仅修改listen监听端口即可, 但不能和系统端口出现冲突
[root@ops ~]# cat /etc/nginx/conf.d/port1.conf
server {
...
listen 80;
...
}
[root@ops ~]# cat /etc/nginx/conf.d/port2.conf
server {
...
listen 81;
...
}
[root@ops ~]# cat /etc/nginx/conf.d/port3.conf
server {
...
listen 82;
...
}范例
[root@ops /etc/nginx/conf.d]# cat port.conf
server {
listen 81;
server_name game.ops.net;
location / {
root /code;
index index.html;
}
}
server {
listen 82;
server_name game.ops.net;
location / {
root /code;
index index.html;
}
}6.5 基于多域名虚拟主机实践
Nginx基于多Host虚拟主机具体配置如下
[root@ops /etc/nginx/conf.d]# mkdir /code/server{1,2}
[root@ops /etc/nginx/conf.d]# echo "server1" > /code/server1/index.html
[root@ops /etc/nginx/conf.d]# echo "server2" > /code/server2/index.html
[root@ops /etc/nginx/conf.d]# cat server1.conf
server {
listen 80;
server_name server1.ops.net;
location / {
root /opt/server1/;
index index.html;
}
}
[root@ops /etc/nginx/conf.d]# cat server1.conf
server {
listen 80;
server_name server2.ops.net;
location / {
root /opt/server2/;
index index.html;
}
}4、Nginx 常用模块
1 Nginx目录索引
当ngx_http_index_module模块找不到索引文件时,通常会将请求传递给ngx_http_autoindex_module模块。
ngx_http_autoindex_module模块处理以斜杠字符('/')结尾的请求,并生成目录列表。
由于Nginx是通过静态编译构建的(没有使用--add-dynamic-module),所以模块都是静态链接的。
可以通过查看Nginx的二进制文件来确认:
[root@ops ~]# strings /usr/sbin/nginx | grep ngx_http_autoindex_module
ngx_http_autoindex_module
ngx_http_autoindex_modulengx_http_autoindex_module是 Nginx 的核心模块,用于在客户端请求目录时自动生成并返回该目录的文件列表页面。
1.1 配置语法
#启用或禁用目录列表输出,on开启,off关闭
Syntax: autoindex on | off;
Default: autoindex off;
Context: http, server, location
#指定是否应在目录列表中输出确切的文件大小,on显示字节,off显示大概单位
Syntax: autoindex_exact_size on | off;
Default: autoindex_exact_size on;
Context: http, server, location
#指定目录列表中的时间是应以本地时区还是UTC输出,on本地时区,off UTC时间
Syntax: autoindex_localtime on | off;
Default: autoindex_localtime off;
Context: http, server, location
1.2 配置示例
[root@ops ~]# mount /dev/sr0 /code/
mount: /dev/sr0 写保护,将以只读方式挂载
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
charset utf-8; #设定字符集,防止中文字符乱码显示
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
location / {
root /code/;
}
}
1.3 模拟企业内网仓库
[root@ops mirror]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
charset utf-8;
root /mirror;
location / {
index index.html;
}
#提供yum仓库目录
location /repo {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
}
#使用rsync同步
[root@ops ~]# yum -y install rsync createrepo
[root@ops ~]# mkdir /repo/
[root@ops mirror]# rsync -avz rsync://rsync.mirrors.ustc.edu.cn/centos-vault/7.9.2009/os/x86_64/Packages /repo/
[root@ops ~]# ls /repo
389-ds-base-1.3.10.2-6.el7.x86_64.rpm NetworkManager-ppp-1.18.8-1.el7.x86_64.rpm
389-ds-base-devel-1.3.10.2-6.el7.x86_64.rpm NetworkManager-team-1.18.8-1.el7.x86_64.rpm
# 将该目录创建为仓库目录
[root@ops ~]# createrepo /repo
[root@ops ~]# createrepo /repo
Saving Primary metadata
Saving file lists metadata
Saving other metadata
Generating sqlite DBs
Sqlite DBs complete2 Nginx访问控制
ngx_http_access_module 模块允许限制对某些客户端地址的访问。
2.1 配置语法
#允许配置语法
Syntax: allow address | CIDR | unix: | all;
Default: -
Context: http, server, location,limit_except
#拒绝配置语法
Syntax: deny address | CIDR | unix: | all;
Default: -
Context: http, server, location,limit_except2.2 配置示例
只允许指定的来源IP能访问/centos, 其它网段全部拒绝。
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
charset utf-8;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
root /mirror;
location / {
index index.html;
}
location /centos {
allow 127.0.0.1;
allow 10.0.0.128/32; #允许地址或地址段
deny all; #拒绝所有人
}
}
#说明:10.0.0.128/32中的 /32表示子网掩码为32位全1(255.255.255.255),该地址只能分配给一台主机,无法作为子网使用,这种表示法常用于精确指定单台设备的IP地址
[root@ops ~]# mkdir -p /mirror/centos
[root@ops ~]# cat /mirror/centos/index.html
a
[root@ops ~]# curl -HHost:mirror.ops.net http://127.0.0.1/centos/
[root@ops ~]# tail -1 /etc/hosts
10.0.0.9 mirror.ops.net
拒绝指定的IP访问该网站的/centos,其他IP全部允许访问。
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
charset utf-8; #设定字符集,防止中文字符乱码显示
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
root /mirror;
location / {
index index.html;
}
location /centos {
deny 10.0.0.128/32; #拒绝指定的地址或地址段
allow all; #允许所有的地址
}
}
注意: deny和allow的顺序是有影响的
默认情况下,从第一条规则进行匹配。
如果匹配成功,则不继续匹配下面的内容。
如果匹配不成功,则继续往下寻找能匹配成功的内容。
3 Nginx基础认证
ngx_http_auth_basic_module模块允许使用HTTP基本身份验证,验证用户名和密码来限制对资源的访问。
3.1 配置语法
#使用HTTP基本身份验证协议启用用户名和密码验证
Syntax: auth_basic string| off;
Default: auth_basic off;
Context: http, server, location,limit_except
#指定保存用户名和密码的文件
Syntax: auth_basic_user_file file;
Default: -
Context: http, server, location,limit_except指定保存用户名和密码的文件,格式如下:
#可以使用htpasswd程序或"openssl passwd"命令生成对应的密码;
name1:passwd1
name2:passwd2
#使用htpaaswd创建新的密码文件, -c创建新文件 -b允许命令行输入密码
[root@ops ~]# yum install httpd-tools -y
[root@ops ~]# htpasswd -b -c /etc/nginx/auth_conf demo 1234563.2 配置示例
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
charset utf-8; #设定字符集,防止中文字符乱码显示。
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
root /mirror;
location / {
index index.html;
}
location /centos {
auth_basic "Auth access Blog Input your Passwd!";
auth_basic_user_file /etc/nginx/auth_conf;
}
}
4 Nginx限流限速
4.1 为什么要限速
限制某个用户在一定时间内能够产生的Http请求,或者说限制某个用户的下载速度。
503: 过载保护
4.2 限速应用场景
下载限速:限制用户下载资源的速度ngx_http_core_module
请求限制:限制用户单位时间内所产生的Http请求数ngx_http_limit_req_module
连接限制:限制同一时间的连接数,及并发数限制ngx_http_limit_conn_module
4.3 请求频率限速原理
水(请求)从上方倒入水桶,从水桶下方流出(被处理)。
如果说水(请求)流入的过快,水桶流出(被处理)的过慢,来不及流出的水存在水桶中(缓存),然后以固定速率流出,水桶满后则水溢出(丢弃)。
简单来说就是:当处理速度,达不到请求的速度,则会将请求放置缓存,然后持续处理。当缓存被占满,如果还有大量的请求,则会被丢弃。
4.4 限制请求并发数
指令
Syntax: limit_req_zone key zone=name:size rate=rate;
Default: -
Context: http
Syntax: limit_req zone number [burst=number] [nodelay];
Default: -
Context: http, server, location基于来源IP对下载速率限制,限制每秒处理1次请求,但可以突发超过5个请求放入缓存区
# http标签段定义请求限制, rate限制速率,限制一秒钟最多一个IP请求
$remote_addr; $binary_remote_addr
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s;
server {
listen 80;
server_name mirror.ops.net;
# 请求超过1r/s,剩下的将被延迟处理,请求数超过burst定义的数量,则返回503
limit_req zone=req_one burst=3 nodelay;
location / {
root /code;
index index.html;
}
}
limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s;
#第一个参数:$binary_remote_addr表示通过这个标识来做限制,限制同一客户端ip地址。
#第二个参数:zone=req_one:10m表示生成一个大小为10M,名为req_one的内存区域,用来存储访问的频次信息。
#第三个参数:rate=1r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒1次。
limit_req zone=req_one burst=3 nodelay;
#第一个参数:zone=req_one 设置使用哪个配置区域来做限制,与上面limit_req_zone 里的name对应。
#第二个参数:burst=3,设置一个大小为3的缓冲区,当有大量请求过来时,超过了访问频次限制的请求可以先放到这个缓冲区内。
#第三个参数:nodelay,超过访问频次并且缓冲区也满了的时候,则会返回503,如果没有设置,则所有请求会等待排队。
浏览器刷新的频率快一些,报错如下:

limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s;
server {
listen 80;
server_name mirror.ops.net;
# 请求超过1r/s,剩下的将被延迟处理,请求数超过burst定义的数量,则返回503
limit_req zone=req_one burst=3 nodelay;
limit_req_status 500;
location / {
root /code;
index index.html;
}
}
[root@ops conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@ops conf.d]# systemctl reload nginx
4.5 限制并发连接数
指令
Syntax: limit_conn_zone key zone=name:size;
Default: -
Context: http
Syntax: limit_conn zone number;
Default: -
Context: http, server, location设置共享内存区域和给定键值的最大允许的连接数。超过此限制时,服务器将返回503错误以回复请求
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
limit_conn_zone $binary_remote_addr zone=conn_od:10m;
server {
listen 80;
server_name mirror.ops.net;
root /code;
charset utf8;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
limit_rate 100k;
limit_conn conn_od 2;
location / {
index index.html;
}
}
[root@ops ~]# dd if=/dev/zero of=/code/bigfile bs=100M count=5
报错自定义提示信息:
[root@ops conf.d]# cat ops.conf
limit_req_zone $binary_remote_addr zone=req_one:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=conn_od:10m;
server {
listen 80;
charset utf-8;
server_name mirror.ops.net;
# 请求超过1r/s,剩下的将被延迟处理,请求数超过burst定义的数量,则返回503
# limit_req zone=req_one burst=3 nodelay;
# limit_req_status 500;
limit_rate 100k;
limit_conn conn_od 2;
# 拦截503错误重新定向到@temp,@内部跳转
error_page 503 @temp;
location @temp {
default_type text/html;
return 200 '请联系haoge,充值VIP服务...';
}
location / {
root /code;
index index.html;
}
}

4.6 限制下载速度
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
root /code;
charset utf8;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
limit_rate_after 100m; #达到100m开始限速
limit_rate 100k;
location / {
index index.html;
}
}
4.7 综合场景实践
限制
web服务器请求数处理为1秒一个,触发值为5、限制用户仅可同时下载一个文件当下载超过
100M则限制下载速度为500k如果同时下载超过2个视频,则返回提示 "请联系
haoge进行会员充值" | 跳转到其他页面;
[root@ops conf.d]# cat mirror.ops.net.conf
limit_req_zone $binary_remote_addr zone=req_od:10m rate=1r/s;
limit_conn_zone $binary_remote_addr zone=conn_od:10m;
server {
listen 80;
server_name mirror.ops.net;
root /code;
charset utf8;
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
limit_req zone=req_od burst=5 nodelay;
limit_conn conn_od 1;
limit_rate_after 100m;
limit_rate 500k;
error_page 503 @errpage;
location @errpage {
default_type text/html;
return 200 'haoge提示-->请联系QQ: 123456789 进行会员充值';
}
location / {
index index.html;
}
}
5 Nginx状态监控
ngx_http_stub_status_module模块提供对基本状态信息的访问。
默认情况下不集成该模块,需要使用 --with-http_stub_status_module 集成。

5.1 配置语法
Syntax: stub_status;
Default: -
Context: server, location5.2 配置示例
[root@ops ~]# # nginx -V
[root@ops ~]# cat /etc/nginx/conf.d/mirror.ops.net.conf
server {
listen 80;
server_name mirror.ops.net;
access_log off;
location /nginx_status {
stub_status;
}
}
#浏览器访问:http://mirror.ops.net/nginx_status
目前状态是一次连接多次请求:
# keep-alive 是为了复用TCP连接,避免每次请求都重新建立连接的开销,提高性能
# 允许客户端复用同一个 TCP 连接发送多个 HTTP 请求(减少建立新连接的开销,提高性能)
[root@ops ~]# cat /etc/nginx/nginx.conf | grep kee -n
27: keepalive_timeout 65;[root@ops ~]# vim +27 /etc/nginx/nginx.conf
keepalive_timeout 0;
[root@ops ~]# systemctl reload nginx 目前状态是一次连接一个请求:

[root@ops ~]# cat /etc/nginx/conf.d/module.conf
server {
listen 80;
server_name mirror.ops.net;
access_log off;
location /nginx_status {
stub_status;
allow 10.0.0.166/32;
deny all;
}
}
[root@ops ~]# curl -s -HHost:mirror.ops.net http://10.0.0.6/nginx_status
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.26.1</center>
</body>
</html>
[root@ops conf.d]# cat module.conf
server {
listen 80;
server_name mirror.ops.net;
access_log off;
location /nginx_status {
stub_status;
allow 127.0.0.1;
allow 10.0.0.166/32;
deny all;
}
}
[root@ops conf.d]# curl -HHost:mirror.ops.net http://127.0.0.1/nginx_status
Active connections: 1
server accepts handled requests
5 5 7
Reading: 0 Writing: 1 Waiting: 05.3 页面状态
此配置创建一个简单的网页,其基本状态数据可能如下所示:
[root@ops ~]# curl -HHost:mirror.ops.net http://10.0.0.9/nginx_status
Active connections: 3
server accepts handled requests
65 65 188
Reading: 0 Writing: 1 Waiting: 2
# Active connections:当前活跃连接数,包括Waiting等待连接数。
# accepts: 已接收的总TCP连接数量。
# handled: 已处理的TCP连接数量。
# requests:当前总http请求数量。
# Reading: 当前读取的请求头数量。
# Writing: 当前响应的请求头数量。
# Waiting: 当前等待请求的空闲客户端连接数。如何理解
Reading、Writing、Waiting假设现在有两条船分别为
C 、S。C船需要S船的1个物品,那么此时C船就要给S船发送一个消息。
1、
S船收到这个消息时就是reading2、
S船将物资发送给C船,这个时候就是writing3、如果
C船需要S船很多个物品,那么需要C船和S船建立起一个物资传送管道,不断的传送物资。这个管道建立起来的时候,就是waiting状态了。
[root@ops ~]# curl -s -HHost:mirror.ops.net http://10.0.0.6/nginx_status | awk -F':' 'NR==1 {print $NF}'
3
[root@ops ~]# curl -s -HHost:mirror.ops.net http://10.0.0.6/nginx_status | awk -F':' 'NR==1 {print $NF}' | sed 's# ##g'
1
[root@ops ~]# echo "当前Nginx的活跃连接数:$(curl -s -HHost:mirror.ops.net http://10.0.0.6/nginx_status | awk -F':' 'NR==1 {print $NF}' | sed 's# ##g')"
当前Nginx的活跃连接数:16 Nginx资源缓存
浏览器缓存设置用于提高网站性能,尤其是新闻网站,图片一旦发布,改动的可能是非常小的。所以我们希望能否用户访问一次后,图片缓存在用户的浏览器长时间缓存。
浏览器是有自己的缓存机制,它是基于
HTTP协议缓存机制来实现的,在HTTP协议中有很多头(Headers)信息,那么实现浏览器的缓存就需要依赖特殊的头信息来与服务器进行特殊的验证,如:Expires (http/1.0) ;Cache-control (http/1.1)
6.1 浏览器无缓存

6.2 浏览器有缓存
6.3 缓存过期校验
浏览器缓存过期校验检查机制,说明如下:
浏览器请求服务器会先进行
Expires、CacheControl的检查,检查缓存是否过期,如果没有过期则直接从缓存文件中读取。如果缓存过期,首先检查是否存在
etag,如果存在则会客户端会向web服务器请求if-None-Match,与etag值进行比对,由服务器决策返回200还是304。如果
etag不存在,则进行last-Modified检查,客户端会向web服务器请求If-Modified-Since,与last-Modified进行比对,由服务器决策返回200还是304。

6.4 缓存配置语法
#作用: 添加Cache-Control Expires头
Syntax: expires [modified] time;
expires epoch | max | off;
Default: expires off;
Context: http, server, location, if in location6.5 资源缓存配置场景
server {
listen 80;
server_name static.ops.net;
root /code;
location ~ .*\.(jpg|gif|png)$ {
#客户端(浏览器/CDN)会缓存这些图片文件7天,期间重复请求时直接从本地缓存读取,减少服务器压力,提升加载速度
expires 7d; # 设置客户端缓存过期时间为7天(604800秒)
}
#如果开发代码没有正式上线时,希望静态文件不被缓存
location ~ .*\.(css|js|swf|json|mp4|htm|html)$ {
add_header Cache-Control no-store; # 禁止客户端缓存
add_header Pragma no-cache; # 兼容旧浏览器,强制每次请求验证
}
}
[root@ops ~]# ls /code/
1.jpg index.html
没缓存如下:


7 Nginx资源压缩
Nginx将发送至客户端之前的数据进行压缩,然后传输,这能够有效地节约带宽,并提高响应速度;
图片:不高;
文本:比较高;

7.1 配置语法
# 1、启用或关闭gzip压缩
Syntax: gzip on | off;
Default: gzip off;
Context: http, server, location, if in location
# 2、gzip支持的压缩类型
Syntax: gzip_types mime-type ...;
Default: gzip_types text/html;
Context: http, server, location
# 3、gzip压缩比率,压缩率越高,CPU消耗越大 9
Syntax: gzip_comp_level level;
Default: gzip_comp_level 1;
Context: http, server, location
# 4、gzip压缩的最小文件,小于设置的值文件将不会被压缩(由"Content-Length"响应头字段确定)
Syntax: gzip_min_length length;
Default: gzip_min_length 20;
Context: http, server, location
# 5、gzip压缩支持的协议版本
Syntax: gzip_http_version 1.0 | 1.1;
Default: gzip_http_version 1.1;
Context: http, server, location
# 6、启用压缩,是否在响应报文首部插入"Vary:
Accept-Encoding"
Syntax: gzip_vary on | off;
Default: gzip_vary off;
Context: http, server, location7.2 图片压缩案例
[root@ops conf.d]# mkdir -p /code/images
[root@ops conf.d]# cat /etc/nginx/mime.types | grep image
image/gif gif;
image/jpeg jpeg jpg;
image/png png;
image/svg+xml svg svgz;
image/tiff tif tiff;
image/vnd.wap.wbmp wbmp;
image/webp webp;
image/x-icon ico;
image/x-jng jng;
image/x-ms-bmp bmp;
[root@ops ~]# vim /etc/nginx/conf.d/static.ops.net.conf
server {
listen 80;
server_name static.ops.net;
root /code/images;
location ~* .*\.(jpg|gif|png)$ {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_min_length 10k;
gzip_types image/jpeg image/gif image/png;
gzip_vary on;
}
}
--------------------------------------------
gzip on - 开启 Gzip 压缩
gzip_http_version 1.1 - 支持 HTTP 1.1 协议
gzip_comp_level 2 - 压缩级别为 2(中等压缩)
gzip_min_length 10k - 只压缩大于 10KB 的文件
gzip_types - 压缩指定的图片格式:JPEG、GIF、PNG
gzip_vary on - 根据客户端支持情况自动选择是否压缩
--------------------------------------------
[root@ops ~]# cp /code/1.jpg /code/images/未压缩之前

启用压缩之后

7.3 文件压缩案例
[root@ops ~]# mkdir -p /code/doc
[root@ops ~]# ll -h /code/doc/
总用量 8.7M
-rw-r--r-- 1 root root 8.7M 10月 26 13:35 access.txt
[root@ops conf.d]# cat static_server.conf
server {
listen 80;
server_name static.ops.net;
root /code/doc;
location ~ .*\.(txt|pdf|log)$ {
gzip on;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_min_length 1k;
gzip_types text/plain application/pdf;
gzip_vary on;
}
}8 Nginx Location
8.1 什么是Location
Location用来控制访问网站的uri路径;
8.2 Location语法示例
location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
/api/xxx/dadas/dsadsa
/apiv1/dsa/dsaxx/sadsa/
# 匹配符,匹配规则 优先级
# = 精确匹配 1
# ^~ 以某个字符串开头 2
# ~ 区分大小写的正则匹配 3
# ~* 不区分大小写的正则匹配 4
# / 通用匹配,任何请求都会匹配到 5location uri 添加 / 和不添加 / 的区别?

#不添加/,默认去/code/test目录下找index.html文件,如果没有 index.html, 则会查找/code/test文件
location /test {
root /code;
index index.html;
}
#添加/,匹配任何以 /uri/ 开头的请求路径
location /test/ {
root /code;
}
#示例测试代码
[root@ops code]# cat /etc/nginx/conf.d/uri.ops.net.conf
server {
listen 80;
server_name uri.ops.net;
root /code;
# location /test {
# index index.html;
# }
location /test/ {
index index.html;
}
}8.3 Location优先级示例
[root@ops conf.d]# cat location.ops.net.conf
server {
listen 80;
server_name location.ops.net;
location = / {
default_type text/html;
return 200 'location = /';
}
location / {
default_type text/html;
return 200 'location /';
}
location /documents/ {
default_type text/html;
return 200 'location /documents/';
}
location ^~ /images/ {
default_type text/html;
return 200 'location ^~ /images/';
}
location ~* \.(gif|jpg|jpeg)$ {
default_type text/html;
return 200 'location ~* \. (gif|jpg|jpeg)';
}
}
#测试结果如下(建议是curl测试)
#1.请求 http://location.ops.net/ 会被 location =/ 匹配
[root@rocky9 ~]# curl http://location.ops.net/
location = /
#2.请求 http://location.ops.net/index.html 会被 location / 匹配
[root@rocky9 ~]# curl http://location.ops.net/index.html
location /
#3.请求 http://location.ops.net/documents/1.html 会被 location /documents/ 匹配
[root@rocky9 ~]# curl http://location.ops.net/documents/1.html
location /documents/
#4.请求 http://location.ops.net/images/1.gif 会被 location ^~ /images/ 匹配
[root@rocky9 ~]# curl http://location.ops.net/images/1.gif
location ^~ /images/
#5.请求 http://location.ops.net/documents/1.jpg 会被 location ~* \.(gif|jpg|jpeg)$ 匹配
[root@rocky9 ~]# curl http://location.ops.net/documents/1.jpg
location ~* \. (gif|jpg|jpeg)8.4 Location 应用场景
[root@ops conf.d]# cat location2.ops.net.conf
server {
listen 80;
server_name location2.ops.net;
charset utf-8;
# 通用匹配,任何请求都会匹配到
location / {
root html;
index index.html;
}
# 精准匹配,必须请求的uri是/nginx_status
location = /nginx_status {
stub_status;
}
# 严格区分大小写,匹配以.php结尾的都走这个 location info.php
location ~ \.php$ {
default_type text/html;
return 200 'php访问成功';
}
# 严格区分大小写,匹配以.jsp结尾的都走这个location
location ~ \.jsp$ {
default_type text/html;
return 200 'jsp访问成功';
}
# 不区分大小写匹配,只要用户访问.jpg,gif,png,js,css 都走这条location
location ~* \.(jpg|gif|png|js|css)$ {
# return 403;
expires 3d;
}
# 不区分大小写匹配
location ~* \.(sql|bak|tgz|tar.gz|git)$ {
deny all;
}
}
8.5 Location @重定向
location @name这样的location不用于常规请求处理,而是用于请求重定.
[root@ops conf.d]# cat location3.ops.net.conf
server {
listen 80;
server_name location.ops.net;
root /code;
charset utf-8;
location / {
index index.html;
}
#如果出现异常,则重新定向到@error_404这个location上
error_page 404 @error_404;
location @error_404 {
default_type text/html;
return 200 '你可能是不小心走丢了。';
}
}
[root@ops conf.d]# echo Error... > /code/err.html
[root@ops conf.d]# cat /code/err.html
Error...
[root@ops conf.d]# cat location3.ops.net.conf
server {
listen 80;
server_name location.ops.net;
root /code;
charset utf-8;
location / {
index index.html;
}
error_page 400 403 404 /err.html;
##如果出现异常,则重新定向到@error_404这个location上
# error_page 404 @error_404;
# location @error_404 {
# default_type text/html;
# return 200 '你可能是不小心走丢了。';
# }
}
将错误访问重定向到主页:
[root@ops conf.d]# cat location3.ops.net.conf
server {
listen 80;
server_name location.ops.net;
root /code;
charset utf-8;
location / {
index index.html;
}
#如果出现异常,则重新定向到@error_404这个location上
error_page 404 @error_404;
location @error_404 {
default_type text/html;
return 302 http://$server_name;
#return 302 http://location.ops.net;
}
}
浏览器访问:http://qq.com/sfafaafsafsafsafsa


浏览器访问京东:http://jd.com/fsafsasa

9 Nginx 日志模块
Nginx的日志记录非常灵活,可以通过log_format来定义格式。
9.1 Nginx日志格式
log_format定义日志格式语法
# 配置语法: 包括: error.log access.log
Syntax: log_format name [escape=default|json] string ...;
Default: log_format combined "...";
Context: http
# 默认Nginx定义语法格式如下
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format test '$remote_addr -$remote_user [$time_local] "$request" ''$status';
#access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/access_test.log test;Nginx日志格式中常用的变量
$remote_addr # 记录客户端IP地址
$remote_user # 记录客户端用户名
$time_local # 记录通用的本地时间
$time_iso8601 # 记录ISO8601标准格式下的本地时间
$request # 记录请求的方法以及请求的http协议
$status # 记录请求状态码(用于定位错误信息)
$body_bytes_sent # 发送给客户端的资源字节数,不包括响应头的大小
$bytes_sent # 发送给客户端的总字节数
$msec # 日志写入时间。单位为秒,精度是毫秒。
$http_referer # 记录从哪个页面链接访问过来的
$http_user_agent # 记录客户端浏览器相关信息
$http_x_forwarded_for #记录客户端IP地址
$request_length # 请求的长度(包括请求行,请求头和请求正文)。
$request_time # 请求花费的时间,单位为秒,精度毫秒
# 注:如果Nginx位于负载均衡器,nginx反向代理之后,web服务器无法直接获取到客户端真实的IP地址。
# $remote_addr获取的是反向代理的IP地址,反向代理服务器在转发请求的http头信息中。
# 增加X-Forwarded-For信息,用来记录客户端IP地址和客户端请求的服务器地址。[root@ops conf.d]# tail -f /var/log/nginx/
10.0.0.166 - - [26/Oct/2025:15:38:47 +0800] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" "-"
10.0.0.166 - - [26/Oct/2025:15:41:14 +0800] "GET / HTTP/1.1" 200 7 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0" "-"
范例:自定义Nginx服务日志
[root@ops conf.d]# vim /etc/nginx/nginx.conf
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format test '$remote_addr - $remote_user [$time_local] "$request" '
'$status';
#access_log /var/log/nginx/access.log main;
access_log /var/log/nginx/access_test.log test;
[root@ops ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@ops ~]# systemctl reload nginx
[root@ops conf.d]# tail -f /var/log/nginx/access_test.log
10.0.0.166 - - [26/Oct/2025:15:54:27 +0800] "GET / HTTP/1.1" 304
10.0.0.166 - - [26/Oct/2025:15:55:40 +0800] "GET / HTTP/1.1" 2009.2 Nginx访问日志
web服务器的访问日志是非常重要的,我们可以通过访问日志来分析用户的访问情况,也可以通过访问日志发现一些异常访问。access_log日志配置语法。
Syntax: access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off;
Default: access_log logs/access.log combined;
Context: http, server, location, if in location, limit_except
http {
access_log /var/log/nginx/access.log main;
server {
}
server {
access_log /var/log/nginx/test.ops.net.log main;
location / {
}
location /admin {
}
}
}Nginx 访问日志配置示例
server {
listen 80;
server_name log.ops.net;
# 将当前的server网站的访问日志记录至对应的目录,使用main格式
access_log /var/log/nginx/log.ops.net.log main;
location / {
root /code;
index index.html;
}
}# cat /etc/nginx/nginx.conf | grep err
error_log /var/log/nginx/error.log;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
# error_page 404 /404.html;
# error_page 500 502 503 504 /50x.html;
[root@rocky9 ~]# cat /etc/nginx/nginx.conf | grep acc
access_log /var/log/nginx/access.log main;[root@ops ~]# cat /code/404.html
404报错了
[root@ops ~]# cat /etc/nginx/conf.d/log.ops.net.conf
server {
listen 80;
charset utf-8;
server_name log.ops.net;
# 将当前的server网站的访问日志记录至对应的目录,使用main格式
access_log /var/log/nginx/log.ops.net.log main;
location / {
root /code;
index index.html;
error_page 404 /404.html;
}
}
9.3 Nginx错误日志
Nginx常见的错误日志级别有debug | info | notice| warn | error | crit | alert | emerg级别越高记录的信息越少,如果不定义,默认级别为warn,它可以配置在main、http、server、location段里

Nginx错误日志示例
error_log /var/log/nginx/error.log warn;
# 关闭错误日志
error_log /dev/null;9.4 Nginx日志过滤
一个网站会包含很多元素,尤其是有大量的images、js、css等静态资源,这样的请求可以不用记录日志
# wget https://www.jd.com/favicon.ico
# wget https://www.baidu.com/favicon.ico
#请求favicon.ico时,不记录日志
location /favicon.ico {
access_log off;
return 200;
}
#或,当有人访问gif、png等资源时,将日志丢入空
location ~* .*\.(gif|jpg|png|css|js)$
{
access_log /dev/null;
}[root@ops ~]# cd /code/
[root@ops code]# wget https://www.jd.com/favicon.ico
[root@ops code]# cat location.ops.net.conf
server {
listen 80;
server_name lo.ops.net;
root /code;
access_log /var/log/nginx/access.log main;
location / {
index index.html;
}
location /favicon.ico {
access_log off;
expires 3650d;
}
}
#若访问无法看到图标,注意缓存问题,按Ctrl+F5进行强刷
5、Nginx 反向代理服务
1. Nginx代理概述
1.1 什么是代理
代理代理,代为办理,对于代理一词而言,我们并不陌生,在我们日常生活中常常用到
比如代理理财、代理租房、代理收货等等

1.2 无代理场景
在没有使用代理的场景下,客户端都是直接请求服务端,服务端直接响应客户端。
比如:抖音在初创阶段时没太多人关注,单台服务器足以支撑业务运行。但随着事件推移,xx门事件的发生,引得抖音迅速蹿红,那么此时单台服务器难以支撑海量的用户请求,甚至一度造成服务瘫痪。

4.1.3 有代理场景
在使用代理的场景下,客户端无法直接向服务端发起请求,需要先请求代理服务,由代理服务代为请求后端节点,以实现客户端与后端通信。
使用代理会增加网络延迟,但能提高系统整体的响应,以此承担海量的并发请求。

2. Nginx正向代理(个人)
正向代理,(内部上网) 客户端<-->代理->服务端.

2.1 客户端科学上网
比如:科学的方式访问 Google.

2.2 客户端提速
比如:游戏加速器.

2.3 客户端缓存
比如:下载资源,可以先查看代理服务是否有,如果有直接通过代理获取.

2.4 客户端授权
很多公司为了安全,连接外网需要通过防火墙,防火墙可以配置规则,允许谁可以上外网,谁不可以上外网.

3. Nginx反向代理(企业)
反向代理,用于公司集群架构中,客户端->代理<-->服务端.

3.1 路由功能
根据用户请求的 URI 调度到【不同的功能的集群服务器】进行处理.

3.2 负载均衡
将用户发送的请求,通过负载均衡调度算法挑选一台合适的节点进行请求处理.

3.3 动静分离
根据用户请求的 URI 进行区分,将动态资源调度至应用服务器处理,将静态资源调度至静态资源服务器处理.

3.4 数据缓存
将后端查询的数据存储至反向代理上缓存,可以加速用户获取资源.

4. 正向与反向代理区别
区别在于形式上服务的"对象"不一样、其次架设的位置点不一样.
正向代理代理的对象是【客户端】,为客户端服务.反向代理代理的对象是【服务端】,为服务端服务.
user-->正向代理(路由器)--> 反向代理(缓存)--> 服务器.
5. Nginx可代理的协议
5.1 Nginx支持代理的协议
Nginx作为代理服务,支持的代理协议非常的多,如下图所示

5.2 Nginx常用的代理协议
通常情况下,我们将Nginx作为反向代理,常常会用到如下几种代理协议,如下图所示

6. Nginx反向代理实践
6.1 配置语法指令
Syntax: proxy_pass URL;
Default: —
Context: location, if in location,
limit_except
proxy_pass http://localhost:8000/uri/
http://10.0.0.7:8000/uri/6.2 代理配置场景

6.2.1 环境准备
6.2.2 web节点配置
# web01服务配置一个网站,监听在8080,此时网站仅172网段的用户能访问
[root@web01 ~]#cat /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@web01 ~]#yum install nginx -y
[root@lb01 ~]# vim /etc/nginx/conf.d/web.ops.com.conf
server {
listen 8080;
server_name web.ops.com;
location / {
root /code_8080;
index index.html;
}
}
[root@lb01 ~]# mkdir /code_8080
[root@web01 /etc/nginx/conf.d]#echo "web01-site..." > /code_8080/index.html
[root@web01 /etc/nginx/conf.d]#systemctl restart nginx
[root@lb01 ~]# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 511 0.0.0.0:8080 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:* 6.2.3 proxy节点配置
# proxy代理服务配置,让外网用户能够通过代理服务访问到后端的172.16.1.7的8080端口站点内容
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
[root@lb01 ~]#mv /etc/nginx/conf.d/default.conf /opt/
[root@lb01 ~]#vim /etc/nginx/conf.d/proxy_web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://172.16.1.7:8080;
}
}
[root@lb01 ~]#systemctl restart nginx
[root@lb01 ~]#ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:80 *:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 100 [::1]:25 [::]:*
浏览器访问:10.0.0.56.2.4 抓包分析访问过程
抓包分析Nginx代理处理整个请求的过程

6.3 代理相关配置参数
6.3.1 proxy_set_header
# 添加发往后端服务器的请求头信息,
Syntax: proxy_set_header field value;
Default: proxy_set_header Host $proxy_host;
proxy_set_header Connection close;
Context: http, server, location
# 客户端请求Host的值是www.ops.net, 那么代理服务会向后端请求时携带Host变量为www.ops.net
proxy_set_header Host $http_host;
# 将$remote_addr的值放进变量X-Real-IP中,$remote_addr的值为客户端的ip
proxy_set_header X-Real-IP $remote_addr;
#配置Nginx记录该头部到访问日志
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$http_x_real_ip"';
# 客户端通过代理服务访问后端服务,后端服务会通过该变量会记录真实客户端地址
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;X-Real-IP和X-Forwarded-For,它们都用于传递客户端的真实IP地址,但使用方式和目的有所不同
X-Real-IP:
• 这是一个非标准头部,通常由反向代理服务器设置,用于传递客户端的真实IP地址。
• 它只包含一个IP地址,即直接与反向代理服务器连接的客户端的IP地址。
• 使用简单,但只能记录一个IP地址。如果请求经过多个代理,则无法记录完整的代理链。
X-Forwarded-For:
• 这是一个标准头部,被广泛支持。
• 它包含一个IP地址列表,每个代理服务器都会将自己的客户端IP添加到这个列表中。
• 格式为:X-Forwarded-For: client, proxy1, proxy2
• 第一个IP是原始客户端IP,后续是经过的代理服务器IP。6.3.2 proxy_http_version

[root@lb01 ~]# cat /etc/nginx/conf.d/proxy_web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://192.168.80.130:80;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
[root@lb01 ~]# vim /etc/nginx/conf.d/proxy_web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://192.168.80.130:80;
proxy_http_version 1.1;
proxy_set_header Connection ""; #代理到后端时,不需要通过Connection这个字段来控制是否为长连接,只需要看协议版本即可
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

6.3.3 proxy_connect_timeout
#nginx代理与后端服务器 "连接超时" 时间(代理连接超时)
Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http, server, location6.3.4 proxy_read_timeout
#nginx代理等待后端服务器 "响应(Header)超时" 时间
Syntax: proxy_read_timeout time;
Default: proxy_read_timeout 60s;
Context: http, server, location6.3.5 proxy_send_timeout
#后端服务器 "数据(Data)回传给nginx代理超时" 时间
Syntax: proxy_send_timeout time;
Default: proxy_send_timeout 60s;
Context: http, server, location[root@lb01 ~]# cat /etc/nginx/conf.d/proxy_web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://192.168.80.130:80;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 120s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
[root@lb01 ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@lb01 ~]# systemctl reload nginx6.3.6 proxy_buffer(缓冲区)
1)启用缓冲时,nginx代理服务器将尽快的接收响应Header以及响应报文,并将其保存到proxy_buffer_size(Headers) 和proxy_buffers(data) 设置的缓冲区中。
# proxy_buffer代理缓冲区
Syntax: proxy_buffering on | off;
Default: proxy_buffering on;
Context: http, server, location如果响应报文过大无法存储至内存,则会将其中部分保存到磁盘上的临时文件中。写入临时文件由proxy_temp_path(控制临时存储目录)proxy_max_temp_file_size(控制临时存储目录大
小) 和 proxy_temp_file_write_size(控制一次写入临时文件的数据大小),临时文件最大大小由proxy_buffer_size 和 proxy_buffers 限制。但当禁用缓冲时,nginx代理服务器会在接收到响应时立即同步传递给客户端。nginx代理服务器不会读取整个响应。
2)proxy_buffer_size用于控制代理服务读取后端第一部分响应Header的缓冲区大小。
Syntax: proxy_buffer_size size;
Default: proxy_buffer_size 4k|8k;
Context: http, server, location
# proxy_buffer_size 64k;3)proxy_buffers是代理服务器为单个连接设置响应缓冲区 “数量” 和 “大小” 。
如果一个后端服务所返回的页面大小为256KB,那么会为其分配4个64KB的缓冲区来缓存,如果页面大小大于256KB,那么大于256KB的部分会缓存到proxy_temp_path 指定的路径中。但是这并不是好方法,因为内存中的数据处理速度要快于硬盘。所以这个值一般建议设置为站点响应所产生的页面大小中间值,如果站点大部分脚本所产生的页面大小为256KB,那么可以把这个值设置为 “16 16k”、“4 64k” 等。
Syntax: proxy_buffers number size;
Default: proxy_buffers 8 4k|8k;
Context: http, server, location
#proxy_buffers 4 64k;[root@lb01 ~]# cat /etc/nginx/conf.d/proxy_web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://192.168.80.130:80;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_connect_timeout 120s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_buffering on;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}6.3.7 代理参数总结
# 代理网站常用优化配置如下,将配置写入一个新文件,调用时使用include即可
[root@lb01 ~]# vim /etc/nginx/proxy_params
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
# 使用include方式,便于后续Location的重复使用。
location / {
proxy_pass http://127.0.0.1:8080;
include proxy_params;
}7. 实现 FastCGI

CGI的由来:
最早的Web服务器只能简单地响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件,但是后期随着网站功能增多网站开发也越来越复杂,以至于出现动态技术,比如像php(1995年)、java(1995)、python(1991)语言开发的网站,但是nginx/apache服务器并不能直接运行 php、java这样的文件,apache实现的方式是打补丁,但是nginx缺通过与第三方基于协议实现,即通过某种特定协议将客户端请求转发给第三方服务处理,第三方服务器会新建新的进程处理用户的请求,处理完成后返回数据给Nginx并回收进程,最后nginx在返回给客户端,那这个约定就是通用网关接口(common gateway interface,简称CGI),CGI(协议) 是web服务器和外部应用程序之间的接口标准,是cgi程序和web服务器之间传递信息的标准化接口。

7.1 为什么会有FastCGI?
CGI协议虽然解决了语言解析器和 Web Server 之间通讯的问题,但是它的效率很低,因为 Web Server每收到一个请求都会创建一个CGI进程,PHP解析器都会解析php.ini文件,初始化环境,请求结束的时候再关闭进程,对于每一个创建的CGI进程都会执行这些操作,所以效率很低,而FastCGI是用来提高CGI性能的,FastCGI每次处理完请求之后不会关闭掉进程,而是保留这个进程,使这个进程可以处理多个请求。这样的话每个请求都不用再重新创建一个进程了,大大提升了处理效率。
7.2 什么是PHP-FPM?
PHP-FPM(FastCGI Process Manager:FastCGI进程管理器)是一个实现了Fastcgi的程序,并且提供进程管理的功能。进程包括master进程和worker进程。master进程只有一个,负责监听端口,接受来自web server的请求。worker进程一般会有多个,每个进程中会嵌入一个PHP解析器,进行PHP代码的处理。
7.3 FastCGI配置指令
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html
Nginx基于模块ngx_http_fastcgi_module实现通过fastcgi协议将指定的客户端请求转发至php-fpm处理,其配置指令如下:
fastcgi_pass address;
#转发请求到后端服务器,address为后端的fastcgi server的地址,可用位置:location, if in location
#示例
fastcgi_pass localhost:9000;
fastcgi_pass unix:/tmp/fastcgi.socket; #注意:文件权限
fastcgi_index name;
#fastcgi默认的主页资源,示例:fastcgi_index index.php;
fastcgi_param parameter value [if_not_empty];
#设置传递给FastCGI服务器的参数值,可以是文本,变量或组合,可用于将Nginx的内置变量赋值给自定义key
fastcgi_param REMOTE_ADDR $remote_addr; #客户端源IP
fastcgi_param REMOTE_PORT $remote_port; #客户端源端口
fastcgi_param SERVER_ADDR $server_addr; #请求的服务器IP地址
fastcgi_param SERVER_PORT $server_port; #请求的服务器端口
fastcgi_param SERVER_NAME $server_name; #请求的server name
Nginx默认配置示例:
location ~ \.php$ {
root /scripts;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; #默认脚本路径
#fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; #此行写法不再需要上面的 root 指令
fastcgi_param HTTPS on; #如果是前端代理采用https,当前后端http服务器需要加此项,否则可能会造成页面显示不正常
include fastcgi_params; #此文件默认系统已提供,存放的相对路径为prefix/conf
}fastcgi 缓存定义指令:注意使用fastcgi缓存, 可能会导致源代码更新失败,生产慎用
fastcgi_cache_path path [levels=levels] [use_temp_path=on|off] keys_zone=name:size [inactive=time] [max_size=size] [manager_files=number] [manager_sleep=time] [manager_threshold=time] [loader_files=number] [loader_sleep=time] [loader_threshold=time] [purger=on|off] [purger_files=number] [purger_sleep=time] [purger_threshold=time];
#定义fastcgi的缓存;
path #缓存位置为磁盘上的文件系统路径
max_size=size #磁盘path路径中用于缓存数据的缓存空间上限
levels=levels: #缓存目录的层级数量,以及每一级的目录数量,levels=ONE:TWO:THREE,示例:leves=1:2:2
keys_zone=name:size #设置缓存名称及k/v映射的内存空间的名称及大小
inactive=time #缓存有效时间,默认10分钟,需要在指定时间满足fastcgi_cache_min_uses 次数被视为活动缓存缓存调用指令:
fastcgi_cache zone | off;
#调用指定的缓存空间来缓存数据,可用位置:http, server, location
fastcgi_cache_key string;
#定义用作缓存项的key的字符串,示例:fastcgi_cache_key $request_uri;
fastcgi_cache_methods GET | HEAD | POST ...;
#为哪些请求方法使用缓存
fastcgi_cache_min_uses number;
#缓存空间中的缓存项在inactive定义的非活动时间内至少要被访问到此处所指定的次数方可被认作活动项
fastcgi_keep_conn on | off;
#收到后端服务器响应后,fastcgi服务器是否关闭连接,建议启用长连接
fastcgi_cache_valid [code ...] time;
#不同的响应码各自的缓存时长
fastcgi_hide_header field; #隐藏响应头指定信息
fastcgi_pass_header field; #返回响应头指定信息,默认不会将Status、X-Accel-...返回7.4 FastCGI实战案例 : Nginx与 Php-fpm在同一服务器
php安装可以通过yum或者编译安装,使用yum安装相对比较简单,编译安装更方便自定义参数或选项。

7.4.1 php 环境准备
范例: Ubuntu 安装 PHP-FPM
#Ubuntu2204安装php-fpm
[root@ubuntu2204 ~]#apt update
[root@ubuntu2204 ~]#apt -y install php-fpm
[root@ubuntu2204 ~]#php-fpm8.1 -v
PHP 8.1.2-1ubuntu2.22 (fpm-fcgi) (built: Jul 15 2025 12:11:22)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.22, Copyright (c), by Zend Technologies
[root@ubuntu2204 ~]#systemctl status php8.1-fpm
● php8.1-fpm.service - The PHP 8.1 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php8.1-fpm.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2025-11-03 03:22:52 UTC; 18min ago
Docs: man:php-fpm8.1(8)
Process: 1022 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/8.1/fpm/pool.d/www.>
Main PID: 898 (php-fpm8.1)
Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
Tasks: 3 (limit: 4515)
Memory: 15.2M
CPU: 373ms
CGroup: /system.slice/php8.1-fpm.service
├─ 898 "php-fpm: master process (/etc/php/8.1/fpm/php-fpm.conf)" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "">
├─1020 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ">
└─1021 "php-fpm: pool www" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ">
Nov 03 03:22:41 ubuntu2204 systemd[1]: Starting The PHP 8.1 FastCGI Process Manager...
Nov 03 03:22:52 ubuntu2204 systemd[1]: Started The PHP 8.1 FastCGI Process Manager.
#Ubuntu2004安装php-fpm
[root@ubuntu2004 ~]#apt -y install php-fpm
[root@ubuntu2004 ~]#php-fpm7.4 -v
PHP 7.4.3 (fpm-fcgi) (built: Nov 2 2022 09:53:44)
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.3, Copyright (c), by Zend Technologies
[root@ubuntu2004 ~]#systemctl status php7.4-fpm.service
● php7.4-fpm.service - The PHP 7.4 FastCGI Process Manager
Loaded: loaded (/lib/systemd/system/php7.4-fpm.service; enabled; vendor preset: enabled)
Active: active (running) since Wed 2022-11-30 18:23:09 CST; 28s ago
Docs: man:php-fpm7.4(8)
Process: 19905 ExecStartPost=/usr/lib/php/php-fpm-socket-helper install /run/php/php-fpm.sock /etc/php/7.4/fpm/pool.d/www.conf >
Main PID: 19887 (php-fpm7.4)
Status: "Processes active: 0, idle: 2, Requests: 0, slow: 0, Traffic: 0req/sec"
Tasks: 3 (limit: 2236)
Memory: 7.2M
CGroup: /system.slice/php7.4-fpm.service
├─19887 php-fpm: master process (/etc/php/7.4/fpm/php-fpm.conf)
├─19903 php-fpm: pool www
└─19904 php-fpm: pool www
11月 30 18:23:09 ubuntu2004 systemd[1]: Starting The PHP 7.4 FastCGI Process Manager...
11月 30 18:23:09 ubuntu2004 systemd[1]: Started The PHP 7.4 FastCGI Process Manager.
[root@ubuntu2204 ~]#ll /run/php/php-fpm.sock
lrwxrwxrwx 1 root root 30 Nov 3 03:22 /run/php/php-fpm.sock -> /etc/alternatives/php-fpm.sock=
#如果nginx使用socket文件和PHP进行通信,需要修改nginx服务和PHP-fpm使用相同的用户,比如:www-data,否则会出现502错误
#如果nginx通过9000端口和PHP进行通信,则无需修改用户身份
[root@ubuntu2204 ~]#ll /run/php/php8.1-fpm.sock
srw-rw---- 1 www-data www-data 0 Nov 3 03:22 /run/php/php8.1-fpm.sock=
[root@ubuntu2204 ~]#ls /run/php/php-fpm.sock -l
lrwxrwxrwx 1 root root 30 Nov 3 03:22 /run/php/php-fpm.sock -> /etc/alternatives/php-fpm.sock
#默认不支持远程连接,所以无回显
[root@ubuntu2204 ~]#ss -ntl | grep 9000范例: 红帽系统使用base源自带的php版本
#yum安装默认版本php和相关APP依赖的包
[root@centos8 ~]# yum -y install php-fpm php-mysqlnd php-json #默认版本
#或者安装清华的php源
[root@centos7 ~]# yum -y install https://mirrors.tuna.tsinghua.edu.cn/remi/enterprise/remi-release-7.rpm
[root@centos8 ~]# systemctl enable --now php-fpm
[root@centos8 ~]# ps -ef | grep php-fpm
root 4925 1 0 17:13 ? 00:00:00 php-fpm: master process
(/etc/php-fpm.conf)
apache 4927 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4928 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4929 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4930 4925 0 17:13 ? 00:00:00 php-fpm: pool www
apache 4931 4925 0 17:13 ? 00:00:00 php-fpm: pool www
root 4933 3235 0 17:13 pts/0 00:00:00 grep --color=auto php-fpm7.4.2 php 相关配置优化
范例: Ubuntu
[root@ubuntu2204 ~]#vim /etc/php/8.1/fpm/php.ini
date.timezone = Asia/Shanghai
post_max_size = 100M #限制整个 POST 请求的总数据量
upload_max_filesize = 100M #仅限制单个上传文件的大小
[root@ubuntu2204 ~]#vim /etc/php/8.1/fpm/pool.d/www.conf
listen = 127.0.0.1:9000
;listen = /run/php/php8.1-fpm.sock
pm.status_path = /pm_status
ping.path = /ping
[root@ubuntu2204 ~]#systemctl restart php8.1-fpm.service范例: 红帽系统
[root@centos8 ~]# grep "^[a-Z]" /etc/php-fpm.conf
include=/etc/php-fpm.d/*.conf
pid = /run/php-fpm/php-fpm.pid
error_log = /var/log/php-fpm/error.log
daemonize = yes #是否后台启动
[root@centos8 ~]#grep -Ev '^;.*$|^ *$' /etc/php-fpm.d/www.conf
[www]
user = nginx
group = nginx
listen = /run/php-fpm/www.sock #指定使用UDS,或者使用下面形式,需要注意文件权限
;listen = 127.0.0.1:9000 #监听地址及IP
listen.acl_users = apache,nginx
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.status_path = /pm_status #修改此行
ping.path = /ping #修改此行
ping.response = ping-pong #修改此行
slowlog = /var/log/php-fpm/www-slow.log #慢日志路径
php_admin_value[error_log] = /var/log/php-fpm/www-error.log #错误日志
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files #phpsession保存方式及路径
php_value[session.save_path] = /var/lib/php/session #当时使用file保存session的文件路径
#文件最后修改下面两行
php_value[session.save_handler] = redis
php_value[session.save_path] = "tcp://redis-server:6379"
php_value[soap.wsdl_cache_dir] = /var/lib/php/wsdlcache
php_value[upload_max_filesize] = 20m
php_value[post_max_size] = 20m
php_value[date.timezone] = Asia/Shanghai
#修改配置文件后记得重启php-fpm
[root@centos8 ~]# systemctl restart php-fpm7.4.3 准备php测试页面
[root@ubuntu2204 ~]#mkdir -p /data/php
[root@ubuntu2204 ~]#vim /data/php/index.php #php测试页面
<?php
phpinfo();
?>
#测试连接数据库
[root@ubuntu2204 ~]#vim /data/php/mysql.php
<?php
$servername = "localhost";
$username = "root";
$password = "123456";
// 创建连接
$conn = mysqli_connect($servername,$username, $password);
// 检测连接
if (!$conn) {
die("php连接MySQL数据库失败: " . mysqli_connect_error());
}
echo "php连接MySQL数据库成功!";
?>
[root@ubuntu2204 ~]#apt install mysql-server -y
[root@ubuntu2204 ~]#systemctl start mysql
[root@ubuntu2204 ~]#mysql
mysql> create user root@"%" identified by '123';
Query OK, 0 rows affected (0.02 sec)
mysql> grant all on *.* to root@"%";
Query OK, 0 rows affected (0.00 sec)
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
[root@ubuntu2204 ~]#vi /etc/mysql/mysql.conf.d/mysqld.cnf
bind-address = 0.0.0.0
#mysqlx-bind-address = 127.0.0.1
[root@ubuntu2204 ~]#systemctl restart mysql
#运行测式脚本
[root@ubuntu2204 ~]#apt install php8.1-mysqli -y
[root@ubuntu2204 ~]#php /data/php/mysql.php
php连接MySQL数据库成功!7.4.4 Nginx配置转发
Nginx安装完成之后默认生成了与fastcgi的相关配置文件,一般保存在nginx的安装路径的conf目录当中
比如: /apps/nginx/conf/fastcgi.conf、/apps/nginx/conf/fastcgi_params、/etc/nginx/fastcgi_params
[root@ubuntu2204 ~]#apt install nginx -y
[root@ubuntu2204 ~]#vim /etc/nginx/conf.d/pc.conf
[root@ubuntu2204 ~]#mkdir -p /data/php
[root@ubuntu2204 ~]#vim /etc/nginx/conf.d/pc.conf
server {
listen 80;
server_name www.ops.net;
index index.php index.html;
location ~ \.php$|pm_status|ping {
root /data/php; #下面的$document_root调用此行的root指令指定的目录
#fastcgi_pass unix:/run/php-fpm/www.sock; #指定使用UDS,或者使用下面形式,需要注意文件权限
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#fastcgi_param SCRIPT_FILENAME /data/php$fastcgi_script_name;
#如果SCRIPT_FILENAME是上面的绝对路径则可以省略root /data/php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_param HTTPS $https if_not_empty; #有些应用支持https需要此项,否则会造成页面不正常
}
}
[root@ubuntu2204 ~]#nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
#重启Nginx并访问web测试
[root@ubuntu2204 ~]#systemctl restart nginx7.5.5 访问验证php测试页面
访问: http://www.ops.net/index.php 显示下面页面

#常见的错误:
File not found. #路径不对
502 #php-fpm处理超时、服务停止运行等原因导致的无法连接或请求超时7.5.6 php-fpm 的运行状态页面
访问配置文件里面指定的路径,会返回php-fpm的当前运行状态。
Nginx配置:
location ~ ^/(ping|pm_status)$ {
fastcgi_pass unix:/run/php-fpm/www.sock;
#fastcgi_pass 127.0.0.1:9000;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
include fastcgi_params;
}
#重启Nginx并测试:

[root@ubuntu2204 ~]#curl www.ops.net/ping
pong
[root@ubuntu2204 ~]#curl www.ops.net/pm_status
pool: www
process manager: dynamic
start time: 03/Nov/2025:04:42:10 +0000
start since: 88
accepted conn: 3
listen queue: 0
max listen queue: 0
listen queue len: 511
idle processes: 1
active processes: 1
total processes: 2
max active processes: 1
max children reached: 0
slow requests: 0
[root@ubuntu2204 ~]#curl www.ops.net/pm_status?full
[root@ubuntu2204 ~]#curl www.ops.net/pm_status?html
[root@ubuntu2204 ~]#curl www.ops.net/pm_status?json7.5.7 配置 php 开启 opcache 加速(默认已开启)
[root@ubuntu2204 ~]#dpkg -L php8.1-opcache
/.
/etc
/etc/php
/etc/php/8.1
/etc/php/8.1/mods-available
[root@ubuntu2204 ~]#cat /etc/php/8.1/mods-available/opcache.ini
; configuration for php opcache module
; priority=10
zend_extension=opcache.so
[root@web01 ~]# yum -y install httpd-tools
#压测
[root@web01 ~]# ab -c 100 -n 1000 http://www.ops.net/index.php7.5 FastCGI实战案例 : Nginx与php不在同一个服务器

7.5.1 yum安装较新版本php-fpm
[root@rocky9 ~]# dnf -y install php-fpm php-mysqlnd php-json php
[root@rocky9 ~]# php -v
PHP 8.0.30 (cli) (built: May 16 2025 04:22:34) ( NTS gcc x86_64 )
Copyright (c) The PHP Group
Zend Engine v4.0.30, Copyright (c) Zend Technologies
with Zend OPcache v8.0.30, Copyright (c), by Zend Technologies
#验证安装路径:
[root@rocky9 ~]# php-fpm -v
PHP 8.0.30 (fpm-fcgi) (built: May 16 2025 04:22:34)
Copyright (c) The PHP Group
Zend Engine v4.0.30, Copyright (c) Zend Technologies
[root@rocky9 ~]# rpm -ql php-fpm
/etc/httpd/conf.d/php.conf
/etc/logrotate.d/php-fpm
/etc/nginx/conf.d/php-fpm.conf
/etc/nginx/default.d/php.conf
/etc/php-fpm.conf
/etc/php-fpm.d
/etc/php-fpm.d/www.conf
/etc/systemd/system/php-fpm.service.d
/run/php-fpm
/usr/lib/.build-id
/usr/lib/.build-id/f5
/usr/lib/.build-id/f5/7e3528401da695c3ef396427bfedca66e365df
/usr/lib/systemd/system/httpd.service.d/php-fpm.conf
/usr/lib/systemd/system/nginx.service.d/php-fpm.conf
/usr/lib/systemd/system/php-fpm.service
/usr/sbin/php-fpm
/usr/share/doc/php-fpm
/usr/share/doc/php-fpm/php-fpm.conf.default
/usr/share/doc/php-fpm/www.conf.default
/usr/share/fpm
/usr/share/fpm/status.html
/usr/share/licenses/php-fpm
/usr/share/licenses/php-fpm/fpm_LICENSE
/usr/share/man/man8/php-fpm.8.gz
/var/lib/php/opcache
/var/lib/php/session
/var/lib/php/wsdlcache
/var/log/php-fpm7.5.2 修改php-fpm监听配置
php-fpm默认监听在127.0.0.1的9000端口,也就是无法远程连接,因此要做相应的修改。
;listen = /run/php-fpm/www.sock #注释此行
listen = 9000 #修改此行,指定监听端口
;listen.allowed_clients = 127.0.0.1 #注释此行7.5.3 准备php测试页面
#准备php数据目录
[root@rocky9 ~]# mkdir -p /data/php
#准备php数据目录
[root@rocky9 ~]# vi /data/php/index.php
<?php
phpinfo();
?>
#测试连接数据库
[root@rocky9 ~]# vi /data/php/mysql.php
<?php
$servername = "10.0.0.90";
$username = "root";
$password = "123";
// 创建连接
$conn = mysqli_connect($servername,$username, $password);
// 检测连接
if (!$conn) {
die("php连接MySQL数据库失败: " . mysqli_connect_error());
}
echo "php连接MySQL数据库成功!";
?>
#运行测式脚本
[root@rocky9 ~]# php /data/php/mysql.php
php连接MySQL数据库成功!7.5.4 启动并验证php-fpm
#启动php-fpm
[root@rocky9 ~]# systemctl enable --now php-fpm.service
#验证php-fpm进程及端口:
[root@rocky9 ~]# ps -ef | grep php-fpm
root 11835 1 0 13:35 ? 00:00:00 php-fpm: master process (/etc/php-fpm.conf)
apache 11836 11835 0 13:35 ? 00:00:00 php-fpm: pool www
apache 11837 11835 0 13:35 ? 00:00:00 php-fpm: pool www
apache 11838 11835 0 13:35 ? 00:00:00 php-fpm: pool www
apache 11839 11835 0 13:35 ? 00:00:00 php-fpm: pool www
apache 11840 11835 0 13:35 ? 00:00:00 php-fpm: pool www
root 11842 11458 0 13:35 pts/0 00:00:00 grep --color=auto php-fpm
[root@rocky9 ~]# ss -ntl | grep 9000
LISTEN 0 511 *:9000 *:*
[root@rocky9 ~]# dnf -y install lsof
[root@rocky9 ~]# lsof -i :9000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
php-fpm 11835 root 8u IPv6 39291 0t0 TCP *:cslistener (LISTEN)
php-fpm 11836 apache 10u IPv6 39291 0t0 TCP *:cslistener (LISTEN)
php-fpm 11837 apache 10u IPv6 39291 0t0 TCP *:cslistener (LISTEN)
php-fpm 11838 apache 10u IPv6 39291 0t0 TCP *:cslistener (LISTEN)
php-fpm 11839 apache 10u IPv6 39291 0t0 TCP *:cslistener (LISTEN)
php-fpm 11840 apache 10u IPv6 39291 0t0 TCP *:cslistener (LISTEN)
7.5.5 Nginx配置转发
[root@ubuntu2204 ~]#vi /etc/nginx/conf.d/pc.conf
server {
listen 80;
server_name www.ops.net;
index index.php index.html;
location ~ \.php$ {
root /data/php;
fastcgi_pass 10.0.0.9:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/php$fastcgi_script_name;
#fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ ^/(ping|pm_status)$ {
fastcgi_pass 10.0.0.9:9000;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
#重启nginx
[root@ubuntu2204 ~]#systemctl restart nginx[root@ubuntu2204 ~]#php -v
PHP 8.1.2-1ubuntu2.22 (cli) (built: Jul 15 2025 12:11:22) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.1.2, Copyright (c) Zend Technologies
with Zend OPcache v8.1.2-1ubuntu2.22, Copyright (c), by Zend Technologies
[root@rocky9 ~]# php -v
PHP 8.0.30 (cli) (built: May 16 2025 04:22:34) ( NTS gcc x86_64 )
Copyright (c) The PHP Group
Zend Engine v4.0.30, Copyright (c) Zend Technologies
with Zend OPcache v8.0.30, Copyright (c), by Zend Technologies7.5.6 访问验证php测试页面

6、Nginx七层负载均衡
1. Nginx负载均衡基本概述
1.1 什么是负载均衡
负载均衡 Load Balance,指的是将用户访问请求所产生的流量,进行平衡,分摊到多个应用节点处理。
负载均衡扩展了应用的服务能力,增强了应用的可用性。
SLB;
CLB;
ULB;
1.2 为什么需要负载均衡
当我们的 Web服务器直接面向用户,往往要承载大量并发请求,单台服务器难以负荷,我使用多台 WEB 服务器组成集群,前端使用 Nginx 负载均衡,将请求分散的打到我们的后端服务器集群中,实现负载的流量分发。从而提升整体性能、以及系统的容灾能力。

1.3 负载均衡与代理区别
Nginx负载均衡与Nginx反向代理不同地方在于:
Nginx代理仅代理一台服务器基于URI来调度,调度到不同功能的应用节点处理。Nginx负载均衡则是将客户端请求通过proxy_pass代理至一组upstream资源池。
2. Nginx负载均衡应用场景
2.1 四层负载均衡
四层负载均衡指的是 OSI 七层模型中的传输层,四层仅需要对客户端的请求进行TCP/IP协议的包代理就可以实现负载均衡。IP+Port
四层负载均衡的性能极好、因为只需要底层进行转发处理,而不需要进行一些复杂的逻辑。

2.2 七层负载均衡
七层负载均衡工作在应用层,它可以完成很多应用方面的协议请求,比如我们说的 http 应用负载均衡,它可以实现 http 头信息的改写、安全应用规则控制、URI 匹配规则控制、及 rewrite 等功能,所以在应用层里面可以做的内容就更多了。

2.3 四层与七层区别
四层负载均衡:传输层
优点:性能高,数据包在底层就进行了转发
缺点:仅支持
ip:prot转发,无法完成复杂的业务逻辑应用。MySQL TCP 3306,Redis、SSH、等;
七层负载均衡:应用层
优点:贴近业务,支持
URI路径匹配、Header改写、Rewrite等缺点:性能低,数据包需要拆解到顶层才进行调度,消耗随机端口;
3. Nginx负载均衡配置场景
Nginx 实现负载均衡需要两个模块:
proxy_pass代理模块proxy_modulesupstream虚拟资源池模块proxy_upstream_module
Syntax: upstream name { ... }
Default: -
Context: http
#upstream例
upstream backend {
server backend1.example.com weight=5;
server backend2.example.com:8080;
server unix:/tmp/backend3;
server backup1.example.com:8080 backup;
}
server {
location / {
proxy_pass http://backend;
}
}3.1 负载均衡场景环境规划
负载均衡场景架构图规划

负载均衡场景地址规划
3.2 后端Web节点配置实例
Web01服务器上配置为应用服务节点, 创建对应html文件
[root@web01 ~]# vim /etc/nginx/conf.d/web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
root /web;
location / {
index index.html;
}
}
[root@web01 conf.d]# mkdir /web
[root@web01 conf.d]# echo "Web01..." > /web/index.html
[root@web01 conf.d]# systemctl restart nginxWeb02 服务器上配置为应用服务节点, 创建对应
html文件
[root@web02 ~]# vim /etc/nginx/conf.d/web.ops.com.conf
server {
listen 80;
server_name web.ops.com;
root /web;
location / {
index index.html;
}
}
[root@web02 conf.d]# mkdir /web
[root@web02 conf.d]# echo "Web02..." > /web/index.html
[root@web02 conf.d]# systemctl restart nginx3.3 前端接入Nginx负载均衡
将
lb01配置为负载均衡,将所有请求代理至虚拟资源池
[root@lb01 ~]# vim /etc/nginx/conf.d/proxy_web.ops.com.conf
upstream web {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://web;
include proxy_params;
}
}
[root@lb01 conf.d]# systemctl restart nginx2.准备 Nginx 负载均衡需要使用的 proxy_params 文件
[root@Nginx ~]# vim /etc/nginx/proxy_params
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 64k;
proxy_buffers 4 64k;3.4 浏览器访问测试负载效果
使用浏览器访问 web.ops.com,然后进行刷新测试

4. Nginx负载均衡调度算法
4.1 轮询调度算法
轮询调度算法的原理是将每一次用户的请求,轮流分配给内部中的服务器。
轮询算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。
upstream load_pass {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}4.2 加权轮询调度算法
轮询调度算法没有考虑每台服务器的处理能力,在实际情况中,由于每台服务器的配置、安装的业务应用等不同,其处理能力会不一样。所以,我们根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。
upstream load_pass {
server 172.16.1.7:80 weight=5;
server 172.16.1.8:80 weight=1;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}4.3 ip_hash调度算法
ip_hash 是基于用户请求的IP,对该 IP 进行 hash 运算,根据 hash运算的值,将请求分配到后端特定的一台节点进行处理。ip_hash 算法实现公式:hash(ip) % node_counts = index

如何配置 ip_hash 调度算法
upstream load_pass {
ip_hash;
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}ip_hash调度算法会带来两个问题
1.如果有大量来自于同一IP的请求会造成某个后端节点流量过大,而其他节点无流量
2.如果临时下线一台节点,会出现重新计算 hash值,官方建议将下线节点标记为 down 状态,以保留客户端IP地址的当前哈希值。(如下图所示)
如果有大量的用户调度到某一节点,而该节点刚好故障,则该算法会重新计算结果,从而造成大量的用户被转移其他节点处理,而需要重新建立会话。
4.4 一致性hash调度算法
为了规避上述hash情况,一致性hash算法就诞生,一致性Hash算法也是使用取模的方法,但不是对服务器节
点数量进行取模,而是对2的32方取模。即,一致性Hash算法将整个Hash空间组织成一个虚拟的圆环,Hash函数值的空间为0 ~ 2^32 - 1,整个哈希环如下:
Hash算法原理
Hash算法增加节点
Hash算法减少节点
Hash算法数据倾斜问题
4.5 url_hash调度算法
根据用户请求的 URL 进行 hash 取模,根据 hash运算的值,将请求分配到后端特定的一台节点进行处理。URL 算法使用场景如下:client-->nginx-->url_hash-->cache1-->app
1.用户请求
nginx负载均衡器,通过url调度算法,将请求调度至Cache1;2.由于
Cache1节点没有对应的缓存数据,则会请求后端获取,然后返回数据,并将数据缓存起来;3.当其他用户再次请求此前相同的
URL时,此时调度器依然会调度至Cache1节点处理;4.由于
Cache1节点已存在该URL资源缓存,所以直接将缓存数据进行返回;能大幅提升网站的响应;
1.配置后端节点
# web1节点
[root@web01 ~]# echo "web1 Url1" > /web/url1.html
[root@web01 ~]# echo "web1 Url2" > /web/url2.html
# web2节点
[root@web02 ~]# echo "web2 Url1" > /web/url1.html
[root@web02 ~]# echo "web2 Url2" > /web/url2.html2.负载均衡配置 url_hash 调度算法
upstream load_pass {
# 请求同一个url,会始终定向到同一个服务器节点,consistent表示使用一致性hash算法
hash $request_uri consistent;
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}3.Client测试,会发现请求相同的URL,始终会被定向至某特定后端节点。
[root@client ~]# curl -HHost:web.ops.com http://10.0.0.5/url1.html
web2 Url1
[root@client ~]# curl -HHost:web.ops.com http://10.0.0.5/url1.html
web2 Url1
[root@client ~]# curl -HHost:web.ops.com http://10.0.0.5/url1.html
web2 Url14.6 least_conn调度算法
least_conn调度算法实现原理,哪台节点连接数少,则将请求调度至哪台节点。
假设:A节点有1000个连接 、b节点有500连接,如果此时新的连接进入会分发给b节点
upstream load_pass {
least_conn;
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}5. Nginx负载均衡后端状态
后端 Web 节点在前端 Nginx 负载均衡调度中的状态
5.1 max_conns限制连接数
max_conns 用来限制每个后端节点能够接收的最大TCP连接数,如果超过此连接则会抛出错误。
[root@lb01 ~]# cat proxy_web.ops.com.conf
upstream load_pass {
server 172.16.1.7:80 max_conns=2;
server 172.16.1.8:80 max_conns=2;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}-n 总请求数
-c 并发用户数
[root@client ~]# ab -n 5000 -c 200 http://web.ops.com/ > results.txtThis is ApacheBench, Version 2.3 <$Revision: 1913912 $> # 这是ApacheBench压力测试工具版本2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ # 版权信息
Licensed to The Apache Software Foundation, http://www.apache.org/ # 授权给Apache软件基金会
Benchmarking web.ops.com (be patient) # 正在对web.ops.com进行基准测试(请耐心等待)
Server Software: nginx/1.28.0 # 服务器软件:nginx版本1.28.0
Server Hostname: web.ops.com # 服务器主机名:web.ops.com
Server Port: 80 # 服务器端口:80
Document Path: / # 测试的文档路径:网站根目录
Document Length: 9 bytes # 文档长度:9字节(很短,可能是错误页面)
Concurrency Level: 200 # 并发级别:200个并发用户
Time taken for tests: 0.800 seconds # 测试总耗时:0.8秒
Complete requests: 5000 # 完成的请求总数:5000个
Failed requests: 2846 # 失败的请求数:2846个
(Connect: 0, Receive: 0, Length: 2846, Exceptions: 0) # 失败类型细分:连接失败0个,接收失败0个,长度不一致2846个,异常0个
Non-2xx responses: 2846 # 非2xx状态码的响应:2846个(非成功响应)
Total transferred: 1392066 bytes # 总传输数据量:1,392,066字节
HTML transferred: 466208 bytes # HTML内容传输量:466,208字节
Requests per second: 6250.32 [#/sec] (mean) # 每秒请求数:6,250.32个/秒(平均值)
Time per request: 31.998 [ms] (mean) # 每个请求时间:31.998毫秒(从用户角度)
Time per request: 0.160 [ms] (mean, across all concurrent requests) # 每个请求时间:0.16毫秒(从服务器角度,考虑并发)
Transfer rate: 1699.39 [Kbytes/sec] received # 传输速率:1,699.39 KB/秒
Connection Times (ms) # 连接时间统计(单位:毫秒)
min mean[+/-sd] median max # 统计项:最小值 平均值[±标准差] 中位数 最大值
Connect: 0 6 5.1 7 22 # 连接时间:最小0ms,平均6ms±5.1ms,中位7ms,最大22ms
Processing: 8 25 14.9 22 217 # 处理时间:最小8ms,平均25ms±14.9ms,中位22ms,最大217ms
Waiting: 1 23 15.4 20 214 # 等待时间:最小1ms,平均23ms±15.4ms,中位20ms,最大214ms
Total: 16 31 14.0 30 227 # 总时间:最小16ms,平均31ms±14.0ms,中位30ms,最大227ms
Percentage of the requests served within a certain time (ms) # 请求在不同时间内的完成百分比分布
50% 30 # 50%的请求在30毫秒内完成
66% 33 # 66%的请求在33毫秒内完成
75% 36 # 75%的请求在36毫秒内完成
80% 37 # 80%的请求在37毫秒内完成
90% 40 # 90%的请求在40毫秒内完成
95% 42 # 95%的请求在42毫秒内完成
98% 56 # 98%的请求在56毫秒内完成
99% 64 # 99%的请求在64毫秒内完成
100% 227 (longest request) # 100%的请求在227毫秒内完成(最慢请求)
通过 jmeter 压力测试发现,当后端节点处理的连接数非常多的时候,当大于4个连接,其余的连接则会抛出异常,也就是每次仅能满足4个连接。
5.2 down标识关闭状态
down 将服务器标记为不可用状态。
[root@lb01 ~]# cat proxy_web.ops.com.conf
upstream load_pass {
server 172.16.1.7:80 down; #一般用于停机维护
server 172.16.1.8:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}5.3 backup标识备份状态
backup 将服务器标记为备份服务器。当主服务器不可用时,将请求传递至备份服务器处理。
[root@lb01 ~]# cat proxy_web.ops.com.conf
upstream load_pass {
server 172.16.1.7:80 backup;
server 172.16.1.8:80;
server 172.16.1.9:80;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}5.4 max_fails与fail_timeout
max_fails=2 服务器通信失败尝试2次,仍然失败,认为服务器不可用;
fail_timeout=5s 服务器通信失败后,每5s探测一次节点是否恢复可用;
在 fail_timeout设定的时间内,与服务器连接失败达到 max_fails 则认为服务器不可用;
[root@lb01 ~]# cat proxy_web.ops.com.conf
upstream load_pass {
server 172.16.1.7:80 max_fails=2 fail_timeout=5s;
server 172.16.1.8:80 max_fails=2 fail_timeout=5s;
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://load_pass;
include proxy_params;
}轮询(Load Balancing):分配请求流量,决定"哪个服务器"处理请求
探测(健康检查):检查服务器健康状态,决定"哪些服务器可用"
5.5 keepalive提升吞吐量
keepalive 主要是与后端服务器激活缓存,也就是长连接,主要用来提升网站吞吐量。
默认情况下:没有与后端服务启用长连接功能,当有请求时,需要建立连接、维护连接、关闭连接,所以会存在网络消耗,但如果将所有的连接都缓存了,当连接空闲了又会占用其系统资源,所以可以使用 keepalive 参数来激活缓存,同时还可以使用 keepalive 参数来限制最大的空闲连接数;
upstream http_backend {
server 127.0.0.1:8080;
keepalive 16;
}
server {
...
location /http/ {
proxy_pass http://http_backend;
proxy_http_version 1.1;
proxy_set_header Connection "";
...
}
}没有启用 keepalive 参数前,对集群进行压力测试

配置 Nginx 负载均衡启用 keepalive 参数:
[root@lb01 ~]# cat proxy_web.ops.com.conf
upstream web {
server 172.16.1.7:80;
server 172.16.1.8:80;
keepalive 16; #最大的空闲连接数
keepalive_timeout 100s; #空闲连接的超时时间
}
server {
listen 80;
server_name web.ops.com;
location / {
proxy_pass http://web;
proxy_http_version 1.1;
proxy_set_header Connection "";
}
}[root@lb01 /opt]# ab -n 5000 -c 200 http://web.ops.com/ > results2.txt
This is ApacheBench, Version 2.3 <$Revision: 1913912 $> # 这是ApacheBench压力测试工具版本2.3
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ # 版权信息
Licensed to The Apache Software Foundation, http://www.apache.org/ # 授权给Apache软件基金会
Benchmarking web.ops.com (be patient) # 正在对web.ops.com进行基准测试(请耐心等待)
Server Software: nginx/1.28.0 # 服务器软件:nginx版本1.28.0
Server Hostname: web.ops.com # 服务器主机名:web.ops.com
Server Port: 80 # 服务器端口:80
Document Path: / # 测试的文档路径:网站根目录
Document Length: 9 bytes # 文档长度:9字节(返回内容很短)
Concurrency Level: 200 # 并发级别:200个并发用户
Time taken for tests: 1.701 seconds # 测试总耗时:1.701秒
Complete requests: 5000 # 完成的请求总数:5000个
Failed requests: 0 # 失败的请求数:0个(完美!)
Total transferred: 1190000 bytes # 总传输数据量:1,190,000字节
HTML transferred: 45000 bytes # HTML内容传输量:45,000字节
Requests per second: 2939.37 [#/sec] (mean) # 每秒请求数:2,939.37个/秒(平均值)
Time per request: 68.042 [ms] (mean) # 每个请求时间:68.042毫秒(从用户角度)
Time per request: 0.340 [ms] (mean, across all concurrent requests) # 每个请求时间:0.340毫秒(从服务器角度,考虑并发)
Transfer rate: 683.17 [Kbytes/sec] received # 传输速率:683.17 KB/秒(接收的数据量)
Connection Times (ms) # 连接时间统计(单位:毫秒)
min mean[+/-sd] median max # 统计项:最小值 平均值[±标准差] 中位数 最大值
Connect: 0 6 8.5 2 39 # 连接时间:最小0ms,平均6ms±8.5ms,中位2ms,最大39ms
Processing: 7 61 26.1 61 125 # 处理时间:最小7ms,平均61ms±26.1ms,中位61ms,最大125ms
Waiting: 1 57 24.3 60 115 # 等待时间:最小1ms,平均57ms±24.3ms,中位60ms,最大115ms
Total: 13 67 21.5 66 125 # 总时间:最小13ms,平均67ms±21.5ms,中位66ms,最大125ms
Percentage of the requests served within a certain time (ms) # 请求在不同时间内的完成百分比分布
50% 66 # 50%的请求在66毫秒内完成
66% 76 # 66%的请求在76毫秒内完成
75% 82 # 75%的请求在82毫秒内完成
80% 86 # 80%的请求在86毫秒内完成
90% 95 # 90%的请求在95毫秒内完成
95% 102 # 95%的请求在102毫秒内完成
98% 107 # 98%的请求在107毫秒内完成
99% 111 # 99%的请求在111毫秒内完成
100% 125 # 100%的请求在125毫秒内完成(最慢请求)对启用 keepalive 参数后的集群进行压力测试,发现整体性能提升了一倍。

7、Nginx动静分离实战
1. 动静分离基本介绍
1.1 什么是动静分离
简单来说就是将动态请求和静态请求分开处理。
1.2 为何需要动静分离
⾸先Tomcat应⽤服务器在处理静态资源时效率不高,但默认情况下⽆论 “动态、静态“ 资源都是由
tomcat处理,而Tomcat在处理静态资源时需要进行逻辑运算,从而会导致应⽤响应慢,并且会占⽤不必要的系统资源。那么借助Nginx实现动态资源请求和静态资源请求分离后,可以减少系统不必要的消耗和延时。以便加快系统的处理性能。
1.3 如何实现动静分离
Nginx通过⽤户请求的 uri 来区分请求的类型,并转发给不同的服务端。
如果请求的uri包含 png、jpg 等资源则由 Nginx 处理;
如果请求的 uri 包含 php、jsp 等资源则代理⾄Tomcat 处理;

2. 单机动静分离实践
单机实现动静分离nginx + Tomcat
2.1 Tomcat配置
[root@web01 ~]# yum install java wget -y
[root@web01 ~]# wget https://mirrors.bfsu.edu.cn/apache/tomcat/tomcat-9/v9.0.111/bin/apache-tomcat-9.0.111.tar.gz
[root@web01 ~]# mkdir /app
[root@web01 ~]# tar xf apache-tomcat-9.0.111.tar.gz -C /app/
[root@web01 ~]# ln -s /app/apache-tomcat-9.0.111/ /app/tomcat
[root@web01 ~]# /app/tomcat/bin/startup.sh2.2 Nginx配置
# 配置动静分离
[root@lb01 ~]# cat /etc/nginx/conf.d/ds.ops.net.conf
server {
listen 80;
server_name java.ops.net;
#处理动态请求
location / {
proxy_pass http://10.0.0.7:8080;
include proxy_params;
}
#如果匹配到.png .jpg这样的后缀,则让其通过Nginx读取本地/code/images下的资源文件
location ~* \.(png|jpg)$ {
root /code/images;
expires 30d;
}
}

3. 集群动静分离实践
通过nginx负载均衡将动态请求和静态请求进行分离,基于⽤户请求URI实现路由功能;
3.1 环境准备
3.3 配置动态节点
# 在10.0.0.7服务器上配置动态资源
[root@web01 ~]# /app/tomcat/bin/shutdown.sh
[root@web01 ~]# rm -rf /app/tomcat/webapps/ROOT/*
# 编写java配置
[root@web01 /app/tomcat/webapps/ROOT]# vim index.jsp
<%@ page language="java" import="java.util.*"
pageEncoding="utf-8"%>
<html>
<head>
<title>Nginx+Tomcat动静分离</title>
</head>
<body>
<%
Random rand = new Random();
out.println("<h2>动态资源</h2>");
out.println(rand.nextInt(99)+100);
%>
<h2>静态图片</h2>
<img src="nginx.png" />
</body>
</html>
[root@web01 /app/tomcat/webapps/ROOT]# ls
index.jsp
[root@web01 ~]# /app/tomcat/bin/startup.sh3.2 配置静态节点
# 在10.0.0.8服务器上配置静态资源
[root@web02 /etc/nginx/conf.d]# ls
ds.ops.net.conf
[root@web02 /etc/nginx/conf.d]# vim ds.ops.net.conf
server {
listen 80;
server_name ds.ops.net;
root /code/images;
location / {
index index.html;
}
}
# 准备目录, 以及静态相关图⽚
[root@web02 ~]# mkdir /code/images -p
[root@web02 ~]# wget -O /code/images/nginx.png http://nginx.org/nginx.png
[root@web02 ~]# systemctl reload nginx3.4 配置负载均衡
# 负载均衡10.0.0.5上配置调度,根据不同的url调度到不同的服务器
[root@lb01 /etc/nginx/conf.d]# cat proxy_web.ops.com.conf
upstream java {
server 10.0.0.19:8080;
}
upstream static {
server 10.0.0.29:80;
}
server {
listen 80;
server_name ds.ops.net;
location / {
proxy_pass http://java;
include proxy_params;
}
location ~* .*\.(png|gif)$ {
proxy_pass http://static;
}
}
[root@lb01 conf.d]# systemctl restart nginx3.5 测试集群动静分离
测试效果动静分离效果

模拟静态资源集群故障。动态内容依旧能正常访问, 静态内容则不会被请求到。

4. Uwsgi代理基本概述
4.1 什么是wsgi
WSGI,全称Web Server Gateway Interface是为Python语⾔定义的Web服务器 和Web应⽤程序之间的⼀种简单通⽤的接⼝。WSGI的官⽅定义,the Python Web Server GatewayInterface。从名字就可以看出来,这是⼀个Gateway⽹关。那么⽹关的作⽤就是在协议之间进行转换。也就是说,
WSGI就像是⼀座桥梁,⼀边连着web服务器,另⼀边连着web应⽤程序。

4.2 什么是uWSGI
uWSGI实现了WSGI、http等数据交换协议。简单来说:我们将项目通过uwsgi⽅式运行,就可以直接对外提供服务,而⽆需依托于Nginx。Uwsgi传送⻔

4.3 uWSGI结合nginx
通常情况下
Python中的Django框架或Flask框架可以通过Uwsgi⽅式对外提供服务。为什么还需要Nginx1.安全:后端服务直接以
http对外提供访问,往往会暴露后端的真实服务,如果使⽤nginx可以隐藏后端的服务,并且nginx能够实现安全限制、Rewrite、HTTPS等功能(这些都是uwsgi⽆法实现的。)2.效率:
nginx可以直接处理静态资源,然后将动态内容通过uWSGI协议转发给后端Django,实现动静分离,提供更好的请求与响应。

5. Uwsgi代理配置场景
步骤⼀、安装
python3的环境步骤⼆、安装
Django框架以及uwsgi步骤三、配置
Django⼯程步骤四、配置
uWSGI、配置Nginx
5.1 安装Python3
[root@web01 ~]# yum install openssl-devel bzip2-devel expat-devel gdbm-devel readline-devel sqlite-devel gcc gcc-c++ openssl-devel zlib zlib-devel python3 python3-devel -y5.2 安装Django
# 安装Django框架和uwsgi
[root@web01 ~]# pip3 install -i https://mirrors.aliyun.com/pypi/simple/ --upgrade pip
[root@web01 ~]# pip3 install -i https://mirrors.aliyun.com/pypi/simple/ django==2.1.8
[root@web01 ~]# pip3 install -i https://mirrors.aliyun.com/pypi/simple/ uwsgi5.3 创建Django项目
# 使⽤Django新建⼯程,运行如下指令
[root@web02 ~]# cd /opt
[root@web02 opt]# django-admin.py startproject demosite
[root@web01 opt]# cd demosite
[root@web01 demosite]# python3 manage.py runserver 0.0.0.0:80025.4 访问Django项目
在浏览器内输入http://IP:8002 正常会提示The install worked successfully! Congratulations!
如果出现ALLOWED_HOSTS报错,修改如下配置即可;

[root@web01 demosite]# vim demosite/settings.py
ALLOWED_HOSTS = ['*']再次访问

5.5 配置Uwsgi运行项目
# 配置Django⼯程以由uwsgi⽅式运行
[root@web01 ~]# vim /opt/demosite/uwsgi.ini
[uwsgi]
#uwsgi监听的端⼝
socket = 127.0.0.1:9999
#uwsgi启动进程数
workers = 2
#最⼤接收的请求数
max-requests = 1000
#buffer缓冲区⼤⼩
buffer-size = 30000
#进程pid存放路径
pidfile = /run/uwsgi.pid
#uwsgi⽇志存储路径
daemonize = /var/log/uwsgi.log5.6 配置Nginx代理Uwsgi
# 通过uwsgi⽅式启动django项目,默认监听127.0.0.1
[root@web01 ~]# uwsgi --ini /opt/demosite/uwsgi.ini
[root@web01 ~]# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.1:9999 0.0.0.0:* LISTEN 23121/uwsgi
# 配置Nginx,使⽤Nginx代理uwsgi应⽤
[root@web01 ~]# cat /etc/nginx/conf.d/py.conf
server {
listen 80;
server_name py.ops.net;
client_max_body_size 100M;
location / {
index index.html; #默认返回⻚⾯
uwsgi_pass 127.0.0.1:9999;
uwsgi_param UWSGI_CHDIR /opt/demosite; #⼯程所在的路径
uwsgi_param UWSGI_SCRIPT demosite.wsgi; #demosite/wsgi接⼝文件
include uwsgi_params;
}
}5.7 浏览器访问测试

6. Uwsgi代理项目实践
使⽤NginxUWSGI代理⽅式部署Python的Django项目
6.1 下载Django博客系统
#1.下载博客系统项目并解压
[root@web01 ~]# mkdir -p /code && cd /code
[root@bgx code]# unzip pythonav.zip
#2.安装该项目所需的依赖包软件
[root@web01 ~]# pip3 install -i https://pypi.doubanio.com/simple/ -r /code/pythonav/requirements.txt6.2 导入Django项目数据库
#1.安装mariadb
[root@web01 ~]# yum install mariadb mariadb-server -y
[root@web01 ~]# systemctl start mariadb
[root@web01 ~]# mysql
MariaDB [(none)]> create database pythonav;
MariaDB [(none)]> exit
#2.配置项目连接数据库信息
[root@web01 pythonav]# vim /code/pythonav/pythonav/settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'pythonav',
'HOST': "127.0.0.1",
'USER': 'root',
'PASSWORD': '',
'PORT': 3306,
}
}
#3.初始化数据库
[root@web01 pythonav]# python3 manage.py makemigrations
[root@web01 pythonav]# python3 manage.py migrate
#4.创建超级管理员⽤户
[root@web02 pythonav]# python3 manage.py createsuperuser
Username (leave blank to use 'root'): ops
Email address: 12345678@qq.com
Password: #输入密码ops.net
Password (again): #确认密码ops.net
Superuser created successfully.6.3 收集Django静态文件
# 收集静态资源⾄指定位置存储
[root@web01 pythonav]# python3 manage.py collectstatic6.4 配置Uwsgi运行项目
# 配置Uwsgi启动Django项目
[root@web01 pythonav]# cat pythonav_uwsgi.ini
[uwsgi]
#uwsgi监听的端⼝
socket = 127.0.0.1:8811
#指定项目所在路径
chdir = /code/pythonav/
#指定项目入⼝文件
wsgi-file = pythonav/wsgi.py
#uwsgi启动的进程数量与线程数量
processes = 4
threads = 10
#最⼤接收的请求数
max-requests = 1000
#buffer缓冲区⼤⼩
buffer-size = 30000
#进程pid存放路径
pidfile = /run/uwsgi-pythonav.pid
#uwsgi⽇志存储路径
daemonize = /var/log/uwsgi-pythonav.log
#启动uwsgi
[root@web01 ~]# uwsgi --ini /code/pythonav/pythonav_uwsgi.ini6.5 配置Nginx代理Uwsgi
# 配置Nginx Uwsgi反向代理
[root@web02 pythonav]# cat /etc/nginx/conf.d/pythonav.ops.net.conf
server {
listen 80;
server_name pythonav.ops.net;
client_max_body_size 100M;
location /static {
alias /code/pythonav/static;
}
location / {
uwsgi_pass 127.0.0.1:8811;
include uwsgi_params;
}
}6.6 浏览器访问博客项目
Django_CRM: 基于Django的学生信息管理系统,基于腾讯云短信和Redis的注册、登录、学生批量导入、批量删除、学校通知公告、班级管理、权限管理、角色分配、增删改查等要素管理。
DBlog: Django 博客系统,一款基于 python3 + django3 + mysql8 + redis + uwsgi + nginx 搭建的入门级多主题博客系统
8、Nginx七层负载均衡
1. Nginx负载均衡会话共享
1.1 什么是会话保持
当用户登陆一个网站服务器,网站服务器会将用户的登陆信息存储下来(存储下来的内容叫 Session )以保证我们能够一直处于 ”登陆在线“ 状态。
客户端:cookies
服务端:sessionID
1.2 为什么需要会话保持
由于我们使用的是负载均衡轮询机制,会导致用户请求分散在不同的节点,从而造成会话无法保持。
假设用户A,通过负载均衡登陆了网站,此时会话信息存储在A节点,那么当它一刷新,负载均衡会将请求分发给B节点,那么B节点没有用户A的登陆信息,就会提示用户A登陆,当A用户点击登陆时又会将请求分发给C节点,从而造成用户A无法实现会话保持。
1.3 如何实现会话保持
1.粘性
session(演示):指Nginx每次都将同一用户的所有请求转发至同一台服务器上,及Nginx的IP_hash。2.
session复制(不用):每次session发生变化,就广播给集群中的服务器,使所有的服务器上的session相同。3.
session共享(√):缓存session至内存数据库中,使用redis,memcached实现。4.
session持久化:将session存储至数据库中,像操作数据一样操作session。
1.4 会话保持场景演示
1.4.1 配置web节点
1.首先安装并配置 phpmyadmin
官网:https://www.phpmyadmin.net/
📎phpMyAdmin-4.8.4-all-languages.zip
[root@web01 conf.d]# cd /code
[root@web01 code]# wget http://files.phpmyadmin.net/phpMyAdmin/4.8.4/phpMyAdmin-4.8.4-all-languages.zip
[root@web01 code]# unzip phpMyAdmin-4.8.4-all-languages.zip2.修改 phpmyadmin 连接远程的数据库
[root@web01 /code]# cd phpMyAdmin-4.8.4-all-languages
[root@web01 phpMyAdmin-4.8.4-alllanguages]# cp config.sample.inc.php config.inc.php
[root@web01 phpMyAdmin-4.8.4-alllanguages]# vim config.inc.php
/* Server parameters */
$cfg['Servers'][$i]['host'] = '172.16.1.51';3.在多台 web 上准备 phpmyadmin 的 nginx 配置文件
[root@web01 ~]# cat /etc/nginx/conf.d/php.conf
server {
listen 80;
server_name php.ops.net;
root /code/phpMyAdmin-4.8.4-all-languages;
location / {
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
#重启Nginx服务
[root@web01 ~]# systemctl restart nginx1.4.2 配置负载均衡
1.编写一份 proxy 负载均衡的配置文件,将请求调度到后端 web 节点
[root@proxy01 ~]# cat /etc/nginx/conf.d/proxy_php.com.conf
upstream php {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name php.ops.net;
location / {
proxy_pass http://php;
include proxy_params;
}
}2.检查语法并重载 nginx
[root@proxy01 conf.d]# nginx -t
[root@proxy01 conf.d]# systemctl restart nginx1.4.3 配置Redis服务
1.安装 redis 内存数据库
[root@Redis-node1 ~]# yum install redis -y2.配置 redis 监听在本地的内网网卡上
[root@Redis-node1 ~]# sed -i '/^bind/c bind 127.0.0.1 172.16.1.41' /etc/redis.conf3.启动 redis
[root@Redis-node1 ~]# systemctl start redis
[root@Redis-node1 ~]# systemctl enable redis1.4.4 配置php连接Redis
1.修改 /etc/php.ini 文件。[所有节点都需要操作]
[root@web ~]# vim /etc/php.ini
session.save_handler = redis
session.save_path = "tcp://172.16.1.41:6379"
;session.save_path = "tcp://172.16.1.41:6379?auth=123" #如果redis存在密码,则使用该方式2.注释 php-fpm.d/www.conf 里面的两条内容,否则 session 内容会一直写入 /var/lib/php/session 目录中,从而造成会话共享失败。[所有节点都需要操作]
[root@web ~]# vim /etc/php-fpm.d/www.conf
;php_value[session.save_handler] = files
;php_value[session.save_path] = /var/lib/php/session3.重启 php-fpm 服务。[所有节点都需要操作]
[root@web ~]# php-fpm -t
[root@web ~]# systemctl restart php-fpm1.4.5 测试集群会话共享
1.使用浏览器登陆网站,获取对应的 cookie 信息

2.检查 redis 中是否存在 cookie 对应的 session 信息
[root@redis-node1 ~]# redis-cli
127.0.0.1:6379> keys *
1) "PHPREDIS_SESSION:393ff522ed2a7e26ba44f6d925f991f2"
127.0.0.1:6379>3.此时用户的 cookie 始终都不会发生任何变化,无论请求被负载调度到那一台后端 web 节点服务器都不会出现没有登陆情况。

2. 后端节点异常容错机制
使用nginx负载均衡时,如何将后端请求超时的服务器流量平滑的切换到另一台上。
如果后台服务连接超时,Nginx是本身是有机制的,如果出现一个节点down掉的时候,Nginx会更据你具体负载均衡的设置,将请求转移到其他的节点上,但是,如果后台服务连接没有down掉,而是返回了错误异常码如:504、502、500,该怎么办
2.1 配置语法
# 当其中一台返回错误码 404,500 等错误时,可以分配到下一台服务器程序继续处理,提高平台访问成功率。
proxy_next_upstream http_500 | http_502 | http_503 | http_504 |http_404;2.2 场景示例
server {
listen 80; # 监听 80 端口(HTTP)
server_name blog.ops.net; # 绑定域名 blog.ops.net
location / { # 匹配所有请求路径
proxy_pass http://node; # 将请求转发到名为 "node" 的上游服务器组
# 定义故障转移条件:以下情况触发转发到下一个后端服务器
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 2; # 最多尝试 2 次后端服务器(含首次)
proxy_next_upstream_timeout 3s; # 故障转移总耗时不超过 3 秒
}
}3. Nginx负载均衡调度场景
3.1 根据uri进行调度(路由)

8.1.1 环境准备
8.1.2 配置应用节点
# 配置后端WEB节点的Nginx (注意提供的页面代码不一样)
[root@web01 conf.d]# cat agent.ops.net.conf
server {
listen 80;
server_name agent.ops.net;
root /code;
location / {
index index.html;
}
}8.1.3 配置负载均衡
# 根据不同的URL请求调度到不同的资源池
[root@proxy01 conf.d]# cat proxy_agent.ops.net.conf
upstream user {
server 172.16.1.8;
}
upstream pass {
server 172.16.1.7;
}
server {
listen 80;
server_name agent.ops.net;
location /user {
proxy_pass http://user;
include proxy_params;
}
location /pass {
proxy_pass http://pass;
include proxy_params;
}
}3.2 Proxy添加/与不添加/
在使用proxy_pass反向代理时,最后结尾添加/和不添加/有什么区别?
proxy_pass http://localhost:8080;proxy_pass http://localhost:8080/;
3.2.1 不添加/示例
server {
listen 80;
server_name agent.ops.net;
location /user {
proxy_pass http://172.16.1.7:80;
}
}
#用户请求URL: /user/test/index.html
#请求到达Nginx负载均衡: /user/test/index.html
#Nginx负载均衡到后端节点:/user/test/index.html3.2.2 添加/示例
server {
listen 80;
server_name agent.ops.net;
location /user {
proxy_pass http://172.16.1.7:80/;
}
}
#用户请求URL: /user/test/index.html
#请求到达Nginx负载均衡: /user/test/index.html
#Nginx负载均衡到后端节点: /test/index.html3.2.3 结果总结
1.带 / 意味着Nginx代理会修改用户请求的URL,将location匹配的URL进行删除。
2.不带 / 意味着Nginx代理不会修改用户请求的URL,而是直接代理到后端应用服务器。
3.3 根据请求设备进行调度
www.jd.com -----> m.jd.com (Rewrite)

3.3.1 环境准备
3.3.2 配置应用节点
# 配置后端WEB节点的Nginx配置。(注意pc和phone准备的站点内容不一样)
[root@web01 conf.d]# cat /etc/nginx/conf.d/agent.ops.net.conf
server {
listen 80;
server_name agent.ops.net;
root /code;
location / {
index index.html;
}
}3.3.3 配置负载均衡
# 根据不同的浏览器调度到不同的资源池
[root@proxy01 conf.d]# cat proxy_agent.ops.net.conf
upstream pc {
server 172.16.1.7:80;
}
upstream phone {
server 172.16.1.8:80;
}
server {
listen 80;
server_name agent.ops.net;
location / {
#默认都走pc
proxy_pass http://pc;
include proxy_params;
default_type text/html;
charset utf-8;
#如果是安卓或iphone,则走phone
if ( $http_user_agent ~* "android|iphone|iPad" ) {
proxy_pass http://phone;
}
#如果是IE浏览器,要么拒绝,要么返回一个好的浏览器下载页面
if ( $http_user_agent ~* "MSIE" )
{
return 200 '浏览器真棒!';
}
}
}3.3.4 结果测试与验证

4. Nginx多级代理获取真实IP
4.1 多级代理获取地址概述
用户发起请求,沿途可能会经过多级代理,最终抵达应用节点,那应用节点如何获取客户端真实IP地址实现方式1:通过X-Forwarded-For透传
客户端的真实IP实现方式2:使用Nginx RealIP模块实现客户端地址透传

4.2 多级代理获取地址实践
4.2.1 环境准备
1.基于代理(七层负载均衡)情况下
环境:
10.0.0.5 proxy_node1 一级代理
10.0.0.6 proxy_node2 二级代理
10.0.0.7 proxy_node3 三级代理
10.0.0.8 webserver 真实节点
4.2.2 配置一级代理
[root@proxy01 conf.d]# cat proxy_ip.ops.net.conf
server {
listen 80;
server_name ip.ops.net;
location / {
proxy_pass http://10.0.0.7;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}4.2.3 配置二级代理
[root@proxy01 conf.d]# cat proxy_ip.ops.net.conf
server {
listen 80;
server_name ip.ops.net;
location / {
proxy_pass http://10.0.0.8;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}4.2.4 配置应用节点
[root@web02 conf.d]# cat ip.ops.net.conf
server {
listen 80;
server_name ip.ops.net;
root /code;
location / {
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}4.3 多级代理获取地址测试
4.3.1 通过php脚本分析
# 通过如下页面获取真实IP,或查看 phpinfo() 函数中的 HTTP_X_FORWARDED_FOR
[root@web02 conf.d]# cat /code/index.php
<?php
phpinfo();
?>4.3.2 通过日志分析
#1.proxy_node1代理的日志
10.0.0.1 - - "GET /index.php HTTP/1.1" 200
#2.proxy_node2代理的日志
10.0.0.5 - - "GET /index.php HTTP/1.1" 200 "10.0.0.1"
#3.真实节点
10.0.0.7 - - "GET /index.php HTTP/1.1" 200 "10.0.0.1, 10.0.0.5"4.4 RealiP模块获取真实IP
使用nginx Realip_module获取多级代理下的客户端真实IP地址,在后端Web节点上添加如下配置即可(Realip需要知道所有沿途经过的代理节点的IP地址或IP段);
4.4.1 配置示例
[root@web02 conf.d]# cat ip.ops.net.conf
server {
listen 80;
server_name ip.ops.net;
root /code;
set_real_ip_from 10.0.0.5;
set_real_ip_from 10.0.0.7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
#set_real_ip_from:真实服务器上一级代理的IP地址或者IP段,可以写多行
#real_ip_header:从哪个header头检索出需要的IP地址
#real_ip_recursive:递归排除set_real_ip_from里面出现的IP,其余没有出现的认为是用户真实IP
location / {
index index.php index.html;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}4.4.2 结果验证
最终结果是"10.0.0.1 - - "GET /index.php HTTP/1.1" 200 "10.0.0.1, 10.0.0.5"
而10.0.0.5出现在set_real_ip_from中,仅仅10.0.0.1没出现,那么他就被认为是用户真实的ip地址,同时会被赋值到 $remote_addr变量中,这样我们的程序无需做任何修改,直接使用$remote_addr变量即可获取真实IP地址。
9、Nginx TCP负载均衡
1. 四层负载均衡基本概述
1.1 什么是四层负载均衡
所谓四层就是基于IP+端口的负载均衡,它通过用户请求的端口来决定将请求转发至哪台后端服务器。
就是通过三层的IP地址并加上四层的端口号,来决定哪些流量需要做负载均衡。对需要负载均衡的流量进行NAT转换,然后转发至后端服务器节点,并记录这个TCP或者UDP的流量是由哪台后端服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。
1.2 四层负载均衡应用场景
1.场景一、端口代理
首先http当然是最常用的一种协议,但是还是有很多非http的应用(mysql、redis、ssh),只能用四层代理。
2.场景二、四层负载均衡+七层负载均衡,实现大规模集群架构。
其次七层代理需要CPU运算,所以单台机器很难做到很高的处理能力,因此需要在七层负载均衡前面再加四层负载均衡。(提高网站的访问效率,并保证了七层负载均衡的高可用性。)

1.3 四层负载均衡优缺点
1.四层负载均衡通常用来转发非http应用:如 tcp/80 tcp/443 tcp/3306 tcp/22 udp/53
2.四层负载均衡可以解决七层负载均衡高可用性的问题。( 多个七层负载均衡同时提供服务 )
3.四层负载均衡可以解决七层负载均衡端口数限制问题。( 七层负载均衡最多能使用的端口是5w )
4.四层转发效率远比七层代理的效率高的多,但是他只能支持tcp/ip协议,所以他的功能较弱,虽然七层效率不高,但他支持http/https这样的应用层协议。
2. 四层负载均衡场景实践
2.1 配置语法示例
stream {
upstream backend {
hash $remote_addr consistent;
server backend1.example.com:12345 weight=5;
server 127.0.0.1:12345 max_fails=3 fail_timeout=30s;
server unix:/tmp/backend3;
}
server {
listen 12345;
proxy_connect_timeout 1s;
proxy_timeout 3s;
proxy_pass backend;
}
}2.2 实现HTTP协议负载均衡
前端四层负载均衡+后端七层负载均衡+应用节点
1.配置nginx四层负载均衡
[root@lb02 ~]# vim /etc/nginx/nginx.conf
events {
....
}
include /etc/nginx/conf.c/*.conf;
http {
.....
}
#创建存放四层负载均衡配置的目录
[root@lb4-01 conf.c]# rm -f /etc/nginx/conf.d/default.conf #删除http的80端口
[root@lb4-01 ~]# mkdir /etc/nginx/conf.c
[root@lb4-01 ~]# cd /etc/nginx/conf.c
[root@lb4-01 conf.c]# cat lb_domain.conf
stream {
upstream lb {
server 172.16.1.5:80 weight=5 max_fails=3 fail_timeout=30s;
server 172.16.1.6:80 weight=5 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
proxy_connect_timeout 3s;
proxy_timeout 3s;
proxy_pass lb;
}
}2.重启Nginx
[root@lb4-01 conf.c]# systemctl restart nginx
[root@lb4-01 conf.c]# systemctl enable nginx2.3 实现MySQL负载均衡
请求负载均衡 5555 ---> 172.16.1.7:22
请求负载均衡 6666 ---> 172.16.1.51:3306
Nginx四层负载均衡配置如下
[root@lb01 ~]# mkdir -p /etc/nginx/conf.c
[root@lb01 ~]# vim /etc/nginx/nginx.conf
# 在events层下面,http层上面配置include
include /etc/nginx/conf.c/*.conf;
# 配置Nginx四层转发
[root@lb01 ~]# cd /etc/nginx/conf.c/
[root@lb01 conf.c]# cat stream.conf
stream {
#1.定义转发tcp/22端口的虚拟资源池
upstream ssh {
server 172.16.1.7:22;
}
#2.定义转发tcp/3306端口的虚拟资源池
upstream mysql {
server 172.16.1.51:3306;
}
#调用虚拟资源池
server {
listen 5555;
proxy_connect_timeout 1s;
proxy_timeout 300s;
proxy_pass ssh;
}
server {
listen 6666;
proxy_connect_timeout 1s;
proxy_timeout 300s;
proxy_pass mysql;
}
}
[root@lb01 conf.c]# systemctl restart nginx2.4 实现非HTTP协议负载均衡

10、Nginx Rewrite模块
1. Rewrite基本介绍
1.1 什么是Rewrite
Rewrite主要实现url地址重写, 以及url地址跳转。
就是将用户请求web服务器的URL地址重新修改为其他URL地址的过程。
比如说京东、google、亚马逊都在使用
1.2 Rewrite应用场景
1.地址跳转,用户访问 www.jd.com 这个URL时,将其定向至一个新的域名 m.jd.com
2.协议跳转,将用户通过http的请求协议重新跳转至https协议(实现https主要手段)
3.URL静态化,将动态URL地址显示为静态URL的一种技术,能提高搜索引擎抓取,并且能减少动态URL对外暴露过多的参数
1.3 Rewrite重写原理

1.nginx和业务在一台服务器 nginx-->
2.nginx和业务系统分开; 360buy.com rewrite --> jd.com
1.4 Rewrite重写模块
set 设置变量
if 语句判断
return 返回返回值或URL
rewrite 重定向URL
2. Rewrite重写模块
2.1 if条件判断指令
2.1.1 语法示例
Syntax: if (condition) { ... }
Default: —
Context: server, location
# ~ 模糊匹配
# ~* 不区分大小写的匹配
# !~ 不匹配
# = 精确匹配2.1.2 场景示例
url.ops.net/index.html?id=1234 --》 proxy -->10.16.3.5:8080
# 需求:匹配Nginx请求中包含id=2356的,然后代理到10.16.3.5 的8080端口
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
default_type application/json;
root /code;
location / {
index index.html;
#\d表示数字,{4} 表示4次,{4,8}表示数字出现的次数是4到8次,如gid=12345678就符合该条件。
if ( $request_uri ~* 'id=\d{4}' ) {
proxy_pass http://10.0.0.17:80;
}
}
}
# 测试
curl -L url.ops.net/?id=2356
2.2 set设定变量指令
2.2.1 语法示例
Syntax: set $variable value;
Default: —
Context: server, location, if2.2.2 场景示例
# 需求:通过user_agent(Header)拦截压测测试工具
# user_agent:
# chrome ,firefox, curl/7.29.0
# 1.确认来请求的用户是使用的curl命令,如果是则做一个标记,设置为1;
# 2.判断标记,如果标记的值假设为1,我们就拒绝,如果不为1则不处理;server {
listen 80;
server_name set.ops.net;
root /code;
index index.html;
location / {
if ($http_user_agent ~* "Wget|ApacheBench") {
set $deny_user_agent 1;
}
if ($deny_user_agent = 1){
return 403;
}
}
}
# 模拟压测工具访问:
curl -A "YisouSpider" -I URL
curl -A "ApacheBench" -I URL
curl -A "wget" -I URL
2.3 return返回数据指令
2.3.1 语法示例
Syntax: return code;
return code [text];
return URL;
Default: —
Context: server, location, if2.3.2 场景实践
# 需求:客户端使用IE浏览器访问站点,则返回段字符串或返回错误
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
index index.html;
default_type text/html;
if ( $http_user_agent ~* "MSIE|firefox" ) {
return 200 "Change browser";
# 返回字符串
# return 500;
# 返回状态码
# return 302 https://www.ops.com; # 返回 URL,进行站点跳转
}
}
}
3. Rewrite重写Flag
rewrite主要是用来重写URL或者跳转URL的指令。
#rewrite表达式可以应用在server,location, if标签下
# 关键字 正则 替代内容 flag标记
Syntax: rewrite regex replacement [flag];
Default: --
Context: server, location, if
#flag
last #本条规则匹配完成后,继续向下匹配新的location URI规则
break #本条规则匹配完成即终止,不再匹配后面的任何规则
redirect #返回302临时重定向, 地址栏会显示跳转后的地址
permanent #返回301永久重定向, 地址栏会显示跳转后的地址3.1 测试代码准备
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
rewrite /1.html /2.html;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
#准备对应代码
[root@web01]# echo "1.html" >/code/1.html
[root@web01]# echo "2.html" >/code/2.html
[root@web01]# echo "3.html" >/code/3.html
[root@web01]# echo "a.html" >/code/a.html
[root@web01]# echo "b.html" >/code/b.html
#测试结果: 当请求/1.html,最终将会访问/b.html
3.2 Break与last
3.2.1 为代码添加Break
#测试结果: 当请求/1.html,最终会访问/2.html
#因为:在location{}内部,遇到break,本location{}内以及后面的所有location{}内的所有指令都不再执行。
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
rewrite /1.html /2.html break;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
3.2.2 为代码添加last
# 测试结果:当请求/1.html,最终会访问/a.html
# 因为:在location{}内部,遇到last,本location{}内后续指令不再执行
# 而重写后的url会对所在的server{...}标签重新发起请求,从头到尾匹配一遍规则,哪个匹配则执行哪个
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
rewrite /1.html /2.html last;
rewrite /2.html /3.html;
}
location /2.html {
rewrite /2.html /a.html;
}
location /3.html {
rewrite /3.html /b.html;
}
}
3.2.3 break与last区别
当rewrite规则遇到break后,本location{}与其他location{}的所有规则都不执行。
当rewrite规则遇到last后,本location{}里后续规则不执行,但重写后的url会再次从头开始匹配所有Location,哪个匹配执行哪个。
3.3 redirect与permanent
3.3.1 为代码添加redirect
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
rewrite /1.html /2.html redirect;
rewrite /2.html /3.html;
}
}
3.3.2 为代码添加permanent
# 跳转后状态码为301
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
rewrite /1.html /2.html permanent;
rewrite /2.html /3.html;
}
}
3.3.3 redirect与permanent区别
4.Rewrite 生产案例实践
4.1 Rewrite跳转示例1
# 需求:根据用户浏览器请求头中携带的语言调度到不同的页面
# /zh
# /en
url.ops.net --》url.ops.net/zh
url.ops.net --》url.ops.net/en
server {
listen 80;
server_name url.ops.net;
root /code;
if ($http_accept_language ~* "zhCN|zh") {
set $language /zh;
}
if ($http_accept_language ~* "en") {
set $language /en;
}
rewrite ^/$ /$language; #根据语言跳转对应的站点
location / {
index index.html;
}
}mkdir /code/zh
mkdir /code/en
echo zh > /code/zh/index.html
echo en > /code/en/index.html
4.2 Rewrite跳转示例2
# 需求:用户通过手机设备访问 url.ops.net,跳转至url.ops.net/m
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
if ($http_user_agent ~* "android|iphone|ipad") {
rewrite ^/$ /m;
}
}mkdir /code/m
echo m > /code/m/index.html
4.3 Rewrite跳转示例3
# 需求:用户通过手机设备访问 url.ops.net 跳转至m.ops.net
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
if ($http_user_agent ~* "android|iphone|ipad") {
rewrite ^/$ http://m.ops.net;
}
}
server {
listen 80;
server_name m.ops.net;
root /data/m;
location / {
index index.html;
}
}mkdir -p /data/m
echo m66 > /data/m/index.html
4.4 Rewrite跳转示例4
# 需求:用户通过http协议请求,能自动跳转至https协议。
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
rewrite ^(.*)$ https://$server_name$1 redirect;
#return 302 https://$server_name$request_uri;
}
server {
listen 443;
server_name url.ops.net;
ssl on;
}4.5 Rewrite跳转示例5
# 需求: 网站在维护过程中,希望用户访问所有网站重定向至一个维护页面
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
#配置示例
rewrite ^(.*)$ /wh.html break;
location / {
index index.html;
}
}echo wh > /code/wh.html
4.6 Rewrite跳转示例6
# 需求: 当服务器遇到 403 404 502 等错误时,自动转到临时维护的静态页。[https://404.life/]
[root@web01]# cat url.ops.net.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
index index.html;
}
#配置示例
error_page 404 403 502 = @tempdown;
location @tempdown {
rewrite ^(.*)$ /wh.html break;
}
}
4.7 Rewrite跳转示例7
# 公司网站在停机维护时,指定的IP能够正常访问,其他的IP跳转到维护页。
[root@web01 conf.d]# cat wh.conf
server {
listen 80;
server_name url.ops.net;
root /code;
#1.在server层下设定ip变量值为0
set $ip 0;
#2.如果来源IP是10.0.0.101 102则设定变量为ip变量为1。
if ($remote_addr ~* "10.0.0.101|10.0.0.102") {
set $ip 1;
}
#3.如果来源IP不是10.0.0.101 102、则跳转至/code/wh.html这个页面,否则不做任何处理
if ($ip = 0) {
rewrite ^(.*)$ /wh.html break;
}
#-->如果想针对某个location进行操作,则将如上配置写入location中即可
location / {
index index.html;
}
}
4.8 Rewrite跳转示例8
# 需求:公司网站后台/admin,只允许公司的出口公网IP可以访问,其他的IP访问全部返回500,或直接跳转至首页
#限制访问来源IP
location /admin {
set $ip 0;
if ( $remote_addr ~* "61.149.186.152|139.226.172.254" ) {
set $ip 1;
}
if ($ip = 0){
return 500;
#rewrite /(.*)$ https://url.ops.net redirect;
}
}
4.9 Rewrite跳转示例9

#解决办法
server {
listen 80;
server_name url.ops.net;
#匹配域名,然后将第一个字段赋值给domain
if ( $host ~* (.*)\.(.*)\.(.*) ) {
#if ( $host ~* (.*)\..* ) {
set $domain $1;
}
rewrite ^/(.*) http://demo:27610/$domain$request_uri redirect;
}
4.10 Rewrite跳转示例10
现有两台服务器,想要实现http://console.ops.net/index.php?r=sur/index/sid/613192/lang/zh-Hans若访问资源为/index.php?r=survey...则跳转到http://sur.ops.net/index.php?r=survey/index/sid/613192/lang/zh-Hans
请求的域名:http://url.ops.net/index.php?r=survey/index/sid/613192/lang/zh-Hans
替换后域名:http://sur.ops.net/index.php?r=survey/index/sid/613192/lang/zh-Hans
[root@web01 ~]# cat /etc/nginx/conf.d/tou.ops.net.conf
server {
listen 80;
server_name console.ops.net;
root /code;
index index.html;
location / {
if ($args ~ r=survey) {
rewrite ^/(.*) http://sur.ops.net$request_uri? redirect;
}
}
}
# 测试
curl -L -I -HHost:url.ops.net http://10.0.0.7/index.php?r=sur/index/sid/613192/lang/zh-Hans
curl -L -I -HHost:url.ops.net http://10.0.0.7/index.php?r=survey/index/sid/613192/lang/zh-Hans
4.11 Rewrite跳转示例11
需求:将用户请求http://url.ops.net/?id=2,替换为 http://url.ops.net/id/2.html
1.必须是请求id? 判断用户请求的是id这个关键参数;
2.提取整个uri中的两个字段, 将左边的做成一个变量,将右边的做成一个变量;
3.如果来源为id成立的话,则执行rewirte;
[root@web01 ~]# cat /etc/nginx/conf.d/url.ops.com.conf
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
if ($args ~* "id") {
set $OK 1;
}
if ($args ~* (.*)\=(.*) ) {
set $id $1;
set $number $2;
}
if ( $OK = "1" ) {
# ?这个尾缀,重定向的目标地址结尾处如果加了?号,则不会再转发传递过来原地址问号内容
rewrite ^(.*)$ http://${server_name}/${id}/${number}.html? last;
}
}
}curl -L -I -HHost:url.ops.net http://10.0.0.7/?id=2
4.12 禁止搜索引擎爬取站点
# 需求:通过user_agent防止搜索引擎的爬取
server {
listen 80;
server_name url.ops.net;
root /code;
location / {
if ($http_user_agent ~* "YisouSpider|YoudaoBot|tt") {
return 403;
}
}
}
# 测试
curl -A "YisouSpider" -I URL
curl -A "ApacheBench" -I URL
curl -A "wget" -I URL
4.13 禁止站点资源被盗用
防盗链,指的是防止资源被其他网站恶意盗用。
如何避免网站资源被盗用:可以根据客户端请求所携带的Referer信息来验证请求的合法性,因为Referer会告诉服务器它是丛哪一个域名点击过来的;
基于Referer限制盗链:
优点:规则简单、配置和使用都很方便
缺点:防盗链所依赖的Referer验证信息是可以伪造的,并非100%可靠
但基于Referer限制盗链的方式,可以限制绝大多数盗链情况
4.13.1 环境准备
4.13.2 配置被盗链节点
# 在 10.0.0.8 节点配置Nginx站点信息
[root@web02 ~]# cat /etc/nginx/conf.d/img.ops.net.conf
server {
listen 80;
server_name img.ops.net;
root /code;
location / {
index index.html;
}
}
[root@web02 ~]# systemctl reload nginx
# 准备图片4.13.3 配置盗链节点
# 在 10.0.0.7 节点配置Nginx站点信息
[root@Nginx ~]# vim /etc/nginx/conf.d/tou.ops.net.conf
server {
listen 80;
server_name tou.ops.net;
location / {
root /code;
index index.html;
}
}
# 准备html网页代码,偷取img.ops.net站点图片
[root@Nginx ~]# vim /code/index.html
<html>
<head>
<meta charset="utf-8">
<title>ops.net</title>
</head>
<img
src="http://img.ops.net/toutu.jpg"/>
</html>
4.13.4 防盗链配置语法
# 基于http_referer防止资源被盗用
Syntax: valid_referers none | blocked |
server_names | string ...;
Default: —
Context: server, location
#none: Referer来源头部为空的情况
#blocked: Referer来源头部不为空,直接填写允许的域名即可
#server_names: 来源头部包含当前的域名,可以正则匹配4.13.5 防盗链配置实践
配置所有来自*.ops.com都可以访问到img.ops.net站点的图片如果来源域名不在这个列表中,那么$invalid_referer变量值为1,后续通过if判断,进行错误返回;
[root@web02 ~]# vim /etc/nginx/conf.d/img.ops.net.conf
server {
listen 80;
server_name img.ops.net;
root /code;
location / {
index index.html;
}
location ~ .*\.(jpg|jpeg|gif|png)$ {
# 来源域名如何合法,invalid_referer这个变量被设置为0,否则为1
valid_referers none blocked *.ops.com;
if ($invalid_referer) {
return 403;
# 当然也可以返回一张图片给用户
rewrite ^(.*)$ /error.jpg break;
}
}
# 允许 google、baidu、等站点能够(盗链)资源,那么则可以通过server_names开放
# location ~* \.(gif|jpg|png|bmp)$ {
# valid_referers none blocked *.ops.com server_names ~\.google\. ~\.baidu\.;
# if ($invalid_referer) {
# return 403;
# }
# }
}
# 如果存在盗链,则返回一张图片
[root@web02 ~]# vim /etc/nginx/conf.d/img.ops.net.conf
server {
listen 80;
server_name img.ops.net;
root /code;
location / {
index index.html;
}
location ~ .*\.(jpg|jpeg|gif|png)$ {
valid_referers none blocked *.ops.com;
if ($invalid_referer) {
rewrite ^(.*)$ /error.gif break;
}
}
}4.13.6 防盗链结果验证

11、Nginx HTTPS 实践
1. HTTPS基本概述
1.1 为何需要HTTPS
因为HTTP采用的是明文传输数据,那么在传输(账号密码、交易信息、等敏感数据)时不安全。容易遭到篡改,如果使用HTTPS协议,数据在传输过程中是加密的,能够有效避免网站传输时信息泄露。
1.2 什么是HTTPS
HTTPS安全的超文本传输协议,我们现在大部分站点都是通过HTTPS来实现站点数据安全。
早期网景公司设计了SSL(Secure Socket Layer)安全套接层协议,主要对HTTP协议传输的数据进行加密。那如何将站点变成安全的HTTPS站点呢?我们需要了解SSL(Secure Socket Layer)协议。
而现在很多时候我们使用的是TLS(Transport Layer Security)传输层安全协议来实现的加密与解密。

1.3 TLS如何实现加密
TLS/SSL是如何实现HTTP明文消息被加密的,TLS/SSL工作在OSI七层模型中,应用层与传输层之间。
1.提供数据安全:保证数据不会被泄露。
2.提供数据的完整性:保证数据在传输过程中不会被篡改。
3.对应用层交给传输层的数据进行加密与解密。

2. HTTPS实现原理
2.1 加密模型-对称加密
对称加密:两个想通讯的人持有相同的秘钥,进行加密与解密。如下:
bob将原始文档通过秘钥加密生成一个密文文档。
alice拿到这个密文文档以后,它可以用这把秘钥还原为原始的明文文档。

对称加密究竟是如何实现的,我们可以以RC4这样一个对称加密序列算法来看一下
加密:秘钥序列+明文=密文
解密:秘钥序列+密文=明文

2.2 加密模型-非对称加密
非对称加密:它根据一个数学原理,创建一对秘钥(公钥和私钥)公钥加密,私钥解密;
私钥:私钥自己使用,不对外开放。
公钥:公钥给大家使用,对外开放。
比如:alice有一对公钥和私钥,他可以将公钥发布给任何人。假设Bob是其中一个,当Bob要传递一份加密文档给alice,那么Bob就可以用alice的公钥进行加密,alice收到密文文档后通过自己的私钥进行解密,获取原始文档。

注意:alice必须知道Bob就是Bob,也就是它收到的信息必须是Bob发来的,那么这个信任问题,在多方通讯的过程中,必须有一个公信机构来验证双方的身份,那么这个机构就是CA机构。
2.3 身份验证机构-CA
通讯双方是如何验证双方的身份?
CA架构是可信任组织架构,主要用来颁发证书及验证证书。那CA机构又是如何申请和颁发证书的呢?

我们首先需要申请证书,需要进行登记,登记我是谁,我是什么组织,我想做什么,到了登记机构在通过CSR发给CA,CA中心通过后,CA中心会生成一对公钥和私钥,那么公钥会在CA证书链中保存,公钥和私钥证书订阅人拿到后,会将其部署在WEB服务器上
1.当浏览器访问我们的https站点时,它会去请求我们的证书
2.Nginx会将我们的公钥证书回传给浏览器。
3.浏览器会去验证我们的证书是否是合法的、是否是有效的。
4.CA机构会将过期的证书放置在CRL服务器,那么CRL服务的验证效率是非常差的,所以CA又推出了OCSP响应程序,OCSP响应程序可以查询指定的一个证书是否过期,所以浏览器可以直接查询OCSP响应程序,但OCSP响应程序性能还不是很高。
5.Nginx会有一个OCSP的开关,当我们开启后,Nginx会主动上OCSP上查询,这样大量的客户端直接从Nginx获取,证书是否有效。
2.4 HTTPS通讯原理

HTTPS加密过程,HTTPS采用混合加密算法,即对称加密、和非对称加密
通信前准备工作:申请域名对应的证书,并将其部署在Nginx服务器中。
1)第一步客户端向服务端发送 Client Hello 消息,这个消息里包含了一个客户端生成的随机数 Random1、客户端支持的加密套件和客户端支持TLS协议版本等信息。
2)服务端会向客户端发送 Server Hello 消息。返回自己的公钥证书、挑选一个合适的加密套件、另外还会生成一份随机数 Random2推送给客户端。至此客户端和服务端都拥有了两个随机数(Random1+ Random2)
3)客户端收到服务端传来的公钥证书后,先从 CA 验证该证书的合法性(CA公钥去解密公钥证书),验证通过后取出证书中的服务端公钥,再生成一个随机数Random3,再用服务端公钥非对称加密Random3。
4)服务端用自己的私钥解出客户端生成的 Random3。至此,客户端和服务端都拥有 Random1 + Random2 + Random3,两边根据同样的算法生成一份秘钥,握手结束后的应用层数据都是使用这个秘钥进行对称加密。
3. HTTPS扩展知识
3.1 Https证书类型
DV;
OV:花钱;
EV:买不起;

3.2 Https购买建议
ops.net (www.ops.net blog.ops.net images.ops.net cdn.ops.net m.ops.net qq.ops.net)
保护1个域名 www
保护5个域名 www images cdn test m
通配符域名 *.ops.net
3.3 Https颜色标识
Https不支持续费,证书到期需重新申请新并进行替换。
Https不支持三级域名解析,如 test.m.ops.net *.m.ops.net
Https显示绿色,说明整个网站的url都是https 的,并且都是安全的。
Https显示黄色,说明网站代码中有部分URL地址是http不安全协议的。(https (http url) )
Https显示红色,要么证书是假的,要么证书已经过期。
4. HTTPS单台配置实践
4.1 配置SSL语法
#官方示例
worker_processes auto;
http {
...
server {
listen 443 ssl;
keepalive_timeout 70;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /usr/local/nginx/conf/cert.pem;
ssl_certificate_key /usr/local/nginx/conf/cert.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
...
}
}4.2 创建SSL证书
1.创建证书存储目录
[root@web01 ~]# mkdir -p /etc/nginx/ssl_key
[root@web01 ~]# cd /etc/nginx/ssl_key2.使用openssl命令充当CA权威机构创建证书(类似黑户)
[root@web01 ssh_key]# openssl genrsa -idea -out server.key 2048
Generating RSA private key, 2048 bit long
modulus
.....+++
#记住配置密码, 我这里是1234
Enter pass phrase for server.key:
Verifying - Enter pass phrase for
server.key:3.生成自签证书,同时去掉私钥的密码
[root@web01 ssl_key]# openssl req -days 36500 -x509 -sha256 -nodes -newkey rsa:2048 -keyout server.key -out server.crt
Country Name (2 letter code) [XX]:CN
#国家
State or Province Name (full name) []:WH #省
Locality Name (eg, city) [Default City]:WH #城市
Organization Name (eg, company) [Default Company Ltd]:edu #公司
Organizational Unit Name (eg, section) []: ops #单位
Common Name (eg, your name or your servers hostname) []: www.zhouhaoit.com #服务器主机名称
Email Address []:ops@qq.com
# req -->用于创建新的证书
# new -->表示创建的是新证书
# x509 -->表示定义证书的格式为标准格式
# key -->表示调用的私钥文件信息
# out -->表示输出证书文件信息
# days -->表示证书的有效期4.3 配置SSL场景
[root@lb01 /etc/nginx/conf.d]# cat www.zhouhaoit.com.conf
server {
listen 443 ssl;
server_name www.zhouhaoit.com;
#ssl on;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
location / {
root /code;
index index.html;
}
}
#准备对应的站点目录, 并重启Nginx服务
[root@web01]# mkdir -p /code
[root@web01]# echo "hello" > /code/index.html
[root@web01]# systemctl restart nginx4.4 访问验证SSL
浏览器输入https://www.zhouhaoit.com/访问,由于该证书非第三方权威机构颁发,而是我们自己签发的,所以浏览器会警告


4.5 强制跳转Https
如果用户忘记在浏览器地址栏输入 https:// 协议那么将不会跳转至https站点;
所以建议新增如下配置,将用户访问 http 请求强制跳转 https
[root@lb01 /etc/nginx/conf.d]# cat www.zhouhaoit.com.conf
server {
listen 443 ssl;
server_name www.zhouhaoit.com;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
location / {
root /code;
index index.html;
}
}
server {
listen 80;
server_name www.zhouhaoit.com;
return 302 https://$server_name$request_uri;
}
[root@lb01 /etc/nginx/conf.d]# nginx -s reload
4.6 配置阿里云证书




[root@lb01 /etc/nginx/conf.d]# cat www.zhouhaoit.com.conf
server {
listen 443 ssl;
server_name www.zhouhaoit.com;
ssl_certificate ssl_key/www.zhouhaoit.com.pem;
ssl_certificate_key ssl_key/www.zhouhaoit.com.key;
location / {
root /code;
index index.html;
}
}
server {
listen 80;
server_name www.zhouhaoit.com;
return 302 https://$server_name$request_uri;
}
5. HTTPS集群配置实践

5.1 环境准备
5.2 配置应用节点
# 配置所有后端节点,监听80端口即可;
[root@web01 conf.d]# cat s.ops.net.conf
server {
listen 80;
server_name s.ops.net;
root /code/wordpress;
location / {
index index.html;
}
}5.3 配置负载均衡
# 1.创建ssl证书
[root@lb01 ~]# mkdir /etc/nginx/ssl_key -p
[root@lb01 ~]# cd /etc/nginx/ssl_key
[root@lb01 ~]# openssl genrsa -idea -out server.key 2048
#备注:rocky 9 系统执行:openssl genrsa -aes256 -out server.key 2048
#原因:Rocky 9 系统使用的 OpenSSL 3.0 版本中,IDEA 算法默认被禁用导致的
[root@lb01 ~]# openssl req -days 36500 -x509 -sha256 -nodes -newkey rsa:2048 -keyout server.key -out server.crt
# 2.Nginx负载均衡配置文件如下
[root@lb01 ~]# cat /etc/nginx/conf.d/proxy.conf
upstream site {
server 172.16.1.7:80 max_fails=2 fail_timeout=10s;
server 172.16.1.8:80 max_fails=2 fail_timeout=10s;
}
# https站点配置信息
server {
listen 443;
server_name s.ops.net;
ssl on;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
location / {
proxy_pass http://site;
include proxy_params;
}
}
# 用户请求http协议,强制跳转至https协议
server {
listen 80;
server_name s.ops.net;
return 302 https://$server_name$request_uri;
}
# 3.重启 Nginx 负载均衡
[root@lb01 ~]# nginx -t
[root@lb01 ~]# systemctl restart nginx6. HTTPS场景配置实践
6.1 场景实践-1
模拟银行网站场景
1.用户访问网站主站,使用 http 协议提供访问
2.当用户点击登陆时,则网站会跳转至一个新的域名,并使用的是 Https 提供安全访问。
#1.主页展示 http://yh.ops.net(提供网页浏览)
#2.模拟登陆 http://yh.ops.net/login(相当于点击了登陆按钮)
#3.登陆页面 https://star.ops.net (提供安全登陆)
#1.配置 https://star.ops.net
[root@web01 ~]# cat /etc/nginx/conf.d/star.ops.net.conf
server {
listen 443 ssl;
server_name start.ops.net;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
root /code/login;
location / {
index index.html;
}
}
[root@web01 ~]# mkdir /code/login -p
[root@web01 ~]# echo "login...https" > /code/login/index.html
#2.配置 http://yh.ops.net
[root@web01 ~]# cat /etc/nginx/conf.d/yh.ops.net.conf
server {
listen 80;
server_name yh.ops.net;
root /code;
location / {
index index.html;
}
location /login {
return 302 https://start.ops.net;
}
}6.2 场景实践-2
需求:希望用户访问网站的所有Url走Https协议,但访问s.ops.net/abc时走Http协议
[root@lb01 conf.d]# cat proxy_s.ops.net.conf
upstream webs {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 443 ssl;
ssl_certificate ssl_key/server.crt;
ssl_certificate_key ssl_key/server.key;
server_name s.ops.net;
location / {
proxy_pass http://webs;
include proxy_params;
}
}
server {
listen 80;
server_name s.ops.net;
if ($request_uri !~* "^/abc") {
return 302 https://$http_host$request_uri;
}
location / {
proxy_pass http://webs;
include proxy_params;
}
}6.3 场景实践-3
开启OCSP,加速验证证书是否有效
# 准备OCSP证书:
# wget -O root.pem https://ssltools.net/certificates/dac9024f54d8f6df94935fb1732638ca6ad77c13.pem
# wget -O intermediate.pem https://letsencrypt.org/certs/lets-encryptx3-cross-signed.pem
# cat intermediate.pem > /etc/nginx/ssl_key/ocsp.pem
# cat root.pem >> /etc/nginx/ssl_key/ocsp.pem
# 配置Nginx
server {
listen 443 ssl;
server_name s.ops.net;
ssl_certificate ssl/6152750_s.ops.net.pem;
ssl_certificate_key ssl/6152750_s.ops.net.key;
#开启OCSP
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate
ssl/ocsp.pem;
root /code;
location / {
index index.html;
}
}验证是否开启OCSP响应程序
# 命令验证
[root@db01 ~]# echo QUIT | openssl s_client -connect s.ops.net:443 -status
2>/dev/null | grep -A 17 "OCSP response"
OCSP response:
======================================
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: 55744FB2724FF560BA50D1D7E6515C9A01871AD7
Produced At: Aug 20 02:33:01 2021 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 978B4716E5B0F658BAE69DAB1689B8363AE3C3A6
Issuer Key Hash: 55744FB2724FF560BA50D1D7E6515C9A01871AD7
Serial Number: 086605F8BF56EA63D3E250FDD617DDF0
Cert Status: good
This Update: Aug 20 02:18:01 2021 GMT
# 本次更新
Next Update: Aug 27 01:33:01 2021 GMT
# 下次更新
# 百度没开启OCSP
[root@db01 ~]# echo QUIT | openssl s_client -connect baidu.com:443 -status
2>/dev/null | grep -A 17 "OCSP response"
OCSP response: no response sent7. HTTPS优化配置实践
7.2 优化基本概述
SSL的运行计算需要消耗额外的 CPU 资源,SSL通讯过程中『握手』阶段的运算最占用 CPU 资源,有如下几个方面可以进行调整与优化。
1.设置worker进程数设置为等于CPU处理器的核心数。worker_processes auto
2.启用 keepalive 长连接,一个连接发送更多个请求
3.启用 shared 会话缓存,所有worker工作进程之间共享的缓存,避免进行多次 SSL『握手』
4.禁用 builtin 内置于的缓存,仅能供一个worker工作进程使用,使用shared缓存即禁止builtin
7.2 优化配置实例
worker_processes auto;
http {
...
server {
listen 443 ssl;
server_name www.example.com;
ssl_certificate www.example.com.crt;
ssl_certificate_key www.example.com.key;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
#Nginx决定使用哪些协议与浏览器进行通讯
keepalive_timeout 70;
#设置长连接
# 默认不开启session_cache: a握手后,关闭浏览器,再次访问,需要重新握手;
#建立握手后如果连接断开,在session_timeout时间内再次连接,无需再次建立握手,可直接复用之间缓存的连接。
ssl_session_cache shared:SSL:10m;
#1M缓存空间能存储 4000 个会话数量
ssl_session_timeout 1440m;
#配置会话超时时间 ( 默认5分钟 )
}12、Nginx平滑升级
1.Nginx平滑升级概述
1.1 什么是平滑升级
在进行服务版本升级的时候,对于用户访问体验无感知、不会造成服务中断。
1.2 平滑升级实现原理
平滑升级四个阶段
只有旧版nginx的master和worker进程
旧版和新版nginx的master和worker进程并存,由旧版nginx接收处理用户的新请求
旧版和新版nginx的master和worker进程并存,由新版nginx接收处理用户的新请求
只有新版nginx的master和worker进程

将旧Nginx二进制文件换成新Nginx程序文件(注意先备份)
向master进程发送USR2信号启动新nginx进程
master进程修改pid文件名加上后缀.oldbin,成为nginx.pid.oldbin
master进程用新Nginx文件启动新master进程及worker子进程成为旧master的子进程
系统中将有新旧两个Nginx主进程和对应的worker子进程并存
当前新的请求仍然由旧Nginx的worker进程进行处理
将新生成的master进程的PID存放至新生成的pid文件nginx.pid
向旧的Nginx服务进程发送WINCH信号,使旧的Nginx worker进程平滑停止
向旧master进程发送QUIT信号,关闭旧master,并删除Nginx.pid.oldbin文件
如果发现升级有问题,可以回滚∶向旧master发送HUP,向新master发送QUIT
1.3 平滑升级和回滚案例
下载最新稳定版
[root@centos7 ~]#yum install wget -y
[root@centos7 ~]#wget https://nginx.org/download/nginx-1.24.0.tar.gz
[root@centos7 ~]#tar xf nginx-1.24.0.tar.gz
[root@centos7 ~]#cd nginx-1.24.0
[root@centos7 ~/nginx-1.24.0]#ls
auto CHANGES.ru configure html man src
CHANGES conf contrib LICENSE README
#查看当前使用的版本及编译选项。结果如下:
[root@centos7 ~/nginx-1.24.0]#/apps/nginx/sbin/nginx -V
nginx version: nginx/1.18.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments: --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
#configure arguments后面是以前编译时的参数。现在编译使用一样的参数
#开始编译新版本
[root@centos7 ~/nginx-1.24.0]#./configure --prefix=/apps/nginx --user=nginx --group=nginx --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-pcre --with-stream --with-stream_ssl_module --with-stream_realip_module
#只要make无需要make install
[root@centos7 ~/nginx-1.24.0]#make
[root@centos7 ~/nginx-1.24.0]#objs/nginx -v
nginx version: nginx/1.24.0
#查看两个版本
[root@centos7 ~/nginx-1.24.0]#ll objs/nginx /apps/nginx/sbin/nginx
-rwxr-xr-x 1 nginx nginx 7774224 6月 12 11:09 /apps/nginx/sbin/nginx
-rwxr-xr-x 1 root root 7953792 6月 12 14:04 objs/nginx
#把之前的旧版的nginx命令备份
[root@centos7 ~/nginx-1.24.0]#cp /apps/nginx/sbin/nginx /usr/local/sbin/nginx.old
#把新版本的nginx命令复制过去覆盖旧版本程序文件,注意:需要加 -f 选项强制覆盖,否则会提示Text file busy
[root@centos7 ~/nginx-1.24.0]#cp -f ./objs/nginx /apps/nginx/sbin/
cp:是否覆盖"/apps/nginx/sbin/nginx"? y
#如果cp 不加-f 选项,会出现下面提示
[root@rocky8 nginx-1.24.0]#cp objs/nginx /apps/nginx/sbin/
cp: overwrite '/apps/nginx/sbin/nginx'? y
cp: cannot create regular file '/apps/nginx/sbin/nginx': Text file busy
#检测一下有没有问题
[root@centos7 ~/nginx-1.24.0]#/apps/nginx/sbin/nginx -t
nginx: the configuration file /apps/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /apps/nginx/conf/nginx.conf test is successful
#发送信号USR2 平滑升级可执行程序,将存储有旧版本主进程PID的文件重命名为nginx.pid.oldbin,并启动新的nginx。
#此时两个master的进程都在运行,只是旧的master不在监听,由新的master监听80。
#此时Nginx开启一个新的master进程,这个master进程会生成新的worker进程,这就是升级后的Nginx进程,此时老的进程不会自动退出,但是当接收到新的请求不作处理而是交给新的进程处理。
[root@centos7 ~/nginx-1.24.0]#kill -USR2 `cat /apps/nginx/run/nginx.pid`
#可以看到两个master,新的master是旧版master的子进程,并生成新版的worker进程
[root@centos7 ~/nginx-1.24.0]#ps auxf|grep nginx
root 7580 0.0 0.0 112824 988 pts/0 S+ 14:29 0:00 \_ grep --color=auto nginx
root 4473 0.0 0.0 46204 1348 ? Ss 14:24 0:00 nginx: master process /apps/nginx/sbin/nginx
nginx 4474 0.0 0.0 46652 1912 ? S 14:24 0:00 \_ nginx: worker process
root 7564 0.0 0.1 46236 3384 ? S 14:28 0:00 \_ nginx: master process /apps/nginx/sbin/nginx
nginx 7565 0.0 0.0 46608 1924 ? S 14:28 0:00 \_ nginx: worker process
[root@centos7 ~/nginx-1.24.0]#lsof -i :80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 4473 root 6u IPv4 23698 0t0 TCP *:http (LISTEN)
nginx 4474 nginx 6u IPv4 23698 0t0 TCP *:http (LISTEN)
nginx 7564 root 6u IPv4 23698 0t0 TCP *:http (LISTEN)
nginx 7565 nginx 6u IPv4 23698 0t0 TCP *:http (LISTEN)
#先关闭旧nginx的worker进程,而不关闭nginx主进程方便回滚
#向原Nginx主进程发送WINCH信号,它会逐步关闭旗下的工作进程(主进程不退出),这时所有请求都会由新版Nginx处理
[root@centos7 ~/nginx-1.24.0]#kill -WINCH `cat /apps/nginx/run/nginx.pid.oldbin`
#如果旧版worker进程有用户的请求,会一直等待处理完后才会关闭
[root@centos7 ~/nginx-1.24.0]#ps auxf|grep nginx
root 7659 0.0 0.0 112824 988 pts/0 S+ 14:30 0:00 \_ grep --color=auto nginx
root 4473 0.0 0.0 46204 1348 ? Ss 14:24 0:00 nginx: master process /apps/nginx/sbin/nginx
root 7564 0.0 0.1 46236 3384 ? S 14:28 0:00 \_ nginx: master process /apps/nginx/sbin/nginx
nginx 7565 0.0 0.0 46608 1924 ? S 14:28 0:00 \_ nginx: worker process
#经过一段时间测试,新版本服务没问题,最后发送QUIT信号,退出老的master
[root@centos7 ~/nginx-1.24.0]#kill -QUIT `cat /apps/nginx/run/nginx.pid.oldbin`
#查看版本是不是已经是新版了
[root@centos7 ~]#nginx -v
nginx version: nginx/1.24.0
[root@centos7 ~]#curl -I 127.0.0.1
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Mon, 12 Jun 2023 06:31:30 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Mon, 12 Jun 2023 06:24:27 GMT
Connection: keep-alive
ETag: "6486ba1b-264"
Accept-Ranges: bytes
#回滚
#如果升级的版本发现问题需要回滚,可以发送HUP信号,重新拉起旧版本的worker
[root@centos7 ~/nginx-1.24.0]#kill -HUP `cat /apps/nginx/run/nginx.pid.oldbin`
[root@centos7 ~/nginx-1.24.0]#pstree -p |grep nginx
|-nginx(8814)-+-nginx(12014)-+-nginx(12015)
| | `-nginx(12016)
| |-nginx(12090)
| `-nginx(12091)
#最后关闭新版的master
[root@centos7 ~/nginx-1.24.0]#kill -QUIT `cat /apps/nginx/run/nginx.pid`