Day 9-1 Nginx 架构与基础配置
本篇合并《Day_9-1_Nginx架构与基础配置.pdf》与《Day_9-1_Nginx架构与基础配置(1).pdf》,重复内容保留一份,补入两个版本各自的实验、输出和图示。存在配置差异时,在对应小节说明。
Nginx——可作为独立的 Web 服务器,更是“流量入口”。
主线说明:本课程主线是 Java 项目(若依 RuoYi-Vue),但 Nginx 作为通用接入层,也会承载 PHP/Python 等非 Java 应用。本节会部署一个 WordPress(PHP + MySQL)测试站点和一个 Flask(Python + Gunicorn)测试站点,验证 Nginx 对 PHP 和 Python 两种后端语言的代理能力。
本章概览

本节目标
| 目标 | 说明 |
|---|---|
| 理解 Nginx 架构 | 掌握 Master-Worker 进程模型和 epoll 事件驱动原理 |
| 部署 Nginx | 使用 YUM 和源码两种方式安装 Nginx,包含第三方模块编译 |
| 掌握核心配置 | 理解 nginx.conf 层级结构、核心指令、location 匹配规则 |
| 理解 root 与 alias | 掌握两者区别及适用场景 |
| 部署 PHP 应用 | 配置 Nginx 代理 PHP-FPM,完成 WordPress 站点部署 |
| 部署 Python 应用 | 配置 Nginx 代理 Gunicorn,完成 Flask 应用部署 |
| 平滑升级 | 掌握 Nginx 不停服升级二进制文件的方法 |
一、Web 架构演进与 Nginx 定位
1.1 Nginx 在整体架构中的位置
在开始学习之前,先建立完整的架构视图。Nginx 在企业级应用中扮演“接入层”的角色:

Nginx 负责“接待”(接收请求、返回静态页面、转发动态请求),各种后端语言负责“干活”(处理业务逻辑、操作数据库)。
二、Nginx 架构深度了解(认知)
2.1 Master-Worker 进程模型
Nginx 启动后,进程分为两种角色:

Master-Worker 详解:
| 进程 | 职责 | 数量 | 关键特点 |
|---|---|---|---|
| Master 进程 | 读取/校验配置、绑定端口、管理 Worker 进程 | 1 个 | 以 root 用户运行,不处理客户端请求 |
| Worker 进程 | 接收并处理客户端请求 | 通常 = CPU 核心数 | 每个 Worker 独立,内存隔离;以 nginx 用户运行 |
实验:查看 Nginx 进程树。
# 启动 Nginx 后查看进程
[root@magedu ~]# ps aux --forest | grep nginx
root 1234 0.0 0.1 ? Ss ... nginx: master process
nginx 1235 0.0 0.2 ? S ... nginx: worker process
nginx 1236 0.0 0.2 ? S ... nginx: worker process
2.2 epoll 事件驱动模型
2.2.1 什么是 IO 模型?
在理解 epoll 之前,首先要明白什么是 IO(Input/Output,输入/输出)。
IO 就是程序从外部设备读取数据或向外部设备写入数据的过程。
对 Web 服务器来说,IO 主要指:
- 读:从网卡读取客户端发送的 HTTP 请求。
- 写:向网卡写入响应数据返回给客户端。
当 Nginx 处理大量并发连接时,每个连接都需要进行 IO 操作。IO 模型决定了服务器如何管理和处理这些 IO 操作,直接影响服务器的并发能力。
2.2.2 三种 IO 模型对比
模型一:阻塞 IO(BIO)——一个连接一个线程

BIO 举例解析:
生活中的场景:餐厅每张桌子配一个服务员。客人不说话,服务员就站在旁边一直等。100 张桌子配 100 个服务员,但真正需要服务的可能只有 2–3 桌。其他服务员都在“发呆等”。
Nginx 实际场景(如果 Nginx 用 BIO):
- 每个客户端连接需要一个独立的 Worker 线程。
- 10000 个并发连接 → 10000 个线程。
- 每个线程栈内存约 1–2 MB → 10000 × 2 MB = 20 GB 内存。
- 线程切换消耗 CPU → 系统卡死。
Nginx 实际做法:Nginx 不用 BIO。Apache 的 prefork MPM 用的是类似 BIO 的模式,这也是为什么 Apache 并发能力远低于 Nginx。
模型二:select/poll——一个线程轮询所有连接

select/poll 举例解析:
生活中的场景:餐厅只雇了 1 个服务员。服务员每隔 5 秒就跑遍所有桌子,挨个问“需要服务吗?”100 张桌子问完,只有 1 张有需求。99% 的时间浪费在问“不需要服务”的桌子上。
Nginx 实际场景(如果 Nginx 用 select/poll):
- 一个 Worker 进程监控所有连接。
- 每次调用 select/poll 需要遍历 10000 个连接的文件描述符。
- 即使只有 1 个连接活跃,也要扫描 10000 次。
- 时间复杂度 O(n),n=连接数,连接越多越慢。
Nginx 实际做法:Nginx 不用 select/poll。select 有 1024 连接数限制,poll 虽然无限制但同样低效。
模型三:epoll——事件驱动,只处理活跃连接

