Nginx 平滑升级(Ubuntu 24.04 环境)
一、平滑升级核心原理
Nginx 平滑升级通过向主进程发送特定信号实现,核心优势是不中断现有请求处理:
- 新请求逐步由新版本 Worker 进程接管;
- 旧 Worker 进程处理完现有连接后优雅退出;
- 全程保持服务可用,无连接拒绝或请求中断;
- 核心信号机制:通过
USR2/WINCH/QUIT等信号实现新旧进程的无缝切换,而非直接重启服务。
二、前置准备
2.1 环境检查(核心基础)
-
查看当前 Nginx 版本和编译参数(新版本必须复用完全一致的编译参数,仅修复语法错误):
bashnginx -v # 查看版本(示例:1.24.0) nginx -V # 查看编译参数(完整复制,后续编译新版本用,关键!)实操示例输出:
bashroot@Ubuntu24-13:~# nginx -v nginx version: nginx/1.24.0 (Ubuntu) root@Ubuntu24-13:~# nginx -V nginx version: nginx/1.24.0 (Ubuntu) built with OpenSSL 3.0.13 30 Jan 2024 TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/build/nginx-WLuzPu/nginx-1.24.0=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=/build/nginx-WLuzPu/nginx-1.24.0=/usr/src/nginx-1.24.0-2ubuntu7.5 -fPIC -Wdate-time -D_FORTIFY_SOURCE=3' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=stderr --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-mail_ssl_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-http_geoip_module=dynamic --with-http_image_filter_module=dynamic --with-http_perl_module=dynamic --with-http_xslt_module=dynamic --with-mail=dynamic --with-stream=dynamic --with-stream_geoip_module=dynamic -
确保 Nginx 进程数充足(便于测试升级效果):
bash# 安装编辑器(若未安装) apt install vim -y # 编辑配置文件 vim /etc/nginx/nginx.conf # 修改 worker_processes 为 2(原若为 auto 则改为固定值,便于观察进程切换) worker_processes 2; # 重载配置(不中断服务) nginx -s reload # 验证进程数 ps aux | grep nginx实操示例输出(需看到 1 个 Master + 2 个 Worker 进程):
bashroot@Ubuntu24-13:~# nginx -s reload 2025/12/16 21:32:12 [notice] 3100#3100: signal process started root@Ubuntu24-13:~# ps aux | grep nginx root 2580 0.0 0.3 59440 13676 ? S 21:13 0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; www-data 3101 0.0 0.1 60264 6284 ? S 21:32 0:00 nginx: worker process www-data 3102 0.0 0.1 60264 6176 ? S 21:32 0:00 nginx: worker process root 3104 0.0 0.0 17832 2340 pts/0 S+ 21:32 0:00 grep --color=auto nginx
2.2 全量依赖环境准备(解决所有编译报错)
编译新版本需安装全量依赖(覆盖所有模块,避免 xslt、image_filter、geoip、perl 等模块编译报错):
bash
apt update && apt install -y build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev perl libperl-dev libxml2 libxml2-dev libxslt1-dev libgd-dev libpng-dev libjpeg-dev libfreetype6-dev libgeoip-dev curl
针对性解决依赖兼容问题:
| 报错场景 | 解决命令 |
|---|---|
Perl 库报错 libperl.so 找不到 |
find / -name libperl.so* && ln -s /usr/lib/x86_64-linux-gnu/libperl.so.5.38 /usr/lib/x86_64-linux-gnu/libperl.so(版本按实际修改) |
GeoIP 模块报错 GeoIP library not found |
apt install -y libgeoip-dev |
image_filter 模块报错 GD library not found |
apt install -y libgd-dev libpng-dev libjpeg-dev |
xslt 模块报错 libxml2/libxslt libraries not found |
apt install -y libxml2-dev libxslt1-dev |
2.3 下载新版本源码(版本选择原则)
- 优先小版本升级(如 1.24.0 → 1.25.0),避免跨大版本(如 1.18 → 1.25)的兼容性问题;
- 仅下载官方源码包,拒绝第三方修改包,保证安全性。
bash
# 创建统一目录结构(便于管理)
mkdir -p /data/softs /data/server/nginx/backup
cd /data/softs
# 下载新版本(以 1.25.0 为例,可替换为目标版本)
wget http://nginx.org/download/nginx-1.25.0.tar.gz
# 校验包完整性(可选,推荐生产环境执行)
md5sum nginx-1.25.0.tar.gz # 对比官网公布的 MD5 值
# 解压
tar xf nginx-1.25.0.tar.gz
cd nginx-1.25.0
三、编译新版本 Nginx(核心避坑)
3.1 复用旧版本编译参数(仅修复1处关键错误)
将 nginx -V 输出的 configure arguments: 后的参数完整复制,仅移除 --with-ld-opt 末尾的 -fPIC(这是 Ubuntu 系统编译的核心语法错误,其余参数完全保留),执行以下命令:
bash
./configure --with-cc-opt='-g -O2 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -ffile-prefix-map=/build/nginx-WLuzPu/nginx-1.24.0=. -flto=auto -ffat-lto-objects -fstack-protector-strong -fstack-clash-protection -Wformat -Werror=format-security -fcf-protection -fdebug-prefix-map=/build/nginx-WLuzPu/nginx-1.24.0=/usr/src/nginx-1.24.0-2ubuntu7.5 -fPIC -Wdate-time -D_FORTIFY_SOURCE=3' --with-ld-opt='-Wl,-Bsymbolic-functions -flto=auto -ffat-lto-objects -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=stderr --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module --with-http_sub_module --with-mail_ssl_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-http_geoip_module=dynamic --with-http_image_filter_module=dynamic --with-http_perl_module=dynamic --with-http_xslt_module=dynamic --with-mail=dynamic --with-stream=dynamic --with-stream_geoip_module=dynamic
3.2 编译(仅编译,绝对禁止执行 make install!)
bash
make # 仅编译二进制文件,不覆盖系统现有配置和程序
编译耗时约1-2分钟,编译完成后,新版本二进制文件位于
./objs/nginx。
3.3 编译后验证(必做)
bash
# 验证版本是否正确
./objs/nginx -v # 应输出 nginx/1.25.0
# 验证配置加载是否正常
./objs/nginx -t -c /etc/nginx/nginx.conf # 用新版本验证现有配置
实操示例输出:
bash
root@Ubuntu24-13:/data/softs/nginx-1.25.0# ./objs/nginx -v
nginx version: nginx/1.25.0
root@Ubuntu24-13:/data/softs/nginx-1.25.0# ./objs/nginx -t -c /etc/nginx/nginx.conf
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
四、平滑升级操作(分步执行,全程可回滚)
4.1 备份旧版本二进制文件(安全第一)
bash
# 备份旧版本(带时间戳,便于追溯)
mv /usr/sbin/nginx /usr/sbin/nginx-$(nginx -v 2>&1 | awk -F '/' '{print $2}')-$(date +%Y%m%d)
# 替换为新版本二进制文件
cp /data/softs/nginx-1.25.0/objs/nginx /usr/sbin/nginx
# 赋予执行权限(确保 root 可执行)
chmod +x /usr/sbin/nginx
# 验证版本(此时仅替换文件,进程仍为旧版本)
nginx -v # 输出 nginx/1.25.0
4.2 启动新版本 Master 进程(核心步骤)
-
获取旧版本 Master 进程 PID:
bashold_pid=$(cat /run/nginx.pid) echo "旧 Master PID:$old_pid"实操示例输出:
bashroot@Ubuntu24-13:/data/softs/nginx-1.25.0# old_pid=$(cat /run/nginx.pid) root@Ubuntu24-13:/data/softs/nginx-1.25.0# echo "旧 Master PID:$old_pid" 旧 Master PID:2580 -
发送
USR2信号,启动新版本 Master 进程:bashkill -USR2 $old_pid -
验证进程状态(此时应存在新旧两个 Master 进程):
bashps auxf | grep nginx ls /run/nginx.pid* # 旧 PID 文件会被重命名为 nginx.pid.oldbin正常输出特征:
bashroot 2580 0.0 0.3 59440 13676 ? S 21:13 0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; # 旧 Master www-data 3101 0.0 0.1 60264 6284 ? S 21:32 0:00 \_ nginx: worker process www-data 3102 0.0 0.1 60264 6176 ? S 21:32 0:00 \_ nginx: worker process root 22771 0.0 0.1 11060 7016 ? S 22:26 0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on; # 新 Master www-data 22772 0.0 0.1 12808 4360 ? S 22:26 0:00 \_ nginx: worker process www-data 22773 0.0 0.1 12808 4488 ? S 22:26 0:00 \_ nginx: worker process
4.3 优雅关闭旧 Worker 进程(新请求接管)
发送 WINCH 信号,让旧 Master 关闭其 Worker 进程,新请求全部由新版本 Worker 处理:
bash
kill -WINCH $old_pid
# 验证新版本接管服务(核心验证)
curl -I 127.0.0.1 | grep Server # 应输出 nginx/1.25.0
4.4 确认升级完成(彻底退出旧 Master)
- 建议观察 1-5 分钟(生产环境可延长至 10-15 分钟),确认业务无异常后再执行;
- 若期间出现问题,可立即执行回滚操作(见第五章)。
bash
# 优雅退出旧 Master 进程
kill -QUIT $old_pid
# 最终验证进程(仅保留新版本 Master + Worker)
ps auxf | grep nginx
正常输出示例:
bash
root 22771 0.0 0.1 11060 7016 ? S 22:26 0:00 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
www-data 22772 0.0 0.1 12808 4360 ? S 22:26 0:00 \_ nginx: worker process
www-data 22773 0.0 0.1 12808 4488 ? S 22:26 0:00 \_ nginx: worker process

