HTTP 和 Nginx

MD原文档下载:百度网盘

一、HTTP协议

1.1 HTTP 协议基础

HTTP (超文本传输协议) : 浏览器和服务器之间的通信语言

基于 TCP / IP 传递数据

HTTP 属于 7 层 (应用层) 协议 , TCP 属于 4 层 (传输层) 协议 , IP 属于 3 层 (网络层) 协议

HTTP 协议工作在 客户端 - 服务器 (Client - Server) 架构 , 浏览器作为 HTTP 客户端 , 通过 URL 向 HTTP 服务端 (Web 服务器) 发送请求

1.2 HTTP 三大特点

1.2.1 无连接

在 HTTP 原始设计中,每次请求结束,服务器都会主动断开 TCP 连接

每个请求都需要 建立/断开连接

Nginx 的 keepalive_timeout 配置项 可优化 HTTP 无连接设计,保持连接指定时间,指定时间内客户端发来新请求,复用这条连接

1.2.2 媒体独立

服务器不绑定、不限制客户端只能接收某一种固定格式的数据,由客户端通过请求头主动声明自己能接受哪些媒体类型,服务器按需返回对应资源

请求头的 Accept 声明客户端请求的资源类型

响应头的 Content-Type 声明服务端返回的资源类型

1.2.3 无状态

HTTP 协议对事物处理没有记忆能力,每次请求都是独立的,服务器不会保留之前请求的信息

引入 Cookie / Session 机制来记住用户

无状态 是 Web 服务器 水平扩展(横向扩容)的基础

1.3 HTTP 请求 和 响应 报文结构

1.3.1 组成部分
  1. 起始行
  2. 首部字段
  3. 消息正文
1.3.2 请求报文

请求行、请求头、空行、请求体 构成

curl -v jd.com
* Host jd.com:80 was resolved.
* IPv6: (none)
* IPv4: 111.13.149.108, 211.144.27.126, 106.39.171.134, 211.144.24.218
*   Trying 111.13.149.108:80...
* Connected to jd.com (111.13.149.108) port 80
* using HTTP/1.x
> GET / HTTP/1.1 # 请求行 (方法 + 路径 + 协议版本)
> Host: jd.com # 请求头 (键值对),此行表示请求的主机名
> User-Agent: curl/8.12.1 # 请求头 (键值对),此行表示用户使用的代理工具
> Accept: */* # 请求头 (键值对),此行表示客户端可接收的资源类型为任意
>  # 空行 (分隔符,分隔首部字段和消息正文)    # 空行下跟请求体,GET 方法为空,POST 方法为请求数据(例如用户名,密码,验证码)
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Date: Fri, 31 Jul 2026 04:03:42 GMT
< Content-Type: text/html
< Content-Length: 178
< Connection: keep-alive
< Location: https://www.jd.com
< Server: jfe
< Cache-Control: no-cache
< 
<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
1.3.3 常见请求头
请求头说明备注
Host目标主机域名HTTP/1.1 必须携带,用于在一台服务器区分多个网站
User-Agent客户端标识标识浏览器类型、版本、操作系统
Accept可接受的响应格式告诉服务端客户端期望返回的文件格式
Cookie携带 Session ID浏览器自动携带,用于会话保持
1.3.4 响应报文

状态行、响应头、空行、响应体 构成

curl -v jd.com
* Host jd.com:80 was resolved.
* IPv6: (none)
* IPv4: 111.13.149.108, 211.144.27.126, 106.39.171.134, 211.144.24.218
*   Trying 111.13.149.108:80...
* Connected to jd.com (111.13.149.108) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: jd.com
> User-Agent: curl/8.12.1
> Accept: */*
> 
* Request completely sent off
< HTTP/1.1 301 Moved Permanently # 状态行 (协议版本 + 状态码 + 描述)
< Date: Fri, 31 Jul 2026 04:03:42 GMT # 响应头 (键值对)
< Content-Type: text/html # 响应头 (键值对) 响应资源的类型
< Content-Length: 178 # 响应头 (键值对) 响应数据的长度
< Connection: keep-alive # 响应头 (键值对)
< Location: https://www.jd.com # 响应头 (键值对) 重定向指向的新主机名
< Server: jfe # 响应头 (键值对)
< Cache-Control: no-cache # 响应头 (键值对)
<  # 空行 (分隔符,分隔响应头部和响应数据)
<html> # 此行及下方内容为 响应体 (实际传输的数据)
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
1.3.5 常见响应头
响应头说明备注
Content-Type响应体格式告诉浏览器如何解析内容
Content-Length响应体大小响应体的字节数
Location重定向目标配合 301 / 302 使用,指定跳转主机域名
Set-Cookie设置 Cookie服务端下发 Cookie 给客户端
X-Frame-Options防点击劫持禁止页面嵌入 iframe
X-Content-Type-Options防 MIME 嗅探禁止浏览器自动推断文件类型
Server服务器软件信息标识 Web 服务器类型和版本
Cache-Control缓存策略告诉浏览器缓存多少秒

1.4 HTTP 请求方法

方法含义幂等性使用场景
GET请求资源查看列表,查看详情,下载文件
POST提交数据创建订单,登录提交,发布评论
PUT全量更新更新完整用户信息,替换文件
PATCH部分更新修改手机号,修改状态
DELETE删除资源删除用户,删除文件
OPTIONS预检请求跨域请求前的探测,查询服务器支持的方法

幂等性: 多次执行同一操作,产生的结果相同

1.5 HTTP 状态码

类型:

分类范围说明
1xx100-199信息提示
2xx200-299成功
3xx300-399重定向
4xx400-499客户端错误
5xx500-599服务端错误

高频状态码:

状态码说明备注
200请求成功
301永久重定向资源永久迁移到新地址,浏览器会缓存这个跳转,下次直接访问新地址
302临时重定向资源临时迁移到新地址,浏览器不会缓存,下次仍访问原地址
304未修改(缓存命中)资源未修改,浏览器可用使用本地缓存
400请求语法错误服务端无法理解请求,通常是参数格式不对
401未认证请求需要用户身份认证
403禁止访问服务端理解请求,但拒绝执行.例如普通用户访问管理页,或访问文件 Nginx 无权限读取
404资源不存在服务端找不到请求的资源
429请求过多(限流)客户端在限定时间发送了太多请求
500服务器内部错误服务端代码执行出错,需要查看后端服务日志(配置错误,依赖库异常)
502网关错误网关从后端服务收到无效响应,与后端通信异常1例如后端 Java 服务宕机,Nginx 无法连接,检查后端是否存活,端口是否监听
503服务不可用服务端过载或正在维护,检查后端负载,限流配置
504网关超时网关等待后端服务响应超时,检查后端响应时间,调大 proxy_read_timeout

1.6 Cookie 与 Session

用于记住用户的登录状态,解决 HTTP 的无状态

会话保持流程:

  1. 用户提交账号密码 → 服务端验证通过
  2. 服务端创建 Session (存储用户身份、权限等信息),生成唯一的 Session ID
  3. 服务端通过 Set-Cookie 响应头将 JSESSIONID= 下发给浏览器
  4. 浏览器将 Session ID 保存在 Cookie 中
  5. 后续每次请求,浏览器自动通过 Cookie 请求头携带 Session ID
  6. 服务端根据 Session ID 找到对应 Session 数据 → 识别用户身份

Cookie 只能浏览器使用

1.6.1 生产环境 Session 存储问题

单机环境: Session 存本地内存 (默认) 或文件,没有问题

负载均衡(多台服务器): Session 集中存储 (Redis / 数据库)

1.6.2 Token 及 JWT

Token 分为普通 Token 和 特殊Token JWT

普通 Token 大部分机制与 Session 一致,只是返回首部头不一样,Token 同时支持微服务使用

JWT无需数据库, 生成JWT保存在客户端,服务端对 JWT 进行签名防篡改

1.7 HTTPS 与 TLS

HTTP 使用明文传输

HTTPS = HTTP + TLS

1.7.1 对称加密和非对称加密
对比纬度对称加密非对称加密
密钥使用同一把密钥加密使用公钥(公开),解密使用私钥(保密)
速度慢(比对称加密慢百倍以上)
代表算法AES,ChaCha20,DESRSA,ECC(椭圆曲线)
用途加密实际传输的数据安全传递对称加密的密钥

实际应用是: 非对称密钥负责安全传递 “对称密钥” ,对称密钥负责快速加密所有数据

公钥负责加密,私钥负责解密

私钥负责签名,公钥负责验证

1.7.2 TLS 握手流程
  1. ClientHello : 客户端发送 支持的TLS版本、加密套件列表、一个随机数 (Client Random)
  2. ServerHello : 服务器回应 选定的加密套件、一个随机数 (Server Random)、服务端数字证书
  3. 客户端验证证书 : 浏览器验证证书链 (域名匹配、有效期、签发者可信、未吊销)
  4. 密钥交换 : 客户端生成 Pre-Master Secret,用服务端数字证书携带的公钥加密后发给服务器
  5. 生成会话密钥 : 双方用 Client Random + Server Random + Pre-Master Secret 计算出 会话密钥 (Master Secret)
  6. 加密通信 : 双方使用 会话密钥 开始加密 HTTP 请求和响应

数字证书包括: 域名 + 网站公钥 + CA 签名

通过 哈希摘要 + 非对称签名 实现防篡改

CA 使用私钥对 TBS(待签名数据) 计算的哈希摘要进行签名,将签名算法和签名值追加到 TBS 后方生成数字证书