epoll 举例解析:
生活中的场景:餐厅只雇了 1 个服务员,但每张桌子上都有呼叫铃。客人需要服务时按铃,服务员只去按铃的桌子。10000 张桌子只有 1 张按铃,服务员只去那 1 张。
Nginx 实际场景(Nginx 实际使用 epoll):
- 一个 Worker 进程监控所有连接。
- 连接有数据时,内核主动通知 Nginx(epoll_wait 返回)。
- 返回的 events 数组中只有活跃连接,无需遍历。
- 时间复杂度 O(1),10000 连接只处理活跃的那 1 个。
- 无连接数限制。
Nginx 实际做法:Nginx 在 events 块中配置 use epoll,就是告诉 Nginx 使用这种高效的事件驱动模型。
2.2.3 三种模型性能对比总结
| 对比维度 | BIO(阻塞 IO) | select/poll | epoll |
|---|---|---|---|
| 并发连接数 | 低(受线程数限制) | 中(select 有 1024 限制) | 高(数万) |
| CPU 占用 | 高(线程切换) | 高(轮询扫描) | 低(事件通知) |
| 内存占用 | 极高(每连接一线程) | 低 | 低 |
| 时间复杂度 | O(n) | O(n) | O(1) |
| 适用场景 | 连接数 <100 | 连接数几百 | 高并发生产环境 |
| 谁在用 | Apache(prefork 模式) | 早期 Unix 网络程序 | Nginx、Redis |
epoll 让 Nginx 的 Worker 进程不会把时间浪费在“问没有数据的连接”上。它只处理真正有数据要读写的连接,所以一个 Worker 能同时支撑数万连接。这就是 Nginx 高性能的核心秘密。
原文的 O(1) 和“无连接数限制”为教学简化:实际处理工作量与就绪事件数相关,连接数还受文件描述符、内存及 worker_connections 等限制。Nginx 的具体事件机制也取决于操作系统,并非所有平台都使用 epoll。
2.3.4 O(n) 和 O(1) 简单理解
这两个是算法复杂度的表示方式,用来描述“随着连接数增加,工作量怎么变化”。本小节保留原文编号 2.3.4。
| 表示法 | 读法 | 含义 |
|---|---|---|
| O(1) | 大 O 一 | 恒定时间——不管连接有多少,工作量不变 |
| O(n) | 大 O n | 线性时间——连接越多,工作量越大 |
对应到 I/O 模型:
| I/O 模型 | 复杂度 | 说明 |
|---|---|---|
| select/poll | O(n) | 每次都要扫描全部 n 个连接,找出哪些有数据。10000 个连接就要扫描 10000 次 |
| epoll | O(1) | 内核直接告诉你有数据的连接是哪几个,只处理这些即可。10000 个连接只有 1 个活跃,就只处理 1 个 |
O(n) = 人越多,活越重
O(1) = 人再多,活不变
2.2.5 Nginx 中如何配置 epoll
events {
use epoll; # 指定使用 epoll 事件模型
worker_connections 10240; # 单 Worker 最大连接数
multi_accept on; # 一次接受所有新连接
}
注意:在 Linux 系统上,Nginx 默认就使用 epoll,无需显式指定。但了解这个配置可以让你知道 Nginx 在用什么机制工作。
三、Nginx 快速部署
3.1 环境准备
主环境:Rocky Linux 10。Ubuntu 26.04 差异见旁注。
# 安装基础工具
[root@magedu ~]# dnf install -y curl wget vim net-tools git
# 关闭防火墙(测试环境)
[root@magedu ~]# systemctl stop firewalld
[root@magedu ~]# systemctl disable firewalld
Ubuntu 26.04 旁注:
[root@magedu ~]# apt update
[root@magedu ~]# apt install -y curl wget vim git
[root@magedu ~]# ufw disable
3.2 生产环境安装方式选择
| 对比维度 | YUM/DNF/APT 安装 | 源码编译安装 |
|---|---|---|
| 安装速度 | 快(1–2 分钟) | 慢(5–10 分钟) |
| 版本可控性 | 取决于 OS 仓库版本 | 完全可控 |
| 模块选择 | 固定 | 完全自定义 |
| 升级维护 | 简单 | 需重新编译 |
| systemd 服务 | 自动创建 | 需手动创建 |
生产环境推荐:源码编译安装——版本可控、路径标准化、可按需添加第三方模块。
3.3 YUM 安装 Nginx(快速上手)
# Rocky Linux 10:安装 Nginx
[root@magedu ~]# dnf install -y nginx
# 查看版本
[root@magedu ~]# nginx -v
nginx version: nginx/1.26.0
# 启动服务(YUM 安装已自带 systemd 服务文件)
[root@magedu ~]# systemctl enable --now nginx
[root@magedu ~]# systemctl status nginx
3.4 源码编译安装(含第三方模块)
源码编译安装后,需要手动创建 systemd 服务文件。
什么是第三方模块?
Nginx 官方版本只包含核心功能,很多企业级功能需要通过第三方模块扩展:
| 模块 | 用途 | 常用场景 |
|---|---|---|
| echo-nginx-module | 输出调试信息 | 测试 location 匹配、调试配置 |
| headers-more-nginx-module | 修改请求/响应头 | 添加、删除、修改 HTTP 头 |
| nginx-http-flv-module | 视频流推送 | 直播推流、视频点播 |
| ngx_brotli | Brotli 压缩 | 比 Gzip 压缩率更高 |
| nginx-module-vts | 流量统计 | 监控每个虚拟机的请求数、流量 |
静态模块 vs 动态模块
Nginx 支持两种方式添加第三方模块:

