Nginx 平滑升级(Ubuntu 24.04 环境)
一、平滑升级核心原理
Nginx 平滑升级通过向主进程发送特定信号实现,核心优势是不中断现有请求处理:
- 新请求逐步由新版本 Worker 进程接管;
- 旧 Worker 进程处理完现有连接后优雅退出;
- 全程保持服务可用,无连接拒绝或请求中断;
- 核心信号机制:通过
USR2/WINCH/QUIT等信号实现新旧进程的无缝切换,而非直接重启服务。
二、前置准备
2.1 环境检查(核心基础)
查看当前 Nginx 版本和编译参数(新版本必须复用完全一致的编译参数,仅修复语法错误):
nginx -v# 查看版本(示例:1.24.0)nginx -V# 查看编译参数(完整复制,后续编译新版本用,关键!)实操示例输出:
root@Ubuntu24-13:~# nginx -vnginx version: nginx/1.24.0(Ubuntu)root@Ubuntu24-13:~# nginx -Vnginx version: nginx/1.24.0(Ubuntu)built with OpenSSL3.0.1330Jan2024TLS 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 进程数充足(便于测试升级效果):
# 安装编辑器(若未安装)aptinstallvim-y# 编辑配置文件vim/etc/nginx/nginx.conf# 修改 worker_processes 为 2(原若为 auto 则改为固定值,便于观察进程切换)worker_processes2;# 重载配置(不中断服务)nginx -s reload# 验证进程数psaux|grepnginx实操示例输出(需看到 1 个 Master + 2 个 Worker 进程):
root@Ubuntu24-13:~# nginx -s reload2025/12/1621:32:12[notice]3100#3100: signal process startedroot@Ubuntu24-13:~# ps aux | grep nginxroot25800.00.35944013676? S21:130:00 nginx: master process /usr/sbin/nginx -g daemon on;master_process on;www-data31010.00.1602646284? S21:320:00 nginx: worker process www-data31020.00.1602646176? S21:320:00 nginx: worker process root31040.00.0178322340pts/0 S+21:320:00grep--color=auto nginx
2.2 全量依赖环境准备(解决所有编译报错)
编译新版本需安装全量依赖(覆盖所有模块,避免 xslt、image_filter、geoip、perl 等模块编译报错):
aptupdate&&aptinstall-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-devcurl针对性解决依赖兼容问题:
| 报错场景 | 解决命令 |
|---|---|
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)的兼容性问题;
- 仅下载官方源码包,拒绝第三方修改包,保证安全性。
# 创建统一目录结构(便于管理)mkdir-p /data/softs /data/server/nginx/backupcd/data/softs# 下载新版本(以 1.25.0 为例,可替换为目标版本)wgethttp://nginx.org/download/nginx-1.25.0.tar.gz# 校验包完整性(可选,推荐生产环境执行)md5sum nginx-1.25.0.tar.gz# 对比官网公布的 MD5 值# 解压tarxf nginx-1.25.0.tar.gzcdnginx-1.25.0三、编译新版本 Nginx(核心避坑)
3.1 复用旧版本编译参数(仅修复1处关键错误)
将nginx -V输出的configure arguments:后的参数完整复制,仅移除 --with-ld-opt 末尾的 -fPIC(这是 Ubuntu 系统编译的核心语法错误,其余参数完全保留),执行以下命令:
./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=dynamic3.2 编译(仅编译,绝对禁止执行 make install!)
make# 仅编译二进制文件,不覆盖系统现有配置和程序编译耗时约1-2分钟,编译完成后,新版本二进制文件位于
./objs/nginx。
3.3 编译后验证(必做)
# 验证版本是否正确./objs/nginx -v# 应输出 nginx/1.25.0# 验证配置加载是否正常./objs/nginx -t -c /etc/nginx/nginx.conf# 用新版本验证现有配置实操示例输出:
root@Ubuntu24-13:/data/softs/nginx-1.25.0# ./objs/nginx -vnginx version: nginx/1.25.0 root@Ubuntu24-13:/data/softs/nginx-1.25.0# ./objs/nginx -t -c /etc/nginx/nginx.confnginx: the configurationfile/etc/nginx/nginx.conf syntax is ok nginx: configurationfile/etc/nginx/nginx.conftestis successful四、平滑升级操作(分步执行,全程可回滚)
4.1 备份旧版本二进制文件(安全第一)
# 备份旧版本(带时间戳,便于追溯)mv/usr/sbin/nginx /usr/sbin/nginx-$(nginx -v2>&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.04.2 启动新版本 Master 进程(核心步骤)
- 获取旧版本 Master 进程 PID:
实操示例输出:old_pid=$(cat/run/nginx.pid)echo"旧 Master PID:$old_pid"root@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 进程:kill-USR2$old_pid - 验证进程状态(此时应存在新旧两个 Master 进程):
正常输出特征:psauxf|grepnginxls/run/nginx.pid*# 旧 PID 文件会被重命名为 nginx.pid.oldbinroot25800.00.35944013676? S21:130:00 nginx: master process /usr/sbin/nginx -g daemon on;master_process on;# 旧 Masterwww-data31010.00.1602646284? S21:320:00\_ nginx: worker process www-data31020.00.1602646176? S21:320:00\_ nginx: worker process root227710.00.1110607016? S22:260:00 nginx: master process /usr/sbin/nginx -g daemon on;master_process on;# 新 Masterwww-data227720.00.1128084360? S22:260:00\_ nginx: worker process www-data227730.00.1128084488? S22:260:00\_ nginx: worker process
4.3 优雅关闭旧 Worker 进程(新请求接管)
发送WINCH信号,让旧 Master 关闭其 Worker 进程,新请求全部由新版本 Worker 处理:
kill-WINCH$old_pid# 验证新版本接管服务(核心验证)curl-I127.0.0.1|grepServer# 应输出 nginx/1.25.04.4 确认升级完成(彻底退出旧 Master)
- 建议观察 1-5 分钟(生产环境可延长至 10-15 分钟),确认业务无异常后再执行;
- 若期间出现问题,可立即执行回滚操作(见第五章)。
# 优雅退出旧 Master 进程kill-QUIT$old_pid# 最终验证进程(仅保留新版本 Master + Worker)psauxf|grepnginx正常输出示例:
root227710.00.1110607016? S22:260:00 nginx: master process /usr/sbin/nginx -g daemon on;master_process on;www-data227720.00.1128084360? S22:260:00\_ nginx: worker process www-data227730.00.1128084488? S22:260:00\_ nginx: worker process五、平滑回滚(新版本异常时,秒级恢复)
若新版本出现卡顿、502、配置报错等问题,立即执行以下步骤回滚至旧版本:
5.1 恢复旧版本二进制文件
# 替换回旧版本二进制(以 1.24.0 为例,按实际备份名修改)mv/usr/sbin/nginx /usr/sbin/nginx-1.25.0mv/usr/sbin/nginx-1.24.0-20251216 /usr/sbin/nginx5.2 重启旧版本 Worker 进程
# 获取旧 Master PID(升级时保留的 oldbin 文件)old_master_pid=$(cat/run/nginx.pid.oldbin)# 拉起旧 Worker 进程kill-HUP$old_master_pid5.3 退出新版本 Master 进程
new_master_pid=$(cat/run/nginx.pid)kill-QUIT$new_master_pid5.4 验证回滚结果
# 进程仅保留旧版本psauxf|grepnginx# 请求返回旧版本标识curl-I127.0.0.1|grepServer# 输出 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 && ./configurenginx -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 等)
# 重新编译适配新版本的模块cd/data/softs/nginx-1.25.0 ./configure`nginx -V2>&1|grep-o'--with-.*'`# 复用编译参数makemodules# 仅编译模块,不覆盖主程序# 替换旧模块文件cpobjs/*.so /usr/share/nginx/modules/# 恢复模块配置并验证mv/etc/nginx/modules-enabled/bak/*.conf /etc/nginx/modules-enabled/ nginx -t&&nginx -s reload8.2 清理无用依赖
aptautoremove -y# 卸载自动安装的无用依赖aptclean# 清理缓存8.3 长期维护
- 定期备份 Nginx 配置和二进制文件;
- 关注官方安全更新,及时小版本升级修复漏洞;
- 建立升级操作手册,标准化流程,避免人工失误。