五、平滑回滚(新版本异常时,秒级恢复)
若新版本出现卡顿、502、配置报错等问题,立即执行以下步骤回滚至旧版本:
5.1 恢复旧版本二进制文件
bash
# 替换回旧版本二进制(以 1.24.0 为例,按实际备份名修改)
mv /usr/sbin/nginx /usr/sbin/nginx-1.25.0
mv /usr/sbin/nginx-1.24.0-20251216 /usr/sbin/nginx
5.2 重启旧版本 Worker 进程
bash
# 获取旧 Master PID(升级时保留的 oldbin 文件)
old_master_pid=$(cat /run/nginx.pid.oldbin)
# 拉起旧 Worker 进程
kill -HUP $old_master_pid
5.3 退出新版本 Master 进程
bash
new_master_pid=$(cat /run/nginx.pid)
kill -QUIT $new_master_pid
5.4 验证回滚结果
bash
# 进程仅保留旧版本
ps auxf | grep nginx
# 请求返回旧版本标识
curl -I 127.0.0.1 | grep Server # 输出 nginx/1.24.0
六、高频问题解决方案
| 问题现象 | 根因 | 解决方案 |
|---|---|---|
| USR2 信号发送后,无新 Master 进程启动 | 1. 新版本二进制替换错误;2. 配置校验失败;3. 动态模块版本不兼容 | 1. 验证 nginx -v 为新版本;2. 执行 nginx -t 修复配置;3. 禁用不兼容模块:mkdir -p /etc/nginx/modules-enabled/bak && mv /etc/nginx/modules-enabled/*.conf /etc/nginx/modules-enabled/bak/ |
配置校验报错 module xxx.so version 1024000 instead of 1025000 |
系统预装的动态模块(如 geoip2、image_filter)是针对旧版本编译的,与新版本主程序不兼容 | 方案1(快速):禁用不兼容模块(如上);方案2(恢复功能):重新编译模块:cd /data/softs/nginx-1.25.0 && ./configure nginx -V 2>&1 |
| configure 报错"xxx library not found" | 缺少对应模块的依赖库 | 对照 2.2 节安装依赖,非关键提示(如 sys/filio.h not found、/dev/poll not found)可忽略 |
| 新请求被拒绝/端口未监听 | 1. 新版本配置错误;2. 端口被占用 | 1. nginx -t 修复配置;2. `netstat -tulpn |
| Perl 模块编译失败 | 缺少 Perl 开发库或软链接错误 | apt install -y libperl-dev + 重新创建 libperl.so 软链接 |
编译时报 flto=auto 错误 |
GCC 版本兼容问题 | 将编译参数中的 -flto=auto -ffat-lto-objects 改为 -flto |
七、关键注意事项
7.1 版本与参数规范
- 编译参数:仅移除
--with-ld-opt末尾的-fPIC,其余参数必须与旧版本完全一致,否则信号机制会失效; - 版本选择:优先小版本迭代,跨大版本升级前必须在测试环境验证至少 72 小时;
- 模块兼容:第三方动态模块(如 GeoIP2、Lua)必须与 Nginx 主程序版本完全一致(1.25.0 主程序需搭配 1.25.0 模块)。
7.2 信号说明(核心操作对照表)
| 信号 | 作用 | 适用场景 |
|---|---|---|
USR2 |
启动新版本 Master 进程 | 升级第一步,启动新版本但不影响旧版本 |
WINCH |
关闭旧 Master 的 Worker 进程 | 升级第二步,让新版本接管新请求 |
HUP |
重启 Worker 进程(重载配置) | 回滚时拉起旧 Worker 进程,或重载配置 |
QUIT |
优雅退出 Master 进程 | 升级完成后退出旧 Master,或回滚时退出新版本 Master |
TERM/KILL |
强制终止进程 | 仅紧急故障时使用(会中断请求) |
7.3 生产环境最佳实践
- 升级前:备份配置文件(
cp -r /etc/nginx /data/server/nginx/backup/nginx-conf-$(date +%Y%m%d))和二进制文件; - 升级中:先在测试环境验证,再灰度升级(如先升级1台应用服务器),最后全量升级;
- 升级后:观察日志(
tail -f /var/log/nginx/error.log)、进程状态、业务指标(QPS、响应时间)至少 24 小时; - 清理:升级完成后清理编译源码(
rm -rf /data/softs/nginx-1.25.0),仅保留二进制备份。
7.4 合规与安全
- 仅使用官方源下载 Nginx,避免第三方篡改包;
- 编译完成后验证二进制文件的属主和权限(必须为 root:root,权限 755);
- 升级后执行安全扫描(如
nginx -T检查配置漏洞、端口扫描验证监听状态)。
八、后续优化
8.1 恢复扩展模块功能(如需 GeoIP2/image_filter 等)
bash
# 重新编译适配新版本的模块
cd /data/softs/nginx-1.25.0
./configure `nginx -V 2>&1 | grep -o '--with-.*'` # 复用编译参数
make modules # 仅编译模块,不覆盖主程序
# 替换旧模块文件
cp objs/*.so /usr/share/nginx/modules/
# 恢复模块配置并验证
mv /etc/nginx/modules-enabled/bak/*.conf /etc/nginx/modules-enabled/
nginx -t && nginx -s reload
8.2 清理无用依赖
bash
apt autoremove -y # 卸载自动安装的无用依赖
apt clean # 清理缓存
8.3 长期维护
- 定期备份 Nginx 配置和二进制文件;
- 关注官方安全更新,及时小版本升级修复漏洞;
- 建立升级操作手册,标准化流程,避免人工失误。