两种方式对比总结:
| 对比维度 | 静态模块(--add-module) | 动态模块(--add-dynamic-module) |
|---|---|---|
| 编译方式 | 嵌入 nginx 二进制 | 生成独立的 .so 文件 |
| 加载方式 | 自动加载 | 需在 nginx.conf 中 load_module |
| 版本匹配 | 无此问题 | 必须与 nginx 版本精确匹配 |
| 启动风险 | 低 | 高(.so 不匹配则启动失败) |
| 新增模块 | 需重新编译整个 nginx | 可单独编译新模块 |
| 适用场景 | 生产环境(推荐) | 开发测试环境 |
企业生产环境实践建议:
生产环境:一次性把所有需要的模块编译进去(静态模块),省心、稳定、不出错。
- 无版本匹配问题,升级 Nginx 时只需重新编译整个二进制。
- 启动时加载完成,运行时无额外开销。
- 避免因 .so 文件与 Nginx 版本不匹配导致服务启动失败。
开发测试环境:可以用动态模块方便试错,但上线前转成静态编译。
第一步:安装编译依赖
[root@magedu ~]# dnf install -y gcc make pcre2-devel zlib-devel openssl-devel git
[root@magedu ~]# dnf groupinstall -y "Development Tools"
第二步:下载 Nginx 源码和第三方模块
[root@magedu ~]# cd /usr/local/src
# 下载 nginx
[root@magedu ~]# wget https://nginx.org/download/nginx-1.30.4.tar.gz
# 下载 echo 模块
[root@magedu ~]# git clone https://github.com/openresty/echo-nginx-module.git
提示:echo 模块如果不能克隆,可以使用提前准备好的文件。
[root@magedu src]# pwd
/usr/local/src
[root@magedu src]# ls
echo-nginx-module-0.65.tar.gz nginx-1.30.4.tar.gz
第三步:配置编译选项(添加第三方模块)
生产推荐:静态编译。
[root@magedu src]# useradd nginx
[root@magedu src]# tar xf nginx-1.30.4.tar.gz
[root@magedu src]# tar xf echo-nginx-module-0.65.tar.gz
[root@magedu src]# ls
echo-nginx-module-0.65 echo-nginx-module-0.65.tar.gz nginx-1.30.4 nginx-1.30.4.tar.gz
[root@magedu ~]# cd nginx-1.30.4
[root@magedu ~]# ./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-0.65
动态编译(了解即可):
# 如需使用动态模块,将 --add-module 替换为 --add-dynamic-module
./configure ...原有参数... \
--add-dynamic-module=/usr/local/src/echo-nginx-module
# 编译后会生成 .so 文件
# 需要在 nginx.conf 中加载:
# load_module modules/ngx_http_echo_module.so;
第四步:编译安装
[root@magedu ~]# make -j$(nproc)
[root@magedu nginx-1.30.4]# make install
make -f objs/Makefile install
make[1]: Entering directory '/usr/local/src/nginx-1.30.4'
test -d '/usr/local/nginx' || mkdir -p '/usr/local/nginx'
test -d '/usr/sbin' \
|| mkdir -p '/usr/sbin'
test ! -f '/usr/sbin/nginx' \
|| mv '/usr/sbin/nginx' \
'/usr/sbin/nginx.old'
cp objs/nginx '/usr/sbin/nginx'
test -d '/etc/nginx' \
|| mkdir -p '/etc/nginx'
cp conf/koi-win '/etc/nginx'
cp conf/koi-utf '/etc/nginx'
cp conf/win-utf '/etc/nginx'
test -f '/etc/nginx/mime.types' \
|| cp conf/mime.types '/etc/nginx'
cp conf/mime.types '/etc/nginx/mime.types.default'
test -f '/etc/nginx/fastcgi_params' \
|| cp conf/fastcgi_params '/etc/nginx'
cp conf/fastcgi_params \
'/etc/nginx/fastcgi_params.default'
test -f '/etc/nginx/fastcgi.conf' \
|| cp conf/fastcgi.conf '/etc/nginx'
cp conf/fastcgi.conf '/etc/nginx/fastcgi.conf.default'
test -f '/etc/nginx/uwsgi_params' \
|| cp conf/uwsgi_params '/etc/nginx'
cp conf/uwsgi_params \
'/etc/nginx/uwsgi_params.default'
test -f '/etc/nginx/scgi_params' \
|| cp conf/scgi_params '/etc/nginx'
cp conf/scgi_params \
'/etc/nginx/scgi_params.default'
test -f '/etc/nginx/nginx.conf' \
|| cp conf/nginx.conf '/etc/nginx/nginx.conf'
cp conf/nginx.conf '/etc/nginx/nginx.conf.default'
test -d '/var/run' \
|| mkdir -p '/var/run'
test -d '/var/log/nginx' \
|| mkdir -p '/var/log/nginx'
test -d '/usr/local/nginx/html' \
|| cp -R html '/usr/local/nginx'
test -d '/var/log/nginx' \
|| mkdir -p '/var/log/nginx'
make[1]: Leaving directory '/usr/local/src/nginx-1.30.4'
第五步:验证模块是否编译成功
[root@magedu nginx-1.30.4]# /usr/sbin/nginx -V
nginx version: nginx/1.30.4
built by gcc 14.3.1 20251022 (Red Hat 14.3.1-4) (GCC)
built with OpenSSL 3.5.5 27 Jan 2026
TLS SNI support enabled
configure arguments: --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-0.65
第六步:源码编译安装后的原生管理方式
在创建 systemd 服务文件之前,先了解 Nginx 原生的启动/停止/重载方式。这些信号控制方式在生产环境排障时非常有用,也是理解 systemd 服务文件的基础。
# 启动 Nginx(直接执行)
[root@magedu ~]# /usr/sbin/nginx
[root@magedu ~]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1003/sshd: /usr/sbi
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 7140/nginx: master
tcp6 0 0 :::22 :::* LISTEN 1003/sshd: /usr/sbi
# 停止 Nginx(快速停止,强制终止)
[root@magedu ~]# /usr/sbin/nginx -s stop
# 优雅停止(完成当前请求后退出)
[root@magedu ~]# /usr/sbin/nginx -s quit
# 重载配置(不停服重新加载)
[root@magedu ~]# /usr/sbin/nginx -s reload
# 重新打开日志文件(日志切割时使用)
[root@magedu ~]# /usr/sbin/nginx -s reopen
# 查看 Nginx 进程
[root@magedu ~]# ps aux | grep nginx
信号控制方式详解:
| 命令 | 信号 | 作用 |
|---|---|---|
| nginx -s stop | SIGTERM | 快速停止 Nginx 进程 |
| nginx -s quit | SIGQUIT | 优雅停止,完成当前请求后退出 |
| nginx -s reload | SIGHUP | 重新加载配置文件,不停服 |
| nginx -s reopen | SIGUSR1 | 重新打开日志文件 |
这些信号控制方式在 systemd 服务文件中也有体现,例如 ExecReload=/usr/sbin/nginx -s reload。
第七步:创建 systemd 服务文件
[root@magedu ~]# 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
[Install]
WantedBy=multi-user.target
EOF
[root@magedu ~]# systemctl daemon-reload
[root@magedu ~]# systemctl enable --now nginx
[root@magedu ~]# netstat -tnlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1003/sshd: /usr/sbi
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 7231/nginx: master
tcp6 0 0 :::22 :::* LISTEN 1003/sshd: /usr/sbi