1.7.3 证书链
证书类型说明签发者存放位置
根 CA 证书 (Root CA)信任锚点,是整个信任链的起点自签浏览器 / 系统内置 (预置信任)
中间 CA 证书 (Intermediate CA)根 CA 授权给中间 CA,用于签发服务器证书根 CA随服务器证书一起下发
服务器证书 (Server Certificate)最终签发给域名的证书,包含 域名 + 服务端公钥 + CA 签名中间 CAWeb 服务器上配置

通配符证书 : *.域名,匹配所有子域名,无需为每个子域名单独购买证书

中间 CA 的作用 : 根 CA 不用于直接签发服务器证书,只签发中间 CA,这样根 CA 可以离线保护根 CA 的私钥,更安全

二、Nginx

2.1 Nginx 相关概念

2.1.1 Nginx 定位

Nginx 可作为独立的 Web 服务端,更是 “流量入口

Nginx 负责 接收请求、返回静态页面、转发动态请求,各种后端服务负责处理业务逻辑、操作数据库

2.1.2 nginx 架构
2.1.2.1 Master - Worker 进程
进程职责数量关键特定
Master读取/校验配置,监听端口,管理 Worker 进程1以 root 用户运行,不处理客户端请求
Worker接收并处理客户端请求= CPU 核心数以 nginx / www-data 用户运行,每个 Worker 独立,内存隔离
# 启动 Nginx 后查看进程树
ps auxf | grep nginx
2.1.2.2 epoll 事件驱动模型

三种内核 I / O 模型:

对比维度BIO (阻塞 IO)select / pollepoll
并发连接数低 (受线程数限制)中 (select 有 1024 限制)高(数万)
CPU 占用高 (线程切换)高 (轮询扫描)低 (事件通知)
内存占用极高 (每个连接建立一个线程)
时间复杂度O(n)O(n)O(1)
适用场景连接数 < 100连接数 < 1000高并发生产环境
使用应用Apache (prefork 模式)早期 Unix 网络程序Nginx、Redis

Nginx 默认使用 epoll 非阻塞模型

并发连接数=RPS/响应时间

建立连接 和 事件处理

2.2 Nginx 部署

2.2.1 包安装

测试环境使用

# 建议安装基础工具
dnf install -y curl wget vim net-tools tar git
apt install -y curl wget vim git

# 测试环境关闭防火墙
systemctl disable --now firewalld

# 安装 nginx
dnf install -y nginx
apt update;apt install -y nginx

# 查看版本
nginx -v

# Rocky 启动服务
systemctl enable --now nginx

# 查看服务状态
systemctl status nginx

# 查看端口监听
ss -ntlp | grep nginx
2.2.2 编译安装

源码获取

生产环境推荐,可自定义安装版本,可按需添加模块,路径标准化

编译时推荐 静态编译 , 模块嵌入 nginx 二进制程序,自动加载,模块与 nginx 版本精确匹配

测试环境推荐编译模块

模块用途使用场景
echo-nginx-module输出调试信息测试 location 匹配,调试配置
headers-more-nginx-module修改 请求 / 响应头添加、修改、删除 HTTP 头
nginx-http-flv-module视频流推送直播推流,视频点播
ngx_brotliBrotli 压缩比 gizp 压缩率更高
nginx-module-vts流量统计监控每个虚拟机的请求数、流量
# 安装编译依赖
dnf install -y gcc make pcre2-devel zlib-devel openssl-devel git

# 下载源码包和第三方模块
cd /usr/local/src/
wget https://nginx.org/download/nginx-1.30.4.tar.gz
git clone https://github.com/openresty/echo-nginx-module.git

# 创建用户
useradd -s /sbin/nologin -r nginx

# 解压缩
tar xf nginx-1.30.4.tar.gz

# 静态编译
cd nginx-1.30.4/
./configure \
--prefix=/usr/local/nginx \
--sbin-path=/usr/sbin/nginx \
--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 \
--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 \
--add-module=/usr/local/src/echo-nginx-module

# 编译安装
make -j$(nproc)
make install

# 查看编译参数验证模块是否编译成功
/usr/sbin/nginx -V

# 创建 systemd 服务文件
tee /etc/systemd/system/nginx.service <<'EOF'
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target
EOF

# 启动服务
systemctl daemon-reload
systemctl enable --now nginx

# 查看服务状态
systemctl status nginx

# 查看端口监听
ss -ntlp | grep nginx

脚本编译安装

文件见网盘

# 进入安装文件放置目录
cd /usr/local/src/

# 放入安装文件

# 运行安装脚本
bash install_nginx.sh

2.3 nginx 原生管理方式

# 直接启动 Nginx
/usr/sbin/nginx

# 强制终止 Nginx
/usr/sbin/nginx -s stop

# 优雅停止 Nginx (完成当前请求后退出)
/usr/sbin/nginx -s quit

# 重载配置 (不重启服务重新加载)
/usr/sbin/nginx -s reload

# 重新打开日志文件 (用于日志切割)
/usr/sbin/nginx -s reopen

2.4 Nginx 平滑升级

在不停止 Nginx 服务的情况下,替换原有二进制文件

原理:

  1. 旧 Master 进程启动新 Master 进程
  2. 新 Master 进程启动新 Woeker 进程
  3. 新 Worker 进程接管新连接
  4. 旧 Worker 进程处理完现有请求后退出
2.4.1 查看旧版本编译参数

平滑升级时,新版本必须和旧版本使用完全相同的编译参数,否则新 Master 进程可能因为路径、模块、启用功能不匹配而启动失败

# 查看旧版本编译参数
nginx -V
2.4.2 平滑升级示例
# 模拟用户持续访问
# 在 nginx 服务器 html/ 目录下生成测试文件
dd if=/dev/zero of=/apps/nginx/html/test.img bs=1M count=100
# 以限定速度下载测试文件,模拟用户持续连接
wget --limit-rate=1k http://10.0.0.221/test.img

# 查看当前 Nginx 版本
curl -I http://10.0.0.210

# 备份当前二进制文件
mv /usr/sbin/nginx /usr/sbin/nginx.old

# 编译新版本,注意只编译获取二进制文件,不安装
cd /usr/local/src/\
wget https://nginx.org/download/nginx-1.30.4.tar.gz
tar xf nginx-1.30.4.tar.gz
./configure \
--prefix=/usr/local/nginx \
--sbin-path=/usr/sbin/nginx \
--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 \
--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 \
--add-module=/usr/local/src/echo-nginx-module
make -j$(nproc)

# 复制编译完成的二进制文件
cp objs/nginx /usr/sbin/nginx

# 用新版本二进制文件做配置文件语法检查,查看是否有报错
nginx -t

# 向旧 Master 进程发送 USR2 信号,启动新 Master 进程
kill -USR2 $(cat /var/run/nginx.pid)
# 此时如果有新请求,仍由旧版本提供服务
curl -I http://10.0.0.210
# 此时新旧 Nginx 并存 
ps aux | grep nginx

# 向旧 Master 进程发送 WINCH 信号,停止旧 Worker 进程接收新连接
kill -WINCH $(cat /var/run/nginx.pid.oldbin)
# 此时如果有新请求,由新版本提供服务
curl -I http://10.0.0.221
# 此时前面模拟的用户持续连接未中断
# 此时旧 Worker 进程因仍有用户连接未退出
ps aux | grep nginx
# 取消模拟的用户持续连接
Ctrl + C
# 此时旧 Worker 进程处理完所有现有连接退出
ps aux | grep nginx

# 此时测试业务是否正常运行,没问题执行升级,否则回滚

# 升级
# 向旧 Master 进程发送 QUIT 信号,旧 Master 进程退出
kill -QUIT $(cat /var/run/nginx.pid.oldbin)

# 此时旧 Master 进程退出,只剩下新 Master 进程和 Worker 进程
ps aux | grep nginx

# 验证 Nginx 版本
nginx -v

# 回滚
# 向旧 Master 进程发送 HUP 信号,重新拉起旧版本的 worker 进程
kill -HUP `cat /apps/nginx/logs/nginx.pid.oldbin`

# 向新 Master 进程发送 QUIT 信号,退出新版本 Master 进程
kill -QUIT `cat /apps/nginx/logs/nginx.pid`

# 恢复旧版本二进制文件
mv /usr/sbin/nginx.old /usr/sbin/nginx

# 验证 Nginx 版本
nginx -v

2.5 Nginx 基础配置

主配置文件: /etc/nginx/nginx.conf

子配置文件: 通过在 http 块添加 include 指定路径,可以实现按业务创建配置文件

# 查看 Nginx 主配置文件的有效行
grep -Ev '^\s*#|^\s*$' /etc/nginx/nginx.conf

2.5.1 配置文件的层级结构

配置块作用范围职责
main全局Nginx 整体运行参数 (用户、Worker 进程数、PID文件)
events全局网络连接参数 (事件模型、最大连接数)
http全局HTTP 通用配置 (MIME、日志、gzip)
server虚拟主机http块的子配置块,定义网站 (域名、端口)
locationURL 路径server块的子配置块,匹配 URL 并执行处理

配置文件中的相对路径是相对于安装时编译参数 --prefix=/usr/local/nginx 指定的路径

2.5.2 main 块配置
# 编辑主配置文件
vim /etc/nginx/nginx.conf
# 修改 Worker 进程数为 auto ,自动匹配 CPU 核心数
worker_processes  auto;

# 修改后校验语法错误
nginx -t

# 重载配置
systemctl reload nginx.service

# 查看 Worker 进程数
ps aux | grep nginx
2.5.3 events 块配置
vim /etc/nginx/nginx.conf
# Nginx 默认使用 epoll 模型,添加此行只是做显性配置
use epoll;
# 修改单个 Worker 进程最大连接数
worker_connections  10240;

