一、升级背景
当前环境
| 服务器 | Nginx 版本 | OpenSSL | GCC | 编译参数 |
|---|---|---|---|---|
| 119 | 1.26.2 | 1.0.2h | 4.8.5 (Red Hat 4.8.5-16) | --prefix=/usr/local/nginx-1.26.2 --with-http_stub_status_module --with-http_ssl_module --with-openssl=/usr/local/openssl-1.0.2h |
| 12 | 1.26.2 | 1.0.2h | 4.8.5 (Red Hat 4.8.5-4) | --with-http_ssl_module --with-openssl=/opt/openssl-1.0.2h |
| 40 | 1.26.2 | 1.0.2h | 4.8.5 (Red Hat 4.8.5-16) | --with-http_ssl_module --with-openssl=/opt/openssl-1.0.2h --with-http_v2_module |
升级原因
- OpenSSL 1.0.2h 于 2018 年 12 月 EOL,存在大量已知安全漏洞,不支持 TLS 1.3
- Nginx 1.30.x 是新的稳定分支,包含性能优化和安全修复
- Nginx 1.30.0+ 对 OpenSSL 有最低版本要求(≥ 1.1.1),必须同步升级 OpenSSL
- 2026年5月,安全研究机构 depthfirst 披露了潜伏18年的 Nginx 高危漏洞 CVE-2026-42945(别名 NGINX Rift),CVSS 评分高达 9.2。该堆缓冲区溢出漏洞影响 Nginx 0.6.27 至 1.30.0 全系列版本,全球约 570 万台服务器面临威胁,中国受影响网站超 254 万。
目标版本
| 组件 | 当前版本 | 目标版本 |
|---|---|---|
| Nginx | 1.26.2 | 1.30.2 |
| OpenSSL | 1.0.2h | 3.0.20 (LTS) |
环境约束
- 三台服务器均为离线环境,无法访问互联网
- 所有源码包、依赖 RPM 包需在有网机器上下载后,通过 U 盘/内网传输到目标服务器
- 建议在一台有网的 CentOS 7 机器上准备所有物料
二、离线物料准备(在有网机器上操作)
2.1 下载源码包
bash
mkdir -p /usr/local/src/nginx-upgrade-pkg && cd /usr/local/src/nginx-upgrade-pkg
# 下载 Nginx 1.30.2
curl -O https://nginx.org/download/nginx-1.30.2.tar.gz
# 下载 OpenSSL 3.0.20
curl -O https://www.openssl.org/source/openssl-3.0.20.tar.gz
2.2 下载依赖 RPM 包
关键 :
yum install --downloadonly对已安装的包不会下载(直接提示 "already installed"),必须使用yumdownloader才能确保所有包都下载到本地,无论是否已安装。
ini
mkdir -p /usr/local/src/nginx-upgrade-pkg/rpms
# 安装 yum-utils(提供 yumdownloader 命令)
yum install -y yum-utils
# 基础编译工具(服务器上可能已有,但离线环境以防万一)
yumdownloader --resolve --destdir=/usr/local/src/nginx-upgrade-pkg/rpms \
gcc gcc-c++ make perl
# OpenSSL 3.x 编译需要的 Perl 模块(CentOS 7 默认缺失,需一次性补齐)
yumdownloader --resolve --destdir=/usr/local/src/nginx-upgrade-pkg/rpms \
perl-IPC-Cmd perl-Pod-Html perl-ExtUtils-MakeMaker perl-Time-Piece \
perl-Test-Harness perl-Test-Simple perl-FindBin perl-File-Temp
# Nginx 依赖
yumdownloader --resolve --destdir=/usr/local/src/nginx-upgrade-pkg/rpms \
pcre pcre-devel zlib zlib-devel
# GCC 升级(devtoolset-7,编译 OpenSSL 3.0.20 可能需要)
# CentOS 7 自带 GCC 4.8.5 可能无法编译 OpenSSL 3.0.20
# 注意:CentOS 7 已 EOL,SCL 源需切换到 vault 归档
yum install -y centos-release-scl
# 修复 SCL 源:注释失效的 mirrorlist,改用 vault 归档地址
# rh 仓库
sed -i 's/^mirrorlist=/#mirrorlist=/' /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo
sed -i 's|^#baseurl=http://mirror.centos.org/centos/7/sclo/$basearch/rh|baseurl=https://vault.centos.org/7.9.2009/sclo/$basearch/rh|' /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo
# sclo 仓库(注意原始 baseurl 前有 "# ",需匹配井号+空格)
sed -i 's/^mirrorlist=/#mirrorlist=/' /etc/yum.repos.d/CentOS-SCLo-scl.repo
sed -i 's|^# baseurl=http://mirror.centos.org/centos/7/sclo/$basearch/sclo/|baseurl=https://vault.centos.org/7.9.2009/sclo/$basearch/sclo/|' /etc/yum.repos.d/CentOS-SCLo-scl.repo
yum clean all
yum makecache
yumdownloader --resolve --destdir=/usr/local/src/nginx-upgrade-pkg/rpms \
devtoolset-7-gcc devtoolset-7-gcc-c++ devtoolset-7-binutils
说明 :
yumdownloader --resolve会自动解析并下载依赖的子包,且不受是否已安装的影响,所有 RPM 都会下载到指定目录。
2.3 打包传输
bash
cd /usr/local/src
tar czf nginx-upgrade-pkg.tar.gz nginx-upgrade-pkg/
# 通过 U 盘或内网传输到三台目标服务器
# scp nginx-upgrade-pkg.tar.gz root@目标IP:/usr/local/src/
三、升级前准备(在目标服务器上操作)
3.1 解压物料包
bash
cd /usr/local/src
tar xzf nginx-upgrade-pkg.tar.gz
3.2 备份当前 Nginx
bash
# 备份整个 Nginx 目录
cp -a /usr/local/nginx-1.26.2 /usr/local/nginx-1.26.2.bak.$(date +%Y%m%d)
cp -a /usr/local/nginx /usr/local/nginx.bak.$(date +%Y%m%d)
# 备份配置文件(额外保险)
cp -a /usr/local/nginx-1.26.2/conf /root/nginx-conf-backup-$(date +%Y%m%d)
# 记录当前编译参数
/usr/local/nginx-1.26.2/sbin/nginx -V 2>&1 | tee /root/nginx-compile-args-backup.txt
3.3 确认当前运行状态
perl
# 检查 Nginx 进程
ps aux | grep nginx
# 检查监听端口
ss -tlnp | grep nginx
# 检查配置是否正常
/usr/local/nginx-1.26.2/sbin/nginx -t
3.4 离线安装依赖 RPM
bash
cd /usr/local/src/nginx-upgrade-pkg/rpms
# 离线安装所有 RPM(已安装的会跳过或升级)
rpm -Uvh --nodeps --force *.rpm
# 或者用 yum 本地安装(自动处理依赖关系,但离线环境可能缺依赖)
# yum localinstall -y *.rpm
注意 :
rpm -Uvh --nodeps跳过依赖检查,安装速度快但可能遗漏子依赖。如果后续编译报错提示缺少某个库,回到有网机器上单独下载该依赖 RPM 再传过来。
3.5 解压源码
bash
cd /usr/local/src/nginx-upgrade-pkg
tar xzf nginx-1.30.2.tar.gz
tar xzf openssl-3.0.20.tar.gz
四、编译安装 OpenSSL 3.0.20
注意 :Nginx 1.30.x 编译时通过
--with-openssl=指向 OpenSSL 源码目录即可,Nginx 会自动编译 OpenSSL。但也可以先独立安装 OpenSSL 到系统路径,再让 Nginx 引用。这里采用独立安装方式,便于后续其他程序也能使用新版 OpenSSL。
4.1 检查 GCC 版本是否满足要求
bash
gcc --version
# 如果 GCC 版本 >= 4.8.5,先尝试直接编译
# 如果编译 OpenSSL 报错,需要启用 devtoolset-7
如果需要升级 GCC:
bash
# 启用 devtoolset-7(GCC 7.x),仅在当前 shell 生效
scl enable devtoolset-7 "bash"
gcc --version
# 预期: gcc (GCC) 7.3.1
4.2 编译安装
bash
cd /usr/local/src/nginx-upgrade-pkg/openssl-3.0.20
# OpenSSL 3.x 编译配置
# --prefix: 安装路径,不影响系统自带 OpenSSL
# --openssldir: 配置文件路径
# shared: 编译动态库
./config \
--prefix=/usr/local/openssl-3.0.20 \
--openssldir=/usr/local/openssl-3.0.20/ssl \
shared \
zlib
make -j$(nproc)
make install
4.3 配置动态链接库
bash
# 添加动态库搜索路径
echo "/usr/local/openssl-3.0.20/lib64" > /etc/ld.so.conf.d/openssl-3.0.20.conf
ldconfig
# 验证安装
/usr/local/openssl-3.0.20/bin/openssl version
# 预期输出: OpenSSL 3.0.20
4.4 备份旧版 OpenSSL(可选)
bash
# 119 服务器
mv /usr/local/openssl-1.0.2h /usr/local/openssl-1.0.2h.bak
# 12 和 40 服务器
mv /opt/openssl-1.0.2h /opt/openssl-1.0.2h.bak
五、编译安装 Nginx 1.30.2
5.1 编译参数适配
关键变化:
- Nginx 1.25.1+ 中
--with-http_v2_module仍然可用,同时新增--with-http_v3_module(HTTP/3,实验性) - OpenSSL 路径改为指向新的源码目录或安装目录
- 建议统一
--prefix格式为/usr/local/nginx-1.30.2
5.2 各服务器编译命令
119 服务器:
javascript
cd /usr/local/src/nginx-upgrade-pkg/nginx-1.30.2
./configure \
--prefix=/usr/local/nginx-1.30.2 \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-openssl=/usr/local/src/nginx-upgrade-pkg/openssl-3.0.20 \
--with-http_v2_module
make -j$(nproc)
12 服务器:
javascript
cd /usr/local/src/nginx-upgrade-pkg/nginx-1.30.2
./configure \
--prefix=/usr/local/nginx-1.30.2 \
--with-http_ssl_module \
--with-openssl=/usr/local/src/nginx-upgrade-pkg/openssl-3.0.20 \
--with-http_v2_module
make -j$(nproc)
40 服务器:
javascript
cd /usr/local/src/nginx-upgrade-pkg/nginx-1.30.2
./configure \
--prefix=/usr/local/nginx-1.30.2 \
--with-http_ssl_module \
--with-openssl=/usr/local/src/nginx-upgrade-pkg/openssl-3.0.20 \
--with-http_v2_module
make -j$(nproc)
说明 :12 和 40 服务器原编译参数没有
--prefix,默认 prefix 为/usr/local/nginx。升级时建议显式指定--prefix=/usr/local/nginx-1.30.2,便于版本管理和回滚。如果希望保持原有行为(直接替换/usr/local/nginx),可以省略--prefix或设为/usr/local/nginx。
建议 :三台服务器统一加上--with-http_v2_module,因为 OpenSSL 3.0.20 已原生支持 ALPN(HTTP/2 必需),且现代浏览器基本都支持 HTTP/2。
5.3 编译后验证
bash
# 检查编译结果(不安装)
./objs/nginx -V
# 确认输出中包含:
# nginx version: nginx/1.30.2
# built with OpenSSL 3.0.20
六、平滑升级(热替换)
核心思路:Nginx 支持热升级------启动新 master 进程接管,旧 master 进程优雅退出,整个过程不中断服务。
6.1 安装新版本
bash
cd /usr/local/src/nginx-upgrade-pkg/nginx-1.30.2
# 方式一:make install(如果 prefix 是新路径,不影响旧版)
make install
# 方式二:只替换二进制文件(更安全,推荐)
# 先 make install 到新 prefix,再手动做热替换
6.2 迁移配置文件
bash
# 119 服务器
cp -a /usr/local/nginx-1.26.2/conf/* /usr/local/nginx-1.30.2/conf/
# 12 和 40 服务器(如果 prefix 是 /usr/local/nginx)
cp -a /usr/local/nginx/conf/* /usr/local/nginx-1.30.2/conf/
# 检查配置兼容性
/usr/local/nginx-1.30.2/sbin/nginx -t -c /usr/local/nginx-1.30.2/conf/nginx.conf
6.3 执行热替换
bash
# 步骤1:发送 USR2 信号,启动新 master 进程
# 旧 master 进程会重命名为 .oldbin
kill -USR2 $(cat /usr/local/nginx-1.26.2/logs/nginx.pid)
# 此时会有两个 master 进程并存:
# - 旧 master (nginx.pid)
# - 新 master (nginx.pid.newbin)
# 步骤2:等待新 master 启动完成
sleep 3
ps aux | grep nginx
# 步骤3:发送 WINCH 信号,让旧 master 的 worker 优雅退出
kill -WINCH $(cat /usr/local/nginx-1.26.2/logs/nginx.pid.oldbin)
# 步骤4:确认旧 worker 全部退出后,发送 QUIT 信号关闭旧 master
kill -QUIT $(cat /usr/local/nginx-1.26.2/logs/nginx.pid.oldbin)
# 步骤5:验证新版本
/usr/local/nginx-1.30.2/sbin/nginx -V
curl -I https://localhost # 验证服务正常
6.4 如果 prefix 相同(直接替换 /usr/local/nginx)
bash
# 备份旧二进制
cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.1.26.2.bak
# 复制新二进制
cp /usr/local/src/nginx-upgrade-pkg/nginx-1.30.2/objs/nginx /usr/local/nginx/sbin/nginx
# 热替换
kill -USR2 $(cat /usr/local/nginx/logs/nginx.pid)
sleep 3
kill -WINCH $(cat /usr/local/nginx/logs/nginx.pid.oldbin)
sleep 2
kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid.oldbin)
# 验证
/usr/local/nginx/sbin/nginx -V
七、升级后验证
7.1 版本确认
ini
nginx -V
# 预期输出:
# nginx version: nginx/1.30.2
# built with OpenSSL 3.0.20
# TLS SNI support enabled
7.2 TLS 版本支持
perl
# 检查支持的 TLS 版本(应包含 TLS 1.3)
openssl s_client -connect localhost:443 -tls1_3 < /dev/null 2>&1 | grep "TLSv1.3"
# 检查证书和协议
curl -vvv https://localhost 2>&1 | grep -E "SSL connection|TLS"
7.3 功能验证
bash
# HTTP/2 支持
curl -I --http2 https://localhost
# stub_status 模块(119 服务器)
curl http://localhost/nginx_status
# 业务接口验证
curl -I https://localhost/你的业务路径
7.4 性能观察
bash
# 观察连接数和请求处理
watch -n 1 'ss -s && echo "---" && curl -s http://localhost/nginx_status 2>/dev/null'
# 检查错误日志
tail -f /usr/local/nginx-1.30.2/logs/error.log
八、回滚方案
8.1 热替换回滚(升级后短时间内)
bash
# 如果旧 master 进程还在(未发送 QUIT)
# 恢复旧 master
kill -HUP $(cat /usr/local/nginx/logs/nginx.pid.oldbin)
kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid)
# 如果旧 master 已退出,需要手动启动旧版
/usr/local/nginx-1.26.2/sbin/nginx -c /usr/local/nginx-1.26.2/conf/nginx.conf
8.2 二进制替换回滚
bash
# 停止新版 Nginx
/usr/local/nginx-1.30.2/sbin/nginx -s stop
# 恢复旧版二进制
cp /usr/local/nginx/sbin/nginx.1.26.2.bak /usr/local/nginx/sbin/nginx
# 启动旧版
/usr/local/nginx/sbin/nginx
8.3 完整回滚(恢复整个目录)
bash
# 停止 Nginx
nginx -s stop
# 恢复备份
rm -rf /usr/local/nginx-1.30.2
mv /usr/local/nginx-1.26.2.bak.YYYYMMDD /usr/local/nginx-1.26.2
# 启动旧版
/usr/local/nginx-1.26.2/sbin/nginx
九、注意事项与踩坑
9.1 离线环境特有问题
- 依赖链不完整 :
rpm -Uvh --nodeps跳过依赖检查,可能遗漏子依赖。编译时如果报错xxx not found,需回到有网机器下载对应 RPM - Perl 模块逐个补齐 :OpenSSL 3.x 的 Configure 脚本依赖多个 Perl 模块,CentOS 7 默认缺失,编译时会逐个报
Can't locate xxx.pm,需逐个安装对应 RPM - devtoolset 安装 :离线安装 devtoolset RPM 包较多,建议在有网机器上用
yumdownloader --resolve递归下载所有依赖 - SCL 源失效 :CentOS 7 已 EOL,
mirrorlist.centos.org不可达,需将 SCL repo 的 baseurl 改为vault.centos.org归档地址 - 源码路径 :所有源码放在
/usr/local/src/nginx-upgrade-pkg/下,编译参数中的--with-openssl=路径要与此一致 - 传输方式:如果 U 盘传输,注意文件系统格式(exFAT/FAT32 支持大文件,NTFS 在 CentOS 7 需额外驱动)
9.2 OpenSSL 3.x 兼容性
- OpenSSL 3.0 对部分旧密码套件默认禁用(如 3DES、RC4),如果业务依赖这些套件需要在
nginx.conf中显式配置 - OpenSSL 3.0 的
ssl.conf配置路径变化:从/usr/local/openssl-1.0.2h/ssl/openssl.cnf变为/usr/local/openssl-3.0.20/ssl/openssl.cnf - 如果有 Lua 或第三方模块依赖旧版 OpenSSL 动态库,需要重新编译
9.3 Nginx 1.30.x 配置变化
listen 443 ssl http2;写法在 1.25.1+ 中仍可用,但推荐新写法listen 443 ssl; http2 on;- 如果使用
listen 443 spdy,需要改为http2(SPDY 早已废弃) ssl on;指令在 1.25.1+ 中已移除,统一使用listen 443 ssl;
9.4 CentOS 7 GCC 版本
- GCC 4.8.5 可以编译 Nginx 1.30.2,但编译 OpenSSL 3.0.20 可能需要更高版本 GCC
- 如果 OpenSSL 编译报错,启用 devtoolset-7:
bash
scl enable devtoolset-7 "bash"
# 在新 shell 中编译 OpenSSL 和 Nginx
9.5 动态库冲突
- 系统自带 OpenSSL 1.0.2(CentOS 7 默认)可能与新版冲突
- 确保
/etc/ld.so.conf.d/openssl-3.0.20.conf优先级正确 - Nginx 编译时如果使用
--with-openssl=指向源码,Nginx 会静态链接 OpenSSL,避免动态库冲突(推荐)
9.6 systemd/service 管理
- 如果使用 systemd 管理 Nginx,需要更新 service 文件中的路径
- 如果使用
nginx.service,更新ExecStart指向新路径
shell
# 更新 systemd service
vim /usr/lib/systemd/system/nginx.service
# 修改 ExecStart=/usr/local/nginx-1.30.2/sbin/nginx
systemctl daemon-reload
systemctl restart nginx