systemd 服务文件各字段说明:
| 字段 | 说明 |
|---|---|
| Type=forking | Nginx 是 fork 方式启动的守护进程 |
| PIDFile | 指定 PID 文件路径,systemd 靠它跟踪主进程 |
| ExecStartPre | 启动前执行配置语法检查 |
| ExecStart | 启动命令 |
| ExecReload | 重载配置命令(nginx -s reload) |
| ExecStop | 停止命令(kill -s QUIT,即优雅停止) |
两种管理方式对比:
| 管理方式 | 启动 | 停止 | 重载 |
|---|---|---|---|
| 原生信号 | /usr/sbin/nginx | nginx -s stop / nginx -s quit | nginx -s reload |
| systemd | systemctl start nginx | systemctl stop nginx | systemctl reload nginx |
3.5 Nginx 平滑升级(生产环境常用)
3.5.1 什么是平滑升级?
平滑升级 = 在不停止 Nginx 服务的情况下,替换二进制文件并让新版本 Worker 接管请求。
原理:旧 Master 进程启动新 Master 进程 → 新 Master 启动新 Worker → 新 Worker 接管新连接 → 旧 Worker 处理完现有请求后退出。
| 场景 | 是否需要平滑升级 |
|---|---|
| 小版本安全补丁(如 1.30.4 → 1.30.5) | 推荐 |
| 添加/删除模块重新编译 | 推荐 |
| 大版本升级(如 1.30 → 1.32) | 推荐 |
| 测试环境 | 可直接重启 |
3.5.2 平滑升级前:必须先查看旧版本的编译参数
平滑升级时,新版本 Nginx 必须用与旧版本完全相同的编译参数,否则新 Master 进程启动时可能因为路径、模块不匹配而失败。
# 1. 查看旧版本的编译参数(必须先做这一步!)
[root@magedu ~]# /usr/sbin/nginx -V
nginx version: nginx/1.30.4
built by gcc 14.2.1 20250128 (Red Hat 14.2.1-7) (GCC)
configure arguments: --prefix=/usr/local/nginx --sbin-path=/usr/sbin/nginx ... --add-module=/usr/local/src/echo-nginx-module
# 建议保存到文件,方便下次升级直接复用
[root@magedu ~]# /usr/sbin/nginx -V | tee /opt/nginx-build-args.txt
原文这条保存命令未重定向标准错误;nginx -V 通常输出到标准错误,应使用本章速查表中的
nginx -V 2>&1 | tee /opt/nginx-build-args.txt。
为什么要先看 nginx -V?
| 原因 | 说明 |
|---|---|
| 路径一致性 | --prefix、--conf-path 等路径参数必须一致,否则新 Master 找不到配置文件 |
| 模块一致性 | 静态编译的模块(--add-module)必须保留,否则新 Master 启动失败 |
| 功能一致性 | 如果旧版本有 --with-http_ssl_module,新版本没有,HTTPS 站点将无法工作 |
3.5.3 平滑升级实验步骤
# 1. 查看当前 Nginx 版本
[root@magedu ~]# /usr/sbin/nginx -v
nginx version: nginx/1.30.4
# 2. 备份当前二进制
[root@magedu ~]# mv /usr/sbin/nginx /usr/sbin/nginx.old
# 3. 编译新版本(使用与旧版本完全相同的编译参数)
[root@magedu src]# cd /usr/local/src
[root@magedu src]# wget https://nginx.org/download/nginx-1.31.3.tar.gz
[root@magedu src]# ls
echo-nginx-module-0.65 nginx-1.30.4 nginx-1.31.3.tar.gz
echo-nginx-module-0.65.tar.gz nginx-1.30.4.tar.gz
[root@magedu src]# tar xzf nginx-1.31.3.tar.gz
[root@magedu src]# cd nginx-1.31.3
[root@magedu nginx-1.31.3]# ./configure [原样粘贴旧版本的编译参数]
[root@magedu nginx-1.31.3]# make # 只编译,不安装
# 4. 复制新二进制文件(保留旧版本)
[root@magedu nginx-1.31.3]# cp objs/nginx /usr/sbin/nginx
[root@magedu nginx-1.31.3]# ls /usr/sbin/nginx*
/usr/sbin/nginx /usr/sbin/nginx.old
# 5. 向旧 Master 进程发送 USR2 信号(启动新版本)
[root@magedu ~]# kill -USR2 $(cat /var/run/nginx.pid)
[root@magedu nginx-1.31.3]# ps aux | grep nginx
root 9092 0.0 0.1 12828 3108 ? Ss 18:04 0:00 nginx: master process /usr/sbin/nginx
nginx 9093 0.0 0.2 13028 4720 ? S 18:04 0:00 nginx: worker process
root 9129 0.0 0.4 12848 7328 ? S 18:08 0:00 nginx: master process /usr/sbin/nginx
nginx 9130 0.0 0.2 13048 4276 ? S 18:08 0:00 nginx: worker process
root 9132 0.0 0.1 227696 2180 pts/0 S+ 18:08 0:00 grep --color=auto nginx
# 6. 向旧 Master 进程发送 WINCH 信号(停止旧 Worker,如果有连接会等连接关闭)
[root@magedu ~]# kill -WINCH $(cat /var/run/nginx.pid.oldbin)
[root@magedu nginx-1.31.3]# ps aux | grep nginx
root 9092 0.0 0.1 12828 3112 ? Ss 18:04 0:00 nginx: master process /usr/sbin/nginx
root 9129 0.0 0.4 12848 7328 ? S 18:08 0:00 nginx: master process /usr/sbin/nginx
nginx 9130 0.0 0.2 13048 4276 ? S 18:08 0:00 nginx: worker process
# 7. 向旧 Master 进程发送 QUIT 信号(完全退出)
[root@magedu ~]# kill -QUIT $(cat /var/run/nginx.pid.oldbin)
[root@magedu nginx-1.31.3]# ps aux | grep nginx
root 9129 0.0 0.4 12848 7328 ? S 18:08 0:00 nginx: master process /usr/sbin/nginx
nginx 9130 0.0 0.2 13048 4276 ? S 18:08 0:00 nginx: worker process
root 9146 0.0 0.1 227696 2208 pts/0 S+ 18:11 0:00 grep --color=auto nginx
# 8. 确认旧 master 已退出
[root@magedu ~]# ps aux | grep nginx | grep -v grep
# 应该只看到新的 master 和 worker 进程
# 9. 验证新版本生效
[root@magedu nginx-1.31.3]# /usr/sbin/nginx -v
nginx version: nginx/1.31.3
平滑升级信号说明:
| 信号 | 作用 |
|---|---|
| USR2 | 启动新版本 Master 进程(新旧共存) |
| WINCH | 停止旧 Worker 进程(新 Worker 接管请求) |
| QUIT | 旧 Master 进程退出 |
进程变化过程:
初始状态:
master (pid A) + worker
USR2 后:
master (pid A) + worker (旧)
master (pid B) + worker (新)
WINCH 后:
master (pid A) ← 只保留了 master 进程
master (pid B) + worker (新) ← 提供服务
QUIT 后:
master (pid B) + worker (新) ← 最终状态
四、Nginx 基础配置
4.1 配置文件的层级结构
| 配置块 | 作用范围 | 主要职责 |
|---|---|---|
| main(全局块) | 全局 | Nginx 整体运行参数(用户、进程数、PID) |
| events 块 | 全局 | 网络连接参数(事件模型、最大连接数) |
| http 块 | 全局 | HTTP 通用配置(MIME、日志、Gzip) |
| server 块 | 虚拟主机 | 定义网站(域名、端口) |
| location 块 | URL 路径 | 匹配 URL 并执行处理 |
# ==================== main 块:全局配置 ====================
# 指定 Nginx worker 进程的运行用户(用于文件访问权限)
user nginx;
# worker 进程数,建议设置为 CPU 核心数,auto 表示自动检测
worker_processes auto;
# 主进程 PID 文件存放路径
pid /var/run/nginx.pid;
# ==================== events 块:事件驱动配置 ====================
events {
# 每个 worker 进程的最大并发连接数,需根据系统 ulimit -n 调整
worker_connections 10240;
# 事件驱动模型,Linux 下使用 epoll 高效处理大量并发连接
use epoll;
}
# ==================== http 块:HTTP 协议相关配置 ====================
http {
# 启用 sendfile 系统调用(零拷贝),提升静态文件传输效率
sendfile on;
# 长连接超时时间(秒),65 秒是常见值,平衡性能与资源占用
keepalive_timeout 65;
# ==================== server 块:虚拟主机配置 ====================
server {
# 监听端口 80(HTTP 默认端口)
listen 80;
# 虚拟主机域名,用于匹配请求的 Host 头
server_name localhost;
# ==================== location 块:URL 路由规则 ====================
location / {
# 站点根目录,对应请求 URL 的物理路径
root /usr/share/nginx/html;
# 默认索引文件,访问目录时按顺序查找
index index.html;
}
}
}
4.2 Nginx 虚拟主机配置
虚拟主机是一种资源共享技术,它让一台物理服务器上同时运行多个独立的网站。每个网站在逻辑上相互隔离,拥有自己独立的域名、根目录和配置文件,互不干扰。
| 类型 | 区分依据 | 配置指令 | 典型应用场景 |
|---|---|---|---|
| 基于域名 | 请求头中的 Host 字段 | server_name | 同一 IP 和端口下运行多个网站(最常用) |
| 基于 IP | 请求的目标 IP 地址 | listen IP:port | 服务器绑定多个 IP,每个 IP 对应不同站点 |
| 基于端口 | 请求的目标端口号 | listen port | 同一 IP 不同端口区分不同服务,如管理后台 |
基于域名的虚拟主机
所有域名解析到同一个 IP,Nginx 根据请求头中的 Host 字段分发到不同站点。

基于 IP 的虚拟主机
服务器绑定多个 IP,每个 IP 对应一个虚拟主机,Nginx 根据请求的目标 IP 分发。

基于端口的虚拟主机
同一 IP,不同端口对应不同虚拟主机,通过端口号区分服务。