nginx -t
systemctl reload nginx.service
2.5.4 http 块配置
# TCP 连接存活时长,实现复用连接
keepalive_timeout  65;

# 关闭响应报文头中显示 Nginx 版本
server_tokens off;

# 指定子配置文件路径
include     /etc/nginx/conf.d/*.conf;
2.5.5 server 块虚拟主机配置

每个 server 块对应一个虚拟主机,用于实现在一台物理服务器同时运行多个独立网站

每个网站相互隔离,拥有独立的域名、根目录和配置文件

2.5.5.1 虚拟主机类型

通过 listenserver_name 配置虚拟主机类型

类型区分依据配置指令使用场景
基于域名请求头的 Host 字段server_name同一 IP 和端口下运行多个网站 (常用)
基于 IP请求的目标 IP 地址listen IP:port服务器绑定多个 IP,每个 IP 对应不同站点
基于端口请求的目标端口号listen port同一 IP 不同端口对应不同服务,如管理后台

基于域名示例:

# 访问 www.test.org 走这个
server {
	listen 80;
	server_name www.test.org;
	root /var/www/test;
}

# 访问 blog.test.com 走这个
server {
	listen 80;
	server_name blog.test.org;
	root /var/www/blog;
}

基于 IP 示例:

# 访问 1.1.1.1 走这个
server {
	listen 1.1.1.1:80;
	server_name _;
	root /var/www/test1;
}

# 访问 2.2.2.2 走这个
server {
	listen 2.2.2.2:80;
	server_name _;
	root /var/www/test2;
}

基于端口示例:

# 访问 80 端口走这个(对外网站)
server {
listen 80;
server_name _;
root /var/www/test;
}

# 访问 3366 端口走这个(管理后台)
server {
listen 3366;
server_name _;
root /var/www/admin;
}
2.5.5.2 基于域名案例
# 创建网站根目录
mkdir -p /webtest/{pc,mobile,app}

# 创建测试页
echo "pc web" > /webtest/pc/index.html
echo "mobile web" > /webtest/mobile/index.html

# 编辑主配置文件在 http 块中添加子配置文件路径
vim /etc/nginx/nginx.conf
include     /webtest/*.conf;

# 创建子域名 pc 配置文件
vim /webtest/pc.conf
server {
  listen       80;
  server_name  pc.test.org;
  location / {
    root   /webtest/pc;
    index  index.html;
  }
}

# 创建子域名 mobile 配置文件
vim /webtest/mobile.conf
server {
  listen       80;
  server_name  mobile.test.org;
  location / {
    root   /webtest/mobile;
    index  index.html;
  }
}

# 测试配置文件是否有语法错误并完整输出配置文件内容
nginx -T

# 校验语法错误
nginx -t

# 重载 Nginx 配置
systemctl reload nginx

# 测试, curl 通过 -H 携带指定请求头
curl 10.0.0.210 -H "Host: pc.test.org"
curl 10.0.0.210 -H "Host: moble.test.org"
grep -Ev "^;|^$" /etc/php-fpm.d/www.conf
2.5.6 location 块配置
2.5.6.1 location 匹配规则

location 决定了如何响应不同的请求

优先级匹配类型语法示例匹配后行为
1精确匹配= /pathlocation = /health立即停止
2前缀优先匹配(不区分大小写)^~ /pathlocation ^~ /static/停止正则匹配
3包含,正则匹配(区分大小写)~ /patternlocation ~ \.php$按顺序匹配
4包含,正则匹配(不区分大小写)~* /patternlocation ~* \.jpg$按顺序匹配
5通用前缀匹配/pathlocation /api/最长匹配
6通用匹配/location /兜底
2.5.6.2 匹配规则示例

使用 echo 模块测试

# 创建测试配置文件
tee /etc/nginx/conf.d/location-test.conf <<'EOF'
server {
    listen 80;
    server_name location.deng.org;

    access_log /var/log/nginx/location_test_access.log main;
    error_log /var/log/nginx/location_test_error.log warn;

    # 1. 精确匹配(最高优先级)
    location = /health {
        echo "精确匹配(=):/health";
    }

    # 2. 前缀优先匹配(匹配后停止正则)
    location ^~ /static/ {
        echo "前缀优先匹配(^~):/static/ 下的所有请求";
    }

    # 3. 正则匹配(区分大小写)
    location ~ \.php$ {
        echo "正则匹配(~):.php 结尾的请求";
    }

    # 4. 正则匹配(不区分大小写)
    location ~* \.jpg$ {
        echo "正则匹配(~*):.jpg 或 .JPG 结尾的请求";
    }

    # 5. 通用前缀匹配(最长匹配原则)
    location /api/v1/ {
        echo "通用前缀匹配:/api/v1/(更长的匹配)";
    }

    location /api/ {
        echo "通用前缀匹配:/api/(较短的匹配)";
    }

    # 6. 通用匹配(兜底)
    location / {
        echo "通用匹配(/):所有未被匹配的请求";
    }
}
EOF

vim /etc/hosts
10.0.0.210 location.deng.org

# 精确匹配配置 1
curl location.deng.org/health

# 前缀匹配配置 2
curl location.deng.org/static/111/222

# 后缀匹配配置 3
curl location.deng.org/xxx/111/222.php
# 配置 3 区分大小写,大写后缀不匹配
curl location.deng.org/xxx/111/222.PHP

# 后缀匹配配置 4 ,不区分大小写
curl location.deng.org/xxx/111/222.JPG

# 访问 /api ,匹配内容更长的
curl location.deng.org/api/v1/111
curl location.deng.org/api/111

# 不能匹配其他配置,都匹配 /
curl location.deng.org
2.5.6.3 rootalias

两者都用于指定文件路径,单拼接方式不同

  • root : root 路径 + location 路径
  • alias : alias 路径 替换 location 路径,使用时路径末尾必须加 / ,否则会路径拼接错误

实验验证

# 创建测试文件
mkdir -p /var/www/static/{root-test,img}
echo "root test" > /var/www/static/root-test/test.txt
echo "alias test" > /var/www/static/img/test.txt

# 创建虚拟主机
tee /etc/nginx/conf.d/root-alias-test.conf <<'EOF'
server {
    listen 80;
    server_name test.deng.org;

    location /root-test/ {
        root /var/www/static;
    }

    location /alias-test/ {
        alias /var/www/static/img/;
    }
}
EOF

# 校验语法,成功后重载 Nginx 配置
nginx -t && systemctl reload nginx

# Windows 打开 SwitchHosts 添加一条解析记录
10.0.0.210 test.deng.org

# 浏览器访问
http://test.deng.org/root-test/test.txt
# 输出 /var/www/static/root-test/test.txt 内容

# 浏览器访问
http://test.deng.org/alias-test/test.txt
# 输出 /var/www/static/img/test.txt 内容,将 /alias-test/ 替换为 /var/www/static/img/

2.6 案例: 部署 PHP 应用 WordPress

2.6.1 整体架构
层级组件作用
接入层Nginx接收用户请求,转发 .php 请求给 PHP-FPM
应用层PHP-FPM执行 WordPress 的 PHP 代码
数据层MySQL存储 WordPress 的数据

先参考上方编译安装部署 Nginx

2.6.2 安装 MySQL
# 安装 MySQL
dnf install -y mysql8.4-server
apt install -y mysql-server

# 启动 MySQL
systemctl enable --now mysqld
systemctl enable --now mysql

# 查看状态
systemctl status mysqld
systemctl status mysql

# 登录数据库创建数据库、用户、授权
mysql
CREATE DATABASE wordpress;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY '123456';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
quit
2.6.3 部署 PHP-FPM
# Rocky 10 部署
# 安装 PHP-FPM
dnf install -y php php-fpm php-mysqlnd php-gd php-xml php-mbstring

# 启动 PHP-FPM
systemctl enable --now php-fpm.service

# 查看 Socket 文件
ls /run/php-fpm/www.sock

# 查看进程
ps aux | grep php-fpm
2.6.4 下载并配置 WordPress
# 下载并解压 WordPress
wget https://cn.wordpress.org/latest-zh_CN.zip
unzip latest-zh_CN.zip

# 复制文件到网站目录
mkdir -p /var/www/wordpress
cp -r wordpress/* /var/www/wordpress

# 设置权限
chown -R nginx:nginx /var/www/wordpress
chmod -R 755 /var/www/wordpress

# 创建配置文件并配置数据库
cp /var/www/wordpress/wp-config-sample.php /var/www/wordpress/wp-config.php 
vim /var/www/wordpress/wp-config.php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', '123456' );
define( 'DB_HOST', 'localhost' );
2.6.5 Nginx 配置
# 编辑主配置文件
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"';

# 在 http 块中添加子配置文件路径
include     /etc/nginx/conf.d/*.conf;

创建虚拟主机

tee /etc/nginx/conf.d/wordpress.conf <<'EOF'
server {
    listen 80;
    server_name wordpress.deng.org;

    root /var/www/wordpress;
    index index.php index.html;

    access_log /var/log/nginx/wordpress_access.log main;
    error_log /var/log/nginx/wordpress_error.log warn;

    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }

    location = /robots.txt {
        log_not_found off;
        access_log off;
    }

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}
EOF

nginx -t
systemctl reload nginx
2.6.6 验证并配置 WordPress
# Windows 打开 SwitchHosts 添加一条解析记录
10.0.0.210 wordpress.deng.org

浏览器访问 http://wordpress.deng.org 完成配置

2.6.7 PHP-FPM 连接方式对比
  • TCP 端口 : 有网络开销,跨主机连接使用
  • Socket : 无网络开销,仅限本机使用,同主机连接推荐
# PHP-FPM 配置

# 编辑配置文件
vim /etc/php-fpm.d/www.conf

# Socket 方式,默认
listen = /run/php-fpm/www.sock

# 端口方式
listen = 9000
# 端口模式,开启此配置项表示只允许本机连接,不开启则任何主机都可以连接
listen.allowed_clients = 127.0.0.1
# Nginx 配置

# Socket 方式
location ~ \.php$ {
	fastcgi_pass unix:/run/php-fpm/www.sock;
	include fastcgi_params;
}

# 端口方式
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
}
2.6.8 PHP-FPM 进程管理
模式说明使用场景
static固定子进程数,启动时创建 pm.max_children 配置项指定个子进程高并发、内存充足
dynamic动态调整,根据负载在 pm.min_spare_serverspm.max_children 之间调整大多数场景(默认)
ondemand按需创建,空闲进程在 pm.process_idle_timeout 指定时间后退出低并发、内存敏感
# 编辑配置文件
vim /etc/php-fpm.d/www.conf

# 必须项,指定管理模式
pm = dynamic

# static 模式配置
pm.max_children = 50 ; 固定50个子进程

# dynamic 模式配置
pm.max_children = 50 ; 最大子进程数
pm.start_servers = 5 ; 启动时创建子进程数
pm.min_spare_servers = 5 ; 最少空闲时子进程数
pm.max_spare_servers = 35 ; 最大空闲时子进程数

# ondemand 模式配置
pm.max_children = 50
pm.process_idle_timeout = 10s ; 空闲 10 秒后退出

# 查看 PHP-FPM 进程数
ps aux | grep php-fpm | grep -v grep | wc -l
# 进程数计算
pm.max_children = (总内存 - 系统占用内存) / 单个 PHP-FPM 进程占用内存

# 示例,服务器 16GB 内存
系统占用 2GB
单个 PHP-FPM 进程占用内存 70 - 90 MB
(16GB - 2GB) / 80MB ≈ 180
保守建议: pm.max_children = 150
2.6.9 PHP-FPM 状态页
# 编辑配置文件,开启状态页
vim /etc/php-fpm.d/www.conf
pm.status_path = /status

# 重载 PHP-FPM 配置
systemctl reload php-fpm

# 编辑虚拟主机配置
vim /etc/nginx/conf.d/wordpress.conf

# 添加 状态页
	location = /status {        
        allow 127.0.0.1;        
        deny all;
        fastcgi_pass unix:/run/php-fpm/www.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

# 重载 Nginx 配置
systemctl reload nginx

# 测试访问状态页
curl http://127.0.0.1/status -H "Host: wordpress.deng.org"

2.7 案例: 部署 Python 应用

# Rocky 10

# 安装 python 和 pip
dnf install -y python3 python3-pip

# 安装 gunicorn 和 flask
pip3 install gunicorn flask

# 创建应用目录
mkdir -p /var/www/flask-app

# 创建 flask 应用
tee /var/www/flask-app/app.py <<'EOF'
#!/usr/bin/env python3
from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route('/')
def hello():
    return jsonify({
        'message': 'Hello from Flask!',
        'status': 'success'
    })

@app.route('/api/user/<int:uid>')
def get_user(uid):
    return jsonify({
        'uid': uid,
        'name': f'User_{uid}',
        'email': f'user{uid}@qq.com'
    })

@app.route('/api/health')
def health():
    return jsonify({'status': 'ok'})

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8000)
EOF

# 启动 gunicorn , 指定工作进程数、绑定地址和端口、模块名和实例名、运行方式为后台运行
cd /var/www/flask-app ; gunicorn -w 4 -b 127.0.0.1:8000 app:app --daemon

# 验证 gunicorn 是否启动
ss -ntlp | grep 8000

# Nginx 配置

# 编辑主配置文件
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"';

# 在 http 块中添加子配置文件路径
include     /etc/nginx/conf.d/*.conf;

# 配置 Nginx 代理 Python 应用
tee /etc/nginx/conf.d/flask.conf <<'EOF'
server {
    listen 80;
    server_name flask.deng.org;
    
    access_log /var/log/nginx/flask_access.log main;
    error_log /var/log/nginx/flask_error.log warn;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        proxy_connect_timeout 60s;
        proxy_send_timeout 60s;
        proxy_read_timeout 60s;
    }
    
    location /api/ {
        proxy_pass http://127.0.0.1:8000/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}
EOF

# 校验语法,成功后重载 Nginx 配置
nginx -t && systemctl reload nginx

# Windows 打开 SwitchHosts 添加一条解析记录
10.0.0.210 flask.deng.org

# 浏览器访问验证,正常输出 JSON 数据
http://flask.deng.org
http://flask.deng.org/api/user/100

三、Nginx 反向代理和 LB

3.1 相关概念

3.1.1 正向代理 vs 反向代理
对比纬度正向代理反向代理
代理对象客户端服务端
配置端客户端服务端
隐藏IP客户端真实 IP服务端真实 IP
使用场景公司内网通过代理访问外网流量入口将请求转发给后端应用
3.1.2 反向代理的核心价值
问题Nginx 的解决方案价值
后端直接暴露不安全后端只监听在内网或本机,Nginx 做唯一入口安全
多个应用需要统一入口根据域名/路径转发到不同后端统一管理
SSL 证书需要在每个应用配置SSL 在 Nginx 部署简化运维
静态请求和动态请求混合静态请求由 Nginx 处理直接返回性能优化
单点故障后端多实例,Nginx 做负载均衡高可用
3.1.3 负载均衡 (LB) 的核心价值
价值说明
高可用一台后端宕机,自动切换其他后端 (健康检查)
高并发多台后端分担请求,整体处理能力提升
弹性扩展可动态扩缩容后端节点
灰度发布部分后端运行新版,逐步切流

3.2 测试环境准备

3.2.1 节点初始化
# 初始化环境

# 修改各节点主机名
hostnamectl set-hostname lb1
hostnamectl set-hostname backend1
hostnamectl set-hostname backend2
hostnamectl set-hostname backend3

# 添加本地解析记录
vim /etc/hosts
10.0.0.210 lb1
10.0.0.211 backend1
10.0.0.212 backend2
10.0.0.213 backend3
3.2.2 Nginx 初始化
# 编辑主配置文件
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"';

# 在 http 块中添加子配置文件路径
include     /etc/nginx/conf.d/*.conf;

# 创建子配置文件目录
mkdir /etc/nginx/conf.d
3.2.3 模拟后端服务
# backend 1
# 创建测试页
mkdir -p /var/www/backend/api
echo "Backend 1 (10.0.0.211)" > /var/www/backend/index.html
echo '{"code":200,"data":"Backend 1"}' > /var/www/backend/api/user

# 配置 Nginx 虚拟主机监听 8080 端口
tee /etc/nginx/conf.d/backend.conf <<'EOF'
server {
    listen 8080;
    server_name backend;
    root /var/www/backend;
    index index.html;
    
    access_log /var/log/nginx/backend_access.log main;
    error_log /var/log/nginx/backend_error.log warn;
    
}
EOF

# 校验语法成功后重载配置
nginx -t && systemctl reload nginx

# backend 2 和 backend 3 仅测试页数据不同,其他步骤一致
echo "Backend 2 (10.0.0.212)" > /var/www/backend/index.html
echo '{"code":200,"data":"Backend 2"}' > /var/www/backend/api/user

echo "Backend 3 (10.0.0.213)" > /var/www/backend/index.html
echo '{"code":200,"data":"Backend 3"}' > /var/www/backend/api/user
3.2.4 LB 静态资源
mkdir -p /var/www/nginx
echo "LB Home Page" > /var/www/nginx/index.html

3.3 示例一: 反向代理单后端

示例配置 后端应用 获取的客户端请求 IP 都是 LB

# LB 创建反向代理 虚拟主机 配置
tee /etc/nginx/conf.d/proxy-single.conf <<'EOF'
server {
	listen 80;
	server_name proxy.deng.org;
	
	location / {
		proxy_pass http://backend1:8080;
	}
}
EOF

# 校验语法成功后重载配置
nginx -t && systemctl reload nginx

# 验证

# 命令行验证
curl 10.0.0.210 -H "Host: proxy.deng.org"

# Windows 打开 SwitchHosts 添加一条解析记录
10.0.0.210 proxy.deng.org
# 浏览器访问
http://proxy.deng.org/
http://proxy.deng.org/api/user

# backend 1 查看日志,发现访问客户端都是 LB
cat /var/log/nginx/backend_access.log

3.4 示例二: 透传 客户端信息

通过添加 透传指定头部信息 将 真实客户端信息 传递给后端服务

# 配置项说明

# 在 location 块添加

# 原始 Host
proxy_set_header Host $host;
# 客户端真实 IP
proxy_set_header X-Real-IP $remote_addr;
# 代理链
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 原始协议(http/https)
proxy_set_header X-Forwarded-Proto $scheme;
# LB 虚拟主机配置 添加 透传配置项
server {
        listen 80;
        server_name proxy.deng.org;

        location / {
                proxy_pass http://backend1:8080;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }
}

# 校验语法成功后重载配置
nginx -t && systemctl reload nginx

# 验证

# 浏览器访问
http://proxy.deng.org/
# backend 1 查看日志,每条日志末尾显示真实客户端 IP (对应日志格式中 http_x_forwarded_for 变量)
cat /var/log/nginx/backend_access.log

3.5 示例三: 负载均衡

# upstream 用于定义一组后端服务器
# 格式
upstream 组名 {
	server 后端地址1 [参数];
	server 后端地址2 [参数];
	server 后端地址3 [参数];
}
# LB 配置负载均衡,使用默认调度策略 轮询
tee /etc/nginx/conf.d/proxy-lb.conf <<'EOF'
upstream backend {
	server backend1:8080;
	server backend2:8080;
	server backend3:8080;
}

server {
	listen 80;
	server_name lb.deng.org;

	# 静态资源:LB 直接返回
	location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js)$ {
		expires 30d;
		access_log off;
	}

	# API 请求:转发到后端(负载均衡)
	location /api/ {
		proxy_pass http://backend;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}

	# 其他请求:LB 直接返回静态文件,按顺序在磁盘查找文件,全部找不到执行最后一项
	location / {
		root /var/www/nginx;
		try_files $uri $uri/ /index.html;
	}
}
EOF

# 校验语法成功后重载配置
nginx -t && systemctl reload nginx

# 命令行测试
vim /etc/hosts
10.0.0.210 lb.deng.org
# 单次测试
curl -s http://lb.deng.org/api/user
# 循环测试
for i in {1..15};do curl -s http://lb.deng.org/api/user;done
# backend 查看日志,因为 轮询 策略的缘故,每台后端承担 1/后端节点总数 的请求
cat /var/log/nginx/backend_access.log

proxy_pass 后参数末尾带 / 会去掉 location 匹配的路径部分,不带 / 则原样转发

3.6 负载均衡调度算法

常见四种算法

算法配置适用场景
轮询 (round-robin)默认后端性能均等
权重 (weight)weight=N后端性能不均
ip_haship_hash;会话保存 (本地 Session)
least_connleast_conn;长连接场景 (WebSocke、SSE)
3.6.1 权重算法示例
# LB 修改负载均衡配置,在后端服务器定义给高性能后端节点配置高权重
vim /etc/nginx/conf.d/proxy-lb.conf
server backend1:8080 weight=3;
server backend2:8080 weight=1;
server backend3:8080 weight=1;

nginx -t && systemctl reload nginx

# 追踪后端节点日志
tail -f /var/log/nginx/backend_access.log

# 循环测试,查看调度策略
for i in {1..15};do curl -s http://lb.deng.org/api/user;done
# 结果符合权重配置 3:1:1 比例
3.6.2 ip_hash 算法示例

基于的客户端的 remote_addr (源地址IPv4前24位或整个IPv6地址) 做 hash 计算

# LB 修改负载均衡配置,在后端服务器定义添加 ip_hash;
vim /etc/nginx/conf.d/proxy-lb.conf
upstream backend {
        server backend1:8080;
        server backend2:8080;
        server backend3:8080;
        ip_hash;
}

nginx -t && systemctl reload nginx

# 循环测试,查看调度策略
for i in {1..15};do curl -s http://lb.deng.org/api/user;done
# 因为客户端 IP 相同,所有请求都被调度到同一个节点

3.7 被动健康检查

# LB 修改负载均衡配置,在后端服务器定义添加 max_fails=3 fail_timeout=30s
vim /etc/nginx/conf.d/proxy-lb.conf
upstream backend {
        server backend1:8080 max_fails=3 fail_timeout=30s;
        server backend2:8080 max_fails=3 fail_timeout=30s;
        server backend3:8080 max_fails=3 fail_timeout=30s;
}

nginx -t && systemctl reload nginx

# 停止一个后端服务,模拟后端服务宕机
systemctl stop nginx

# 循环测试,查看调度策略
for i in {1..15};do curl -s http://lb.deng.org/api/user;done
# 不再往宕机后端服务转发

# LB 查看错误日志,出现 3 次失败转发
tail /var/log/nginx/error.log

# 启动后端服务,模拟故障恢复
systemctl start nginx

for i in {1..15};do curl -s http://lb.deng.org/api/user;done
# 恢复故障后端转发

参数说明

参数默认值说明
max_fails1失败指定次数后将对应后端服务器标记为不可用
fail_timeout10s后端服务器被标记为不可用后,等待指定时间再次尝试转发请求,成功则恢复后端,失败则等待指定时间再次尝试

3.8 四层代理

Nginx 支持 四层代理,但一般不使用 Nginx 做四层代理

需要编译启用 stream 模块

四、HTTPS 与 安全加固

4.1 HTTPS 配置

在 LB 配置

4.1.1 确认 SSL 模块已安装
nginx -V 2>&1 | grep with-http_ssl_module
4.1.2 公网 HTTPS 案例
4.1.2.1 准备域名

dengtest.pw

4.1.2.2 购买云服务

阿里云 - 香港 -抢占式实例

Dengtest123

4.1.2.3 DNS解析

image-20260804195632526

4.1.2.4 源码部署 Nginx 及基础配置

源码部署 Nginx

# 安装依赖包
dnf install -y curl wget vim net-tools tar git gcc make pcre2-devel zlib-devel openssl-devel epel-release

# 下载源码包并解压
cd /usr/local/src/
wget https://nginx.org/download/nginx-1.30.4.tar.gz
git clone https://github.com/openresty/echo-nginx-module.git
tar xf nginx-1.30.4.tar.gz

# 创建 nginx 用户
useradd -s /sbin/nologin -r nginx


# 编译并安装
cd nginx-1.30.4/
./configure --prefix=/usr/local/nginx --sbin-path=/usr/sbin/nginx --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 --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 --add-module=/usr/local/src/echo-nginx-module
make -j$(nproc)
make install

# 创建服务文件
tee /etc/systemd/system/nginx.service <<'EOF'
[Unit]
Description=The nginx HTTP and reverse proxy server
After=network.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target
EOF

# 启动 nginx
systemctl daemon-reload && systemctl enable --now nginx

Nginx 基础配置

# 编辑主配置文件
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"';

# 在 http 块中添加子配置文件路径
include     /etc/nginx/conf.d/*.conf;

# 创建子配置文件目录
mkdir /etc/nginx/conf.d
4.1.2.5 创建虚拟主机
# 创建测试页
mkdir -p /var/www/nginx
echo "HTTPS Test..." > /var/www/nginx/index.html

# 创建虚拟主机配置
tee /etc/nginx/conf.d/proxy-lb.conf <<'EOF'
server {
    listen 80;
    server_name www.dengtest.pw;
    
    access_log /var/log/nginx/dengtest_access.log main;
    error_log /var/log/nginx/dengtest_error.log warn;
    
    location / {
        root /var/www/nginx;
        try_files $uri $uri/ /index.html;
    }
}
EOF
4.1.2.6 Let’s Encrypt 申请证书并自动部署
# 安装 Let's Encrypt 证书申请和自动部署软件包
dnf install -y certbot python3-certbot-nginx

# 申请证书并自动部署
certbot --nginx -d dengtest.pw 
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address or hit Enter to skip.
 (Enter 'c' to cancel):   # 按 回车 跳过

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at:
https://letsencrypt.org/documents/LE-SA-v1.8-July-06-2026.pdf
You must agree in order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: Y  # 按 Y 同意协议
Account registered.
Requesting a certificate for dengtest.pw

Successfully received certificate.	# 完成挑战,成功接收证书 fullchain.pem 和私钥 privkey.pem
Certificate is saved at: /etc/letsencrypt/live/dengtest.pw/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/dengtest.pw/privkey.pem
This certificate expires on 2026-11-02.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate	# 自动完成证书部署
Successfully deployed certificate for dengtest.pw to /etc/nginx/conf.d/proxy-lb.conf
Congratulations! You have successfully enabled HTTPS on https://dengtest.pw

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4.1.2.7 虚拟主机配置修改
# 修改自动生成的虚拟主机配置项,实现访问 dengtest.pw 和 www.dengtest.pw 均自动跳转到 https://www.dengtest.pw
vim /etc/nginx/conf.d/proxy-lb.conf
server {
    server_name www.dengtest.pw;

    access_log /var/log/nginx/dengtest_access.log main;
    error_log /var/log/nginx/dengtest_error.log warn;

    location / {
        root /var/www/nginx;
        try_files $uri $uri/ /index.html;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/dengtest.pw/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/dengtest.pw/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    listen 80;
    server_name dengtest.pw www.dengtest.pw;
    return 301 https://www.dengtest.pw$request_uri;
}

# 检测语法,成功后重载 Nginx 配置
nginx -t && systemctl reload nginx

# 查看 Nginx 是否开启 443 端口监听
ss -ntlp
4.1.2.8 测试

浏览器访问:

dengtest.pw

www.dengtest.pw

4.1.3 内网 HTTPS 案例

基于 3.5 已部署 Nginx 负载均衡集群

4.1.3.1 生成泛域名证书
# 在 LB 节点操作
# 安装软件包
dnf install -y openssl

# 创建证书存放目录
mkdir -p /opt/ca && cd /opt/ca

# 生成根 CA
openssl req -x509 -new -nodes -newkey rsa:4096 -keyout ca.key -out ca.crt \
-days 3650 -sha256 -subj "/C=CN/ST=Shanghai/L=Shanghai/O=WangXin/OU=IT/CN=WangXin Root CA"
chmod 400 ca.key

# 为项目生成私钥 key 和证书申请文件 csr
openssl req -new -nodes -out deng.csr -keyout deng.key \
-subj "/C=CN/ST=Shanghai/L=Shanghai/O=WangXin/OU=IT/CN=*.deng.org" \
-addext "subjectAltName=DNS:*.deng.org,DNS:deng.org"

# 用私有 CA 签发证书
openssl x509 -req -in deng.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out deng.crt -days 365 -copy_extensions copy

# 验证 SAN 是否生效
openssl x509 -in deng.crt -text -noout | grep -A 3 "Subject Alternative Name"
4.1.3.2 Nginx 使用证书
# LB 配置虚拟主机 HTTPS
vim /etc/nginx/conf.d/proxy-lb.conf
upstream backend {                      
        server backend1:8080 max_fails=3 fail_timeout=30s;
        server backend2:8080 max_fails=3 fail_timeout=30s;
        server backend3:8080 max_fails=3 fail_timeout=30s;
} 

server {
        listen 443 ssl;                 
        server_name www.deng.org;       
  
        ssl_certificate /opt/ca/deng.crt;
        ssl_certificate_key /opt/ca/deng.key;
  
        # 静态资源:LB 直接返回         
        location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js)$ {
                expires 30d;            
                access_log off;         
        }                               
  
        # API 请求:转发到后端(负载均衡)
        location /api/ {                
                proxy_pass http://backend;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }                               
  
        # 其他请求:LB 直接返回静态文件,按顺序在磁盘查找文件,全部找不到执行最后一项
        location / {                    
                root /var/www/nginx;    
                try_files $uri $uri/ /index.html;
        }                               
} 
  
server {
        listen 80;                      
        server_name www.deng.org deng.org;
        return 301 https://www.deng.org$request_uri;
}

# 检测语法,成功后重载 Nginx 配置
nginx -t && systemctl reload nginx
4.1.3.3 Windows 访问

导入私有 CA 证书文件 ca.crt

image-20260804205531875

image-20260804205551118

image-20260804205618262

image-20260804205647421

image-20260804205709733

image-20260804205730424

image-20260804205740984

image-20260804205758317

image-20260804205902124

image-20260804210712569

4.1.3.4 Linux 访问
# Rocky 复制私有 CA 证书到证书信任目录并更新证书信任
cp ca.crt /etc/pki/ca-trust/source/anchors/ && update-ca-trust

# Ubuntu 复制私有 CA 证书到证书信任目录并更新证书信任
cp ca.crt /usr/local/share/ca-certificates/ && update-ca-certificates

# 添加本地 hosts 解析记录指向 LB
vim /etc/hosts
10.0.0.210 www.deng.org deng.org

# 跟随跳转测试访问
curl -L deng.org

4.2 安全加固

4.2.1 隐藏版本号
# 在 http 块中添加 server_tokens off; 配置项,隐藏版本号
vim /etc/nginx/nginx.conf
http {
	server_tokens off;
}

# 测试访问,首部 Server 头隐藏 Nginx 版本号
curl -I lb.deng.org
Server: nginx
4.2.2 限制 HTTP 危险方法

除非对网站非常了解,明确禁止某些方法,否则不要使用

# 在 server 块添加
server {
	if ($request_method !~ ^(GET|HEAD|POST)$ ) {
		return 444;
	}
}
4.2.3 禁止目录浏览
# 新版 Nginx 默认关闭目录浏览
autoindex off;

# 如果需要开启指定目录浏览,在 location 块配置
	location /iso {
		autoindex off;
		root /var/www/nginx;
	}

4.4 防盗链

白名单机制

一般在 location 块给静态资源(图片,视频等媒体资源)配置防盗链,以节省流量

4.4.1 valid_referers 参数详解
参数说明使用场景
none没有 Referer 的请求地址栏输入、书签打开
blockedReferer 被防火墙/代理移除的请求企业防火墙、隐私插件
server_namesReferer 匹配 server_name 列表本站页面发起
ruoyi.deng.org明确指定域名从指定域名发起
*.deng.org通配符匹配子域名从指定泛域名发起
4.4.2 配置示例
vim /etc/nginx/conf.d/proxy-lb.conf
        location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js)$ {
                valid_referers none blocked server_names ruoyi.deng.org *.deng.org;	# 配置白名单
                if ($invalid_referer) {	# 非白名单请求返回 403 状态码
                        return 403;
                }
                expires 30d;
                access_log off;
        }

# 创建测试文件
mkdir /var/www/nginx/image
echo "Test Image ..." > /var/www/nginx/image/pthot.jpg

# 测试

# 正常访问
curl lb.deng.org/image/pthot.jpg

# 携带未在白名单中 Referer 请求头测试访问
curl -H "Referer: http://www.xxx.com" lb.deng.org/image/pthot.jpg
# 拒绝访问,返回 403

# 通配域名,允许访问
curl -H "Referer: http://xxx.deng.org" lb.deng.org/image/pthot.jpg

4.5 限流配置

限制客户端单位时间的请求数量,防止恶意攻击

在 http 块定义限流区域和超出容量返回规则,在动态资源和敏感请求(例如登录) 的 location 块配置限流

# 配置示例
vim /etc/nginx/conf.d/proxy-lb.conf
        # 定义限流区域,$binary_remote_addr表示限制每个客户端IP,zone=api:10m表示限流区域名称和内存缓冲池大小,rate=10r/s表示每 100ms 释放 1 个配额
        limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
        limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

upstream backend {
        server backend1:8080 max_fails=3 fail_timeout=30s;
        server backend2:8080 max_fails=3 fail_timeout=30s;
        server backend3:8080 max_fails=3 fail_timeout=30s;
}

server {
        listen 80;
        server_name lb.deng.org;

        root /var/www/nginx;

        # 自定义超出容量返回 429 响应
        error_page 503 = @rate_limit;
        location @rate_limit {
                add_header Content-Type application/json;
                return 429 '{"code":429,"message":"请求过于频繁"}';
        }

        # 静态资源:LB 直接返回
        location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js)$ {
                valid_referers none blocked server_names ruoyi.deng.org *.deng.org;
                if ($invalid_referer) {
                        return 403;
                }
                expires 30d;
                access_log off;
        }

        # 登录接口,瞬间最多允许 3 个请求,后续每秒允许 1 次(防暴力破解)
        location /api/login {
                limit_req zone=login burst=3 nodelay;
                proxy_pass http://backend/api/login;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }

        # 普通 API 请求,瞬间最多允许 20 个请求,后续 100ms 允许 1 次
        location /api/ {
                limit_req zone=api burst=20 nodelay;
                proxy_pass http://backend;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }

        # 其他请求:LB 直接返回静态文件
        location / {
                try_files $uri $uri/ /index.html;
        }
}

nginx -t && systemctl reload nginx

# 测试访问普通 API,-s 静默模式(不显示进度条和统计信息),-o /dev/null 丢弃响应内容(只看状态码),-w "%{http_code}\n" 输出 HTTP 状态码
for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" http://lb.deng.org/api/user ;done | sort | uniq -c
     24 200
     26 429
# 测试访问登录 API
for i in {1..50}; do curl -s -o /dev/null -w "%{http_code}\n" http://lb.deng.org/api/login ;done | sort | uniq -c
      4 404
     46 429

4.6 综合配置案例

# 主配置文件 /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
server_tokens off;

events {
	worker_connections 10240;
}

http {
	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	# ===== 限流定义 =====
	limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
	limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;

	# ===== 自定义 429 响应 =====
	error_page 503 = @rate_limit;
	location @rate_limit {
		add_header Content-Type application/json;
		return 429 '{"code":429,"message":"请求过于频繁"}';
	}
	
	# ===== 日志格式 =====
    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;
	error_log /var/log/nginx/error.log warn;

	# ===== 禁止目录浏览 =====
	autoindex off;
	
	include /etc/nginx/conf.d/*.conf;
}
# 子配置文件 /etc/nginx/conf.d/ruoyi-https.conf
# ===== 定义后端服务 =====
upstream ruoyi_backend {
	server ruoyi_backend1:8080;
	server ruoyi_backend2:8080;
	server ruoyi_backend3:8080;
}

server {
	listen 443 ssl http2;
	server_name ruoyi.deng.org deng.org;

	# ===== 私有 CA 证书 =====
	ssl_certificate /opt/ca/certs/deng.org/deng.crt;
	ssl_certificate_key /opt/ca/certs/deng.org/deng.key;

	# ===== TLS 优化 =====
	ssl_protocols TLSv1.2 TLSv1.3;
	ssl_ciphers HIGH:!aNULL:!MD5;
	ssl_prefer_server_ciphers on;

	# ===== 安全响应头 =====
	add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
	add_header X-Frame-Options "SAMEORIGIN" always;
	add_header X-Content-Type-Options "nosniff" always;
	server_tokens off;

	# ===== 防盗链:静态资源由 LB 直接返回 =====
	location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js)$ {
		root /var/www/nginx;
		valid_referers none blocked server_names ruoyi.deng.org deng.org *.deng.org;
		if ($invalid_referer) {
			return 403;
		}
		expires 30d;
		access_log off;
	}

	# ===== 登录接口限流 =====
	location /api/login {
		limit_req zone=login burst=3 nodelay;
		proxy_pass http://ruoyi_backend/api/login;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}
	
	# ===== API 请求限流 =====
	location /api/ {
		limit_req zone=api burst=20 nodelay;
		proxy_pass http://ruoyi_backend;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
	}
	
	# ===== 其他请求:LB 直接返回 =====
	location / {
		root /var/www/nginx;
		try_files $uri $uri/ /index.html;
	}
}
	
# ===== HTTP 跳转 HTTPS =====
server {
	listen 80;
	server_name ruoyi.deng.org deng.org;
	return 301 https://$host$request_uri;
}

五、日志管理

5.1 日志类型

  • 访问日志: 默认文件位置 /var/log/nginx/access.log , 记录每次请求的详细信息
  • 错误日志: 默认文件位置 /var/log/nginx/error.log , 记录 Nginx 运行中的错误和警告信息

5.2 访问日志格式

vim /etc/nginx/nginx.conf
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"';

    #access_log  logs/access.log  main;
}
# 完整日志格式,含性能统计
    log_format detailed '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for" '
                        'rt=$request_time uct="$upstream_connect_time" '
                        'urt="$upstream_response_time" uaddr="$upstream_addr"';

5.3 访问日志变量解析

变量说明输出示例排障价值
$remote_addr客户端 IP10.0.0.240定位访问来源
$remote_user认证用户名admin审计用户行为
$time_local本地时间05/Aug/2026:13:10:22 +0800确定请求时间
$request完整请求行GET /api/login HTTP/1.1查看具体请求
$statusHTTP 状态码200判断请求是否成功
$body_bytes_sent响应体大小32流量统计
$http_referer来源页面http://bl.deng.org/来源分析/防盗链
$http_user_agent用户代理信息Mozilla/5.0 …客户端统计
$http_x_forwarded_for客户端真实 IP 链10.0.0.240代理场景溯源
$request_time请求总耗时,单位秒0.002性能分析
$upstream_addr后端地址10.0.0.211:8080确认请求转发
$upstream_response_time后端响应时间0.001后端性能分析
$upstream_connect_time连接后端耗时0.000网络问题排查

5.4 错误日志级别

级别说明生产环境配置
debug1调试信息不推荐
info2一般信息不推荐
notice3正常但重要不推荐
warn4警告可用
error5错误推荐
crit6严重错误推荐
alert7需要立即处理推荐
emerg8系统不可用推荐

配置建议

# 主配置文件
error_log /var/log/nginx/error.log error;

# 开发调试
error_log /var/log/nginx/error.log debug;

# 虚拟主机独立日志
error_log /var/log/nginx/ruoyi_error.log warn;

常见错误日志解析

错误信息含义解决方案
permission denied文件权限不足chmod 755chown nginx:nginx
connect() failed (111: Connection refused)后端服务未启动启动后端服务
connect() failed (113: No route to host)网络不通检查防火墙/路由
SSL_CTX_use_PrivateKey_file failed证书私钥不匹配查看证书和私钥是否匹配
upstream timed out后端响应超时增加 proxy_read_timeout
client intended to send too large body请求头过大增加 client_max_body_size

5.5 配置日志示例

# 主配置文件定义日志格式
vim /etc/nginx/nginx.conf
http {
    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 detailed '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for" '
                        'rt=$request_time uct="$upstream_connect_time" '
                        'urt="$upstream_response_time" uaddr="$upstream_addr"';

    access_log  /var/log/nginx/access.log  main;
}

# 项目配置独立日志
vim /etc/nginx/conf.d/proxy-lb.conf
server {
        access_log /var/log/nginx/ruoyi_access.log detailed;
        error_log /var/log/nginx/ruoyi_error.log warn;
}

nginx -t && systemctl reload nginx

# 测试访问后验证日志输出
tail /var/log/nginx/ruoyi_access.log

5.6 JSON 格式日志

# 主配置文件定义日志格式
vim /etc/nginx/nginx.conf
http {
	log_format json escape=json '{'
		'"time_local":"$time_local",'
		'"remote_addr":"$remote_addr",'
		'"remote_user":"$remote_user",'
		'"request":"$request",'
		'"status":$status,'
		'"body_bytes_sent":$body_bytes_sent,'
		'"request_time":$request_time,'
		'"http_referer":"$http_referer",'
		'"http_user_agent":"$http_user_agent",'
		'"http_x_forwarded_for":"$http_x_forwarded_for",'
		'"upstream_addr":"$upstream_addr",'
		'"upstream_status":"$upstream_status",'
		'"upstream_response_time":"$upstream_response_time"'
	'}';
	access_log /var/log/nginx/access.json.log json;
}

5.7 logrotate 日志切割

在 logrotate 配置文件定义轮转规则,logrotate 按规则定期对日志进行切割

配置项解析

配置项说明
daily / weekly每天切割 /每周切割
missingok文件缺失不报错
rotate 30旧日志保留副本数
compress压缩旧日志
delaycompress延迟一天压缩
dateext旧日志文件添加日期后缀
notifempty空文件不切割
sharedscripts对多个日志做切割时,所有日志切割后执行一次脚本
postrotate声明脚本起始
endscript声明脚本结束
# 创建 nginx 日志切割规则
vim /etc/logrotate.d/nginx
# 对 /var/log/nginx/ 目录下所有 .log 结尾文件进行切割
/var/log/nginx/*.log {
        daily
        missingok
        rotate 30
        dateext
        compress
        delaycompress
        notifempty
        sharedscripts
        postrotate
            /usr/bin/killall -HUP nginx
        endscript
}

# 查看 logrotate 定时任务
systemctl list-timers
Thu 2026-08-06 00:10:24 CST       8h Wed 2026-08-05 10:02:36 CST 5h 43min ago logrotate.timer              logrotate.service

# 手动触发 logrotate
logrotate -f /etc/logrotate.d/nginx

# 查看切割后的日志
ll /var/log/nginx/

六、性能调优

面向资源(CPU计算、内存、存储、网络)优化

内存优化 : 对其他资源优化时,要预留好内存资源,避免耗尽内存资源

CPU 优化 : Worker 进程数、Worker 进程和 CPU 核心绑定、多路复用、增大 Worker 进程优先级(设置为 -10)、避免第三方模块携带阻塞操作和长时间 CPU 密集计算

网络优化 : Nginx作为客户端(upstream 长连接、增加本地端口可用范围、前后端超时对齐)、Nginx作为服务端(半连接队列长度、全连接队列长度、临时启用 syncookie)、提升句柄数量上限(文件描述符限制)

存储优化 : 文件缓存、浏览器缓存、压缩、大文件直接 I/O、异步 I/O、线程池

6.1 Worker 进程优化

6.1.1 Worker 进程数

进程数应等于核心数而不是线程数,超线程会造成调度争抢

vim /etc/nginx/nginx.conf
# 全局配置
# Worker 进程数自动检测
worker_processes auto;

nginx -t && systemctl reload nginx

ps aux | grep nginx
6.1.2 worker_cpu_affinity 进程和核心绑定
vim /etc/nginx/nginx.conf
# 全局配置
worker_cpu_affinity 00000001 00000010;

nginx -t && systemctl reload nginx

# 验证绑定关系
ps -eo pid,cmd,psr | grep nginx
6.1.3 文件描述符上限
# Nginx 四层限制链路(生效取最小值)
内核全局 fs.file-max / fs.nr_open
        ↓
systemd LimitNOFILE(master进程继承硬上限)
        ↓
nginx.conf worker_rlimit_nofile(worker进程能上调的上限)
        ↓
events { worker_connections }
vim /etc/nginx/nginx.conf
# 全局配置
worker_rlimit_nofile 65535;

nginx -t && systemctl reload nginx
# nginx 直接启动修改系统文件描述符上限
# 临时修改
ulimit -n 65535

# 永久修改
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf

# 重新登录查看系统文件描述符上限
ulimit -n

# systemd 启动修改系统文件描述符上限
nginx.service 文件
[Service]
LimitNOFILE=65535
6.1.4 单个 Worker 最大连接数
events {                      
    worker_connections  65535;
}

nginx -t && systemctl reload nginx
6.1.5 多路复用
multi_accept on # 开启多路复用

http {
	server {
		listen 80 reuseport; # 关键配置
	}
}

6.2 网络优化

6.2.1 sendfile 零拷贝
vim /etc/nginx/nginx.conf

http {
    sendfile        on; # 启用零拷贝,新版默认启用
    tcp_nopush     on; # 配合 sendfile ,小包累积再发送;默认注释,去除 # 启用
}

nginx -t && systemctl reload nginx
6.2.2 keepalive 长连接优化

复用 TCP 连接

vim /etc/nginx/nginx.conf

http {
    keepalive_timeout  65; # 新版默认启用,空闲长连接超时时间
    keepalive_requests 10000; # 单个连接最大请求数
}
6.2.3 upstream 长连接

LB 配置

vim /etc/nginx/conf.d/proxy-lb.conf

upstream backend {             
        server backend1:8080 max_fails=3 fail_timeout=30s;
        server backend2:8080 max_fails=3 fail_timeout=30s;
        server backend3:8080 max_fails=3 fail_timeout=30s;
                               
        keepalive 32; # 维持的空闲长连接最大数量
        keepalive_requests 1000; # 单个连接最大请求数
        keepalive_timeout 60s; # 空闲长连接超时时间
}

server {
        location /api/ {               
                limit_req zone=api burst=20 nodelay;
                proxy_pass http://backend;
                 
                proxy_http_version 1.1; # HTTP/1.1 默认开启长连接
                proxy_set_header Connection ""; # 清空转发给后端的 Connection 请求头
                
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        } 
}

nginx -t && systemctl reload nginx
6.2.4 全连接队列长度

需配合内核参数优化项 net.core.somaxconn,两者取最小者生效

server {
    listen 80 backlog=4096;  # 重点:backlog 指定监听队列长度
    server_name localhost;
    # ...
}

6.3 Web Server 优化

6.3.1 open_file_cache 文件缓存
vim /etc/nginx/nginx.conf

http {
    open_file_cache max=10000 inactive=60s; # 最多缓存 10000 个文件,60 秒未被访问则淘汰
    open_file_cache_valid 60s; # 缓存有效期 60 秒
    open_file_cache_min_uses 2; # 60秒内被访问 2 次才缓存
    open_file_cache_errors on; # 文件不存在的错误信息也缓存
}
6.3.2 expires 浏览器缓存过期时间
vim /etc/nginx/conf.d/proxy-lb.conf

        location ~* \.(jpg|jpeg|png|gif|ico|svg|webp|css|js)$ {
                valid_referers none blocked server_names ruoyi.deng.org *.deng.org;
                if ($invalid_referer) {
                        return 403;
                }
                expires 30d; # 浏览器缓存 30 天
                access_log off;
        }
参数含义适用场景
expires 30d缓存 30 天图片、字体 (永久不变化)
expires 7d缓存 7 天CSS / JS (版本更新变化)
expires 1h缓存 1 小时热点数据、API 响应
expires -1不缓存HTML (需实时更新)
expires epoch不缓存
expires max最大缓存 (10年)完全静态资源
6.3.3gzip 压缩

压缩传输内容,减少带宽占用,但会消耗 CPU 资源

vim /etc/nginx/nginx.conf

http {
    gzip  on; # 开启 gzip 响应压缩
    gzip_min_length 1k; # 最小压缩阈值
    gzip_comp_level 4; # 压缩等级, 4 属于均衡选择
    gzip_types text/plain text/css text/xml application/json # 指定压缩的 MIME 类型
               application/javascript application/xml text/javascript;
    gzip_vary on; # 自动增加响应头
    gzip_disable "MSIE [1-6]\."; # 对 IE6 及以下浏览器禁用 gzip
}
6.3.4 Brotli 压缩

是Google推出的新一代压缩算法,比Gzip压缩率更高,体积可以再减15%~30%,需编译第三方模块

# 下载 Brotli 模块源码
cd /usr/local/src
git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli
git submodule update --init

# 重新编译 Nginx
cd /usr/local/src/nginx-1.30.4
nginx -V
./configure [原有参数] --add-module=/usr/local/src/ngx_brotli
make -j$(nproc)

# 复制编译完成的二进制文件
cp objs/nginx /usr/sbin/nginx

# 配置 Brotli 压缩

http {
	# Brotli压缩
	brotli on;
	brotli_comp_level 6; # 推荐5-8
	brotli_min_length 512;
	brotli_types text/plain text/css application/json application/javascript
	text/xml application/xml image/svg+xml;
	brotli_static on; # 优先使用预压缩的 .br 文件

	# Gzip 作为降级方案(客户端不支持 Brotli 时使用)
	gzip on;
	gzip_comp_level 4;
	gzip_types text/plain text/css application/json application/javascript;
	gzip_vary on;
}
6.3.5 大文件直接 I/O
location /data {
	directio 300M # 文件大小超过 300 M 开启直接 I/O
}
6.3.6 异步 I/O
aio on
6.3.7 线程池

高并发场景开启线程池,性能提升9倍左右

需要编译时添加编译选项 --with-threads

当需要读取本地文件时,创建 I/O 任务,投递到线程池任务队列

主线程立刻回归 epoll 事件循环,继续处理其它连接,不会等待文件读完

# 配置在最外层,配置格式
thread_pool <pool_name> threads=N [max_queue=M];

# 配置示例
thread_pool default threads=32 max_queue=65536;

6.4 LB 优化

6.4.1 代理缓冲优化
vim /etc/nginx/conf.d/proxy-lb.conf

        location /api/ {
                proxy_pass http://backend;
                 
                proxy_buffering on; # 开启缓冲,Nginx 接收完成再转发给客户端
                proxy_buffer_size 4k; # 响应头的缓冲区大小
                proxy_buffers 8 16k; # 响应体的缓冲区,8个16KB块
                proxy_busy_buffers_size 32k; # 忙时缓冲区大小
        } 
6.4.2 超时优化
vim /etc/nginx/conf.d/proxy-lb.conf

        location /api/ {
                proxy_pass http://backend;
                
                proxy_connect_timeout 5s; # 与后端建立连接的超时时间,建议 3-10s
                proxy_send_timeout 30s; # 向后端发送请求的超时时间,建议 30-120s
                proxy_read_timeout 30s; # 等待后端响应的超时时间,建议 30-120s

当出现 504 状态码时,建议调大 proxy_read_timeout 时间

6.5 5xx 状态码

状态码含义原因排查方向
500服务器内部错误服务端代码执行出错查看后端服务日志
502网关错误网关从后端服务收到无效响应.例如后端 Java 服务宕机,Nginx 无法连接检查后端是否存活,端口是否监听
503服务不可用服务端过载或正在维护检查后端负载,限流配置
504网关超时网关等待后端服务响应超时检查后端响应时间,调大 proxy_read_timeout

6.6 系统内核参数调优

# 允许 TIME_WAIT socket 复用(高并发必开)
net.ipv4.tcp_tw_reuse = 1

# TIME_WAIT 最大数量(太小会报错)
net.ipv4.tcp_max_tw_buckets = 65535

# TCP 全连接连接队列长度(net.core.somaxconn 必须大于 nginx 的 backlog)
net.core.somaxconn = 65535

# SYN 半连接队列长度(防 SYN Flood 攻击)
net.ipv4.tcp_max_syn_backlog = 65535

# SYN 重试次数(默认 5 次太慢)
net.ipv4.tcp_synack_retries = 2

# FIN_WAIT2 超时时间(默认60秒太长)
net.ipv4.tcp_fin_timeout = 15

# keepalive探测
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# 本地临时端口范围(默认32768-61000)
net.ipv4.ip_local_port_range = 1024 65535

# TCP缓冲区
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# 网卡队列
net.core.netdev_max_backlog = 65535

# 文件描述符
fs.file-max = 20000000
fs.nr_open = 2097152

# 临时手段,半连接队列满时临时启用,高峰期过后关闭
net.ipv4.tcp_syncookie = 1
# 配置示例
vim /etc/sysctl.conf

net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_max_tw_buckets = 65535
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.netdev_max_backlog = 65535

sysctl -p

临时手段 : syn-cookie

6.7 压测工具

# 安装 ab (Apache Bench)
dnf install -y httpd-tools
apt install -y apache2-utils

# 安装 装wrk
apt install -y wrk
6.7.1 ab 命令常用选项
选项说明示例
-n总发起请求数-n 100000
-c并发数-c 1000
-k启用长连接-k
-H添加请求头-H "Accept-Encoding: gzip"
-t压测持续时间,秒-t 30
-T指定 MIME 类型-T "application/json"
-pPOST 请求的文件-p post_data.txt
# 基础压测,10000个请求,1000并发
ab -n 10000 -c 1000 http://www.deng.org/

# 启用长连接
ab -n 10000 -c 1000 -k http://www.deng.org/

# 带 gzip 请求头压测
ab -n 10000 -c 1000 -H "Accept-Encoding: gzip" http://www.deng.org/

# 压测并记录结果到文件
ab -n 10000 -c 1000 http://www.deng.org/ > /tmp/bench_result.txt
6.7.2 ab 输出结果解析

P99 重点关注,长尾效应,大型网站由众多请求构成,多个请求叠加慢响应概率提升

Server Software:        nginx/1.30.4 # 服务器软件及版本
Server Hostname:        www.deng.org # 服务器主机名
Server Port:            80 # 服务器端口

Document Path:          / # 请求路径
Document Length:        169 bytes # 响应体大小

Concurrency Level:      1000 # 并发数
Time taken for tests:   0.768 seconds # 总耗时
Complete requests:      10000 # 完成请求数
Failed requests:        128 # 失败请求数(必须为0)
   (Connect: 0, Receive: 0, Length: 64, Exceptions: 64)
Non-2xx responses:      9936
Total transferred:      3576960 bytes # 总传输字节数(含头部)
HTML transferred:       1679184 bytes # HTML传输字节数
Requests per second:    13013.68 [#/sec] (mean) # QPS(每秒请求数)
Time per request:       76.842 [ms] (mean) # 平均响应时间(含所有并发)
Time per request:       0.077 [ms] (mean, across all concurrent requests)
Transfer rate:          4545.84 [Kbytes/sec] received # 传输速率

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   30   5.1     30      49 # TCP 连接时间
Processing:    15   44   9.7     44      75 # 服务端处理时间
Waiting:        0   32   8.5     34      63 # 等待响应时间
Total:         33   74   9.7     74     110 # 总时间

Percentage of the requests served within a certain time (ms)
  50%     74
  66%     76
  75%     77
  80%     79
  90%     84
  95%     93
  98%     99
  99%     99 # 99% 的请求在 99ms 内完成, P99 重点关注,长尾效应,大型网站由众多请求构成,多个请求叠加慢响应概率提升
 100%    110 (longest request) # 最慢的请求在 110ms 内完成
6.7.3 wrk 常用选项
选项说明示例
-t线程数-t 4
-c并发连接数-c 100
-d压测持续数据-d 30s
-H添加请求头-H "Accept-Encoding: gzip"
--timeout超时时间--timeout 5s
# 基础压测
wrk -t4 -c100 -d30s http://www.deng.org/

# 带 gzip 请求头
wrk -t4 -c100 -d30s -H "Accept-Encoding: gzip" http://www.deng.org/

# 输出详细结果
wrk -t4 -c100 -d30s --latency http://www.deng.org/
6.7.4 wrk 输出结果解析
Running 30s test @ http://www.deng.org/
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     2.01ms  270.41us  43.82ms   98.02% # 响应时间统计, Avg 越小越好 , Max 不能过大
    Req/Sec    12.48k   191.61    14.80k    81.58% # 单线程QPS,数值越大越好
  Latency Distribution
     50%    2.00ms
     75%    2.04ms
     90%    2.09ms
     99%    2.38ms # 99%的请求在2.38ms内完成,重点关注
  1490453 requests in 30.01s, 518.81MB read # 总请求数/总数据量
Requests/sec:  49668.81 # QPS(每秒请求数)
Transfer/sec:     17.29MB # 传输速率
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值