虚拟主机配置示例
# ① 基于域名的虚拟主机(最常用)
server {
listen 80;
server_name www.magedu.com; # 访问 www.magedu.com 走这个
root /var/www/magedu;
}
server {
listen 80;
server_name blog.magedu.com; # 访问 blog.magedu.com 走这个
root /var/www/blog;
}
# ② 基于 IP 的虚拟主机
server {
listen 192.168.1.10:80; # 访问 192.168.1.10 走这个
server_name _;
root /var/www/site1;
}
server {
listen 192.168.1.11:80; # 访问 192.168.1.11 走这个
server_name _;
root /var/www/site2;
}
# ③ 基于端口的虚拟主机
server {
listen 80; # 对外网站
server_name www.magedu.com;
root /var/www/public;
}
server {
listen 8080; # 管理后台
server_name www.magedu.com;
root /var/www/admin;
}
虚拟主机技术:以京东为例
为什么需要虚拟主机?
想象一下,如果京东所有业务都挤在一个服务器、一个域名下:
- www.jd.com/家电
- www.jd.com/图书
- www.jd.com/金融
- www.jd.com/物流
这种结构会导致以下问题:
| 问题 | 说明 |
|---|---|
| 代码耦合 | 所有业务代码混在一起,牵一发而动全身 |
| 故障扩散 | 图书系统崩溃可能导致整个 www.jd.com 不可用 |
| 独立运维 | 无法单独重启或升级某一个业务模块 |
| 权限混乱 | 所有业务共享同一套配置和权限体系 |
| 扩展困难 | 无法针对高流量业务单独扩容 |
京东的子域名架构(虚拟主机实践)
原文以基于域名的虚拟主机为例,将不同业务隔离到独立的子域名下:

Nginx 虚拟主机配置(京东风格):
# 京东主站
server {
listen 80;
server_name www.jd.com;
root /var/www/jd/main;
}
# 京东图书
server {
listen 80;
server_name book.jd.com;
root /var/www/jd/book;
}
# 京东金融:独立域名,独立 SSL 证书
server {
listen 443 ssl;
server_name jr.jd.com;
root /var/www/jd/finance;
ssl_certificate finance.crt;
ssl_certificate_key finance.key;
}
# 京东秒杀
server {
listen 80;
server_name miaosha.jd.com;
root /var/www/jd/miaosha;
}
# 京东物流
server {
listen 80;
server_name logistics.jd.com;
root /var/www/jd/logistics;
}
虚拟主机本质上是一种“多租户”技术——让一台服务器(或一组服务器)通过域名区分不同业务,每个业务拥有独立的代码、配置、团队和生命周期,既能共享基础设施,又能保持业务隔离。京东等大型互联网公司的子域名架构,正是原文用于解释虚拟主机技术的案例。
4.3 location 匹配规则
location 是 Nginx 配置中最核心和强大的指令之一,它决定了如何响应不同的客户端请求。
六种匹配方式:
| 优先级 | 匹配类型 | 语法 | 示例 | 匹配后行为 |
|---|---|---|---|---|
| 1 | 精确匹配 | = /path | location = /health | 立即停止 |
| 2 | 前缀优先匹配 | ^~ /path | location ^~ /static/ | 停止正则匹配 |
| 3 | 正则匹配(区分大小写) | ~ /pattern | location ~ .php$ | 按顺序匹配 |
| 4 | 正则匹配(不区分大小写) | ~* /pattern | location ~* .jpg$ | 按顺序匹配 |
| 5 | 通用前缀匹配 | /path | location /api/ | 最长匹配 |
| 6 | 通用匹配 | / | location / | 兜底 |
原文将 ~ 和 ~ 分列为优先级 3、4;实际上两者同属正则 location,按配置出现顺序测试,首个匹配者胜出,并非 ~ 固定高于 ~。前缀匹配先记录最长前缀;最长前缀带 ^~ 时才跳过相应正则匹配。
生产环境常见 location 配置:
server {
# 1. 健康检查:精确匹配
location = /health {
return 200 "OK\n";
}
# 2. 静态资源:前缀优先匹配
location ^~ /static/ {
root /var/www/ruoyi;
expires 30d;
}
# 3. 图片文件:不区分大小写正则匹配
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
root /var/www/ruoyi;
expires 30d;
}
# 4. PHP 请求:区分大小写正则匹配
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# 5. API 版本控制:最长匹配
location /api/v1/ {
proxy_pass http://backend_v1/;
}
location /api/ {
proxy_pass http://backend/;
}
# 6. 前端 SPA:兜底
location / {
try_files $uri $uri/ /index.html;
}
}
第二份课件还展示了默认虚拟主机中的错误页处理。下面为去除重复监听及首页配置后的相关指令,放在 server 中:
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
4.4 实验:验证 location 匹配规则
实验目标
通过本实验,直观验证六种 location 匹配方式的优先级和实际效果。
实验步骤
Step 1:确认 echo 模块已安装。
[root@magedu ~]# /usr/sbin/nginx -V 2>&1 | grep echo
--add-module=/usr/local/src/echo-nginx-module
如果没有输出,说明编译时未添加 echo 模块,需要重新编译。
Step 2:创建测试配置文件。
[root@magedu ~]# cat > /etc/nginx/conf.d/location-test.conf <<'EOF'
server {
listen 80;
server_name location.magedu.com;
# 日志
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
Step 3:测试配置并重载。
[root@magedu ~]# nginx -t
[root@magedu ~]# systemctl reload nginx
Step 4:验证各匹配规则。
# 1. 精确匹配测试
[root@magedu ~]# curl http://location.magedu.com/health
精确匹配(=):/health
[root@magedu ~]# curl http://location.magedu.com/health/
通用匹配(/):所有未被匹配的请求
# 注意:/health/ 不能匹配 = /health,会落到 / 兜底
# 2. 前缀优先匹配测试
[root@magedu ~]# curl http://location.magedu.com/static/css/style.css
前缀优先匹配(^~):/static/ 下的所有请求
# 3. 正则匹配(区分大小写).php
[root@magedu ~]# curl http://location.magedu.com/index.php
正则匹配(~):.php 结尾的请求
[root@magedu ~]# curl http://location.magedu.com/index.PHP
通用匹配(/):所有未被匹配的请求
# 注意:区分大小写,.PHP 不匹配
# 4. 正则匹配(不区分大小写).jpg
[root@magedu ~]# curl http://location.magedu.com/photo.jpg
正则匹配(~*):.jpg 或 .JPG 结尾的请求
[root@magedu ~]# curl http://location.magedu.com/photo.JPG
正则匹配(~*):.jpg 或 .JPG 结尾的请求
# 5. 通用前缀匹配(最长匹配原则)
[root@magedu ~]# curl http://location.magedu.com/api/v1/user
通用前缀匹配:/api/v1/(更长的匹配)
[root@magedu ~]# curl http://location.magedu.com/api/user
通用前缀匹配:/api/(较短的匹配)
# 6. 兜底匹配
[root@magedu ~]# curl http://location.magedu.com/anything
通用匹配(/):所有未被匹配的请求
匹配结果总结:
| 请求 URL | 匹配规则 | 说明 |
|---|---|---|
| /health | = /health 精确匹配 | 最高优先级,完全相等才匹配 |
| /health/ | / 通用匹配 | 精确匹配不包含 /health/ |
| /static/css/style.css | ^~ /static/ 前缀优先匹配 | 匹配后停止正则匹配 |
| /index.php | ~ .php$ 正则匹配(区分大小写) | 小写 .php 匹配 |
| /index.PHP | / 通用匹配 | 大写 .PHP 不匹配区分大小写的正则 |
| /photo.jpg | ~* .jpg$ 正则匹配(不区分大小写) | 小写 .jpg 匹配 |
| /photo.JPG | ~* .jpg$ 正则匹配(不区分大小写) | 大写 .JPG 也匹配 |
| /api/v1/user | /api/v1/ 通用前缀匹配 | 更长的匹配优先 |
| /api/user | /api/ 通用前缀匹配 | 匹配到较短的通用前缀 |
| /anything | / 通用匹配 | 兜底匹配 |
核心收获:通过这个实验,你直观地看到了 Nginx 如何根据不同的 location 规则将请求路由到不同的处理逻辑。这正是 Nginx 作为“流量入口”的核心能力——根据 URL 特征做精细化路由。
4.5 root vs alias 的区别
root 和 alias 都用于指定文件路径,但行为完全不同:
| 指令 | 路径拼接方式 | 示例 |
|---|---|---|
| root | root 路径 + location 路径 | root /var/www; + /images/1.jpg → /var/www/images/1.jpg |
| alias | alias 路径替换 location 路径 | alias /var/www/img/; + /images/1.jpg → /var/www/img/1.jpg |
配置对比
# root 方式:拼接路径
location /images/ {
root /var/www/static;
# 请求 /images/logo.png → 查找 /var/www/static/images/logo.png
}
# alias 方式:替换路径
location /images/ {
alias /var/www/static/img/;
# 请求 /images/logo.png → 查找 /var/www/static/img/logo.png
}
关键注意事项
| 注意事项 | root | alias |
|---|---|---|
| 末尾斜杠 | 可加可不加 | 必须加(否则路径拼接异常) |
| location 匹配 | 匹配路径会拼接到 root 后 | 匹配路径被 alias 完全替换 |
| 适用场景 | 常规静态文件服务 | 路径映射/重命名目录 |
# 错误:alias 忘记末尾斜杠
location /images/ {
alias /var/www/static/img;
# 请求 /images/logo.png → /var/www/static/imglogo.png(缺少 /)
}
# 正确
location /images/ {
alias /var/www/static/img/;
}
# root 无此问题
location /images/ {
root /var/www/static;
# 请求 /images/logo.png → /var/www/static/images/logo.png
}
实验验证
# 创建测试文件
[root@magedu ~]# mkdir -p /var/www/static/root-test
[root@magedu ~]# echo "root test" > /var/www/static/root-test/test.txt
[root@magedu ~]# mkdir -p /var/www/static/img
[root@magedu ~]# echo "alias test" > /var/www/static/img/test.txt
# 配置测试
[root@magedu ~]# cat > /etc/nginx/conf.d/root-alias-test.conf <<'EOF'
server {
listen 80;
server_name test.magedu.com;
location /root-test/ {
root /var/www/static;
}
location /alias-test/ {
alias /var/www/static/img/;
}
}
EOF
[root@magedu ~]# nginx -t && systemctl reload nginx
[root@magedu ~]# curl http://test.magedu.com/root-test/test.txt
root test # 实际读取 /var/www/static/root-test/test.txt
[root@magedu ~]# curl http://test.magedu.com/alias-test/test.txt
alias test # 实际读取 /var/www/static/img/test.txt
本实验采用第二份课件已修正的 root-test 路径,避免第一份课件中创建 images 目录而请求 root-test 导致的路径不一致。
五、实验:创建第一个静态网站
# 创建网站目录和首页
[root@magedu ~]# mkdir -p /var/www/ruoyi
[root@magedu ~]# cat > /var/www/ruoyi/index.html <<'EOF'
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>若依管理系统</title></head>
<body><h1>若依管理系统</h1><p>Nginx 静态页面测试成功!</p></body>
</html>
EOF
[root@magedu ~]# chown -R nginx:nginx /var/www/ruoyi
# 创建配置文件
[root@magedu ~]# cat > /etc/nginx/conf.d/ruoyi.conf <<'EOF'
server {
listen 80;
server_name ruoyi.magedu.com;
root /var/www/ruoyi;
index index.html;
}
EOF
# 测试并重载
[root@magedu ~]# nginx -t
[root@magedu ~]# systemctl reload nginx
# 验证
[root@magedu ~]# curl -I http://localhost/
HTTP/1.1 200 OK
第二份课件的完整请求验证:
[root@magedu ~]# curl http://ruoyi.magedu.com
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>若依管理系统</title></head>
<body><h1>若依管理系统</h1><p>Nginx 静态页面测试成功!</p></body>
</html>
[root@magedu ~]# curl -v http://ruoyi.magedu.com
* Host ruoyi.magedu.com:80 was resolved.
* IPv6: (none)
* IPv4: 10.0.0.144
* Trying 10.0.0.144:80...
* Connected to ruoyi.magedu.com (10.0.0.144) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: ruoyi.magedu.com
> User-Agent: curl/8.12.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Server: nginx/1.31.3
< Date: Thu, 30 Jul 2026 12:31:36 GMT
< Content-Type: text/html
< Content-Length: 180
< Last-Modified: Thu, 30 Jul 2026 12:28:30 GMT
< Connection: keep-alive
< ETag: "6a6b436e-b4"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>若依管理系统</title></head>
<body><h1>若依管理系统</h1><p>Nginx 静态页面测试成功!</p></body>
</html>
* Connection #0 to host ruoyi.magedu.com left intact
六、案例实战一:部署 WordPress 站点(PHP + MySQL)
6.1 整体架构

生产环境部署方式:
| 组件 | 实验环境(单机) | 生产环境(推荐) |
|---|---|---|
| Nginx | magedu | 独立接入层服务器 |
| PHP-FPM | magedu | 独立应用服务器(可水平扩展) |
| MySQL | magedu | 独立数据库服务器(主从/集群) |
| 层级 | 组件 | 主机名 | IP 地址 | 端口 | 作用 |
|---|---|---|---|---|---|
| 接入层 | Nginx | magedu | 192.168.100.10 | 80 | 接收用户请求,转发 .php 请求给 PHP-FPM |
| 应用层 | PHP-FPM | magedu | 192.168.100.10 | 9000 | 执行 WordPress 的 PHP 代码 |
| 数据层 | MySQL | magedu | 192.168.100.10 | 3306 | 存储 WordPress 数据 |
6.2 安装 MySQL
Rocky Linux 10 的 MySQL 软件包名是 mysql8.4-server。
# Rocky Linux 10 安装 MySQL
[root@magedu ~]# dnf install -y mysql8.4-server
# 启动 MySQL
[root@magedu ~]# systemctl enable --now mysqld
[root@magedu ~]# systemctl status mysqld
# Rocky 10 默认空密码,直接登录
[root@magedu ~]# mysql
# 创建 WordPress 数据库和用户
mysql> CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
mysql> CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'YANGge123@';
mysql> GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> EXIT;
Ubuntu 26.04 旁注:
[root@magedu ~]# apt install -y mysql-server
[root@magedu ~]# systemctl enable --now mysql
6.3 部署 PHP-FPM
6.3.1 安装 PHP-FPM 与监听方式
# Rocky Linux 10
[root@magedu ~]# dnf install -y php php-fpm php-mysqlnd php-gd php-xml php-mbstring
[root@magedu ~]# systemctl enable --now php-fpm
第一份课件使用 TCP 端口连接:
[root@magedu ~]# ss -tlnp | grep php-fpm
tcp LISTEN 0 128 127.0.0.1:9000 0.0.0.0:* users:(("php-fpm",pid=1234,fd=5))
第二份课件使用 Unix Socket,后文 WordPress 的完整配置采用此方式:
[root@magedu ~]# ls /run/php-fpm/www.sock
/run/php-fpm/www.sock
[root@magedu ~]# ps aux | grep php-fpm
root 10248 0.0 1.7 419860 29200 ? Ss 18:27 0:00 php-fpm: master process (/etc/php-fpm.conf)
apache 10250 0.0 0.6 419860 11640 ? S 18:27 0:00 php-fpm: pool www
apache 10251 0.0 0.6 419860 11640 ? S 18:27 0:00 php-fpm: pool www
apache 10252 0.0 0.6 419860 11636 ? S 18:27 0:00 php-fpm: pool www
apache 10253 0.0 0.6 419860 11640 ? S 18:27 0:00 php-fpm: pool www
apache 10254 0.0 0.6 419860 11652 ? S 18:27 0:00 php-fpm: pool www
Ubuntu 26.04 旁注:
[root@magedu ~]# apt install -y php php-fpm php-mysql php-gd php-xml php-mbstring
[root@magedu ~]# systemctl enable --now php8.4-fpm
# Ubuntu 默认使用 socket 通信:/run/php/php8.4-fpm.sock
6.3.2 PHP-FPM 进程管理模式
PHP-FPM 有三种进程管理模式,通过 pm 指令配置:
| 模式 | 说明 | 适用场景 |
|---|---|---|
| static | 固定进程数,启动时创建 pm.max_children 个进程,永不变化 | 高并发、内存充足的生产环境 |
| dynamic | 动态调整,根据负载在 min 和 max 之间调整进程数 | 大多数场景(默认) |
| ondemand | 按需创建,空闲进程在 pm.process_idle_timeout 后退出 | 低并发、内存敏感的场景 |
配置示例:
[root@magedu ~]# vim /etc/php-fpm.d/www.conf
; 管理模式选择
; static: 固定进程数
; dynamic: 动态调整(默认)
; ondemand: 按需创建
pm = dynamic
; static 模式配置
; pm.max_children = 50 ; 固定 50 个进程
; dynamic 模式配置(推荐)
pm.max_children = 50 ; 最大进程数(不能超过)
pm.start_servers = 10 ; 启动时创建 10 个进程
pm.min_spare_servers = 5 ; 最少空闲进程数
pm.max_spare_servers = 15 ; 最多空闲进程数
; ondemand 模式配置
; pm.max_children = 50
; pm.process_idle_timeout = 10s ; 空闲 10 秒后退出
进程数计算公式
pm.max_children 的计算公式(dynamic 模式):
max_children = (总内存 - 系统内存 - MySQL内存) / 单个PHP进程内存
示例:服务器 8GB 内存
- 系统 + MySQL ≈ 2GB
- 可用内存 ≈ 6GB
- 单个PHP进程 ≈ 30–50MB
- max_children = 6GB / 40MB ≈ 153
- 保守建议:80–100
查看当前进程数
# 查看 PHP-FPM 进程数量
[root@magedu ~]# ps aux | grep php-fpm | grep -v grep | wc -l
12
两份课件的进程计数示例分别为 12 和 7,实际数量取决于运行环境和负载。状态页的开启配置及完整输出统一见 6.7。
6.4 下载并配置 WordPress
# 下载 WordPress
[root@magedu ~]# cd /tmp
[root@magedu ~]# wget https://wordpress.org/latest.tar.gz
[root@magedu ~]# tar xzf latest.tar.gz
# 复制到网站目录
[root@magedu ~]# mkdir -p /var/www/wordpress
[root@magedu ~]# cp -r /tmp/wordpress/* /var/www/wordpress/
# 设置权限(Nginx 用户需读写权限)
[root@magedu ~]# chown -R nginx:nginx /var/www/wordpress
[root@magedu ~]# chmod -R 755 /var/www/wordpress
# 创建配置文件
[root@magedu ~]# cd /var/www/wordpress
[root@magedu ~]# cp wp-config-sample.php wp-config.php
[root@magedu ~]# vim wp-config.php
# 修改以下内容:
# DB_NAME = 'wordpress'
# DB_USER = 'wpuser'
# DB_PASSWORD = 'YANGge123@'
# DB_HOST = 'localhost'
6.5 配置 Nginx 代理 WordPress
先在主配置中定义 main 日志格式,并包含 conf.d 子配置。第二份课件给出的有效配置如下:
[root@magedu ~]# grep -Ev "^ *#|^$" /etc/nginx/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
# 打开日志格式定义
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
# 包含该目录下 *.conf 的子配置文件
include /etc/nginx/conf.d/*.conf;
}
创建 WordPress 虚拟主机:
[root@magedu ~]# cat > /etc/nginx/conf.d/wordpress.conf <<'EOF'
server {
listen 80;
server_name wordpress.magedu.com;
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
[root@magedu ~]# nginx -t
[root@magedu ~]# systemctl reload nginx
6.6 验证 WordPress
# 测试 PHP 是否正常
[root@magedu ~]# curl -I http://wordpress.magedu.com/
HTTP/1.1 200 OK
Server: nginx/1.30.4
# 浏览器访问 http://wordpress.magedu.com/
# 应显示 WordPress 安装页面
提前做好 Windows hosts 文件解析。浏览器按下面的画面完成站点初始化、登录和后台验证:




6.7 开启并查看 PHP-FPM 状态页
# PHP-FPM 配置
[root@magedu ~]# vim /etc/php-fpm.d/www.conf
; Default Value: not set
pm.status_path = /status
[root@magedu ~]# systemctl reload php-fpm.service
# nginx 配置:添加到 WordPress server 中
[root@magedu ~]# vim /etc/nginx/conf.d/wordpress.conf
location = /status {
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
[root@magedu ~]# systemctl reload nginx.service
# 查看 PHP-FPM 状态
[root@magedu ~]# curl http://127.0.0.1/status -H "Host: wordpress.magedu.com"
pool: www
process manager: dynamic
start time: 30/Jul/2026:19:25:19 +0800
start since: 14
accepted conn: 1
listen queue: 0
max listen queue: 0
listen queue len: 0
idle processes: 4
active processes: 1
total processes: 5
max active processes: 1
max children reached: 0
slow requests: 0
6.8 TCP 与 Unix Socket 两种连接方式对比

| 对比项 | TCP 端口方式 | Unix Socket 方式 |
|---|---|---|
| 地址 | 127.0.0.1:9000 | /run/php-fpm/www.sock |
| 网络开销 | 有(经过网络协议栈) | 无(本地进程间通信) |
| 性能 | 稍低 | 更高(推荐) |
| 跨机器 | 支持 | 仅限本机 |
| 配置复杂度 | 简单 | 需注意权限(listen.acl_users) |
对应 Nginx 配置
完整 WordPress 配置已采用 Socket 方式。选择 TCP 时,将该 PHP location 的 fastcgi_pass 改为:
fastcgi_pass 127.0.0.1:9000;
Socket 方式对应:
fastcgi_pass unix:/run/php-fpm/www.sock;
其余 FastCGI 参数保留完整配置中的设置。
PHP-FPM 配置
; /etc/php-fpm.d/www.conf
; 端口方式
; listen = 127.0.0.1:9000
; Socket 方式(推荐)
listen = /run/php-fpm/www.sock
listen.acl_users = apache,nginx
listen.mode = 0660
架构选择建议
| 场景 | 推荐方式 |
|---|---|
| 单机部署(Nginx + PHP-FPM 同机) | Unix Socket,性能更好 |
| 分布式部署(Nginx 和 PHP-FPM 分离) | TCP 端口,支持跨机通信 |
| 容器化环境(K8s/Docker) | TCP 端口或 Socket,取决于网络模型 |
七、案例实战二:部署 Flask 应用(Python + Gunicorn)
7.1 整体架构

生产环境部署方式:
| 组件 | 实验环境(单机) | 生产环境(推荐) |
|---|---|---|
| Nginx | magedu | 独立接入层服务器 |
| Gunicorn + Flask | magedu | 独立应用服务器(可水平扩展) |
| 层级 | 组件 | 主机名 | IP 地址 | 端口 | 作用 |
|---|---|---|---|---|---|
| 接入层 | Nginx | magedu | 192.168.100.10 | 80 | 接收用户请求,转发给 Gunicorn |
| 应用层 | Gunicorn + Flask | magedu | 192.168.100.10 | 8000 | WSGI 服务器,运行 Flask 应用 |
7.2 什么是 Gunicorn?
Gunicorn(Green Unicorn)是 Python 的 WSGI HTTP 服务器,用于运行 Python Web 应用。
类似 Java 中的 Tomcat、PHP 中的 PHP-FPM,Gunicorn 负责接收 Nginx 转发的请求,调用 Flask/Django 应用处理,并返回响应。

WSGI(Web Server Gateway Interface,Web 服务器网关接口)是 Python Web 应用与 Web 服务器之间的一种标准接口规范。原文将其表述为 Web 服务器(如 Nginx)和应用框架(如 Flask、Django)之间的通信协议。
严格来说,本例由 Gunicorn 实现 WSGI 接口,Nginx 与 Gunicorn 之间使用 HTTP 代理。
7.3 安装 Python 环境
# Rocky Linux 10 安装 Python 和 pip
[root@magedu ~]# dnf install -y python3 python3-pip
# 安装 Gunicorn 和 Flask
[root@magedu ~]# pip3 install gunicorn flask


7.4 创建 Flask 应用
# 创建应用目录
[root@magedu ~]# mkdir -p /var/www/flask-app
[root@magedu ~]# cd /var/www/flask-app
# 创建 Flask 应用
[root@magedu ~]# cat > 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}@magedu.com'
})
@app.route('/api/health')
def health():
return jsonify({'status': 'ok'})
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000)
EOF
7.5 启动 Gunicorn
# 使用 Gunicorn 启动 Flask 应用(绑定 127.0.0.1:8000)
[root@magedu ~]# cd /var/www/flask-app
[root@magedu ~]# gunicorn -w 4 -b 127.0.0.1:8000 app:app --daemon
# 参数说明:
# -w 4:4 个 Worker 进程
# -b 127.0.0.1:8000:绑定地址和端口
# app:app:模块名:应用实例名
# --daemon:后台运行
# 验证 Gunicorn 是否启动
[root@magedu flask-app]# ss -tnlp | grep 8000
LISTEN 0 2048 127.0.0.1:8000 0.0.0.0:* users:(("gunicorn",pid=10981,fd=3),("gunicorn",pid=10980,fd=3),("gunicorn",pid=10979,fd=3),("gunicorn",pid=10978,fd=3),("gunicorn",pid=10977,fd=3))
7.6 配置 Nginx 代理 Python 应用
[root@magedu ~]# cat > /etc/nginx/conf.d/flask.conf <<'EOF'
server {
listen 80;
server_name flask.magedu.com;
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
[root@magedu ~]# nginx -t
[root@magedu ~]# systemctl reload nginx
7.7 验证 Flask 应用
# 直接测试 Gunicorn
[root@magedu ~]# curl http://127.0.0.1:8000/
{"message":"Hello from Flask!","status":"success"}
# 通过 Nginx 访问
[root@magedu ~]# curl http://flask.magedu.com/api/user/100
{"email":"user100@magedu.com","name":"User_100","uid":100}
# 不依赖域名解析的本机测试方式
[root@magedu flask-app]# curl http://127.0.0.1/api/user/100 -H "Host: flask.magedu.com"
{"email":"user100@magedu.com","name":"User_100","uid":100}
# 浏览器访问 http://flask.magedu.com/
# 应显示 JSON 响应

八、本章小结
8.1 核心知识点速记
Nginx 架构:Master 管 Worker,Worker 处理请求,epoll 高并发,单机数万连。
IO 模型:BIO 一个连接一个线程,select 轮询所有连接,epoll 只通知活跃连接。
location 优先级:= 最高,^~ 次之,~ 正则排第三,最后才是通用匹配。
root vs alias:root 拼接路径,alias 替换路径。
静态 vs 动态模块:静态编译进二进制,生产推荐;动态生成 .so,版本匹配是隐患。
Nginx 与 PHP-FPM:Nginx 接收 HTTP 请求,.php 请求通过 FastCGI 转发给 PHP-FPM。
Nginx 与 Gunicorn:Nginx 接收 HTTP 请求,通过 proxy_pass 转发给 Gunicorn(Python 应用)。
平滑升级:USR2 启动新版本 → WINCH 停止旧 Worker → QUIT 退出旧 Master。
8.2 常用命令速查
| 操作 | 命令 |
|---|---|
| 语法检查 | nginx -t |
| systemd 重载 | systemctl reload nginx |
| 原生重载 | nginx -s reload |
| 原生停止 | nginx -s stop |
| 原生优雅停止 | nginx -s quit |
| 平滑升级 | kill -USR2 $(cat /var/run/nginx.pid) |
| 查看版本 | nginx -v |
| 查看编译参数(升级前必做) | nginx -V |
| 保存编译参数 | nginx -V 2>&1 | tee /opt/nginx-build-args.txt |
8.3 学完本节应能独立完成
- 理解 Nginx 的 Master-Worker 进程模型。
- 理解三种 IO 模型的区别。
- 源码编译安装 Nginx 并添加第三方模块。
- 执行 Nginx 平滑升级。
- 部署 WordPress 站点(Nginx + PHP-FPM + MySQL 8.4)。
- 部署 Flask 应用(Nginx + Gunicorn + Python)。
- 配置 Nginx 代理 PHP 和 Python 两种后端。
- 区分 root 和 alias 的使用场景。
下一节预告
Day 9-2:反向代理与负载均衡。
我们将学习反向代理(转发请求给 Java/PHP/Python 后端)和负载均衡(分发请求到多台后端),让 Nginx 从“静态 Web 服务器”升级为“流量入口”。
评论