Nginx 平滑升级

Nginx 平滑升级(Ubuntu 24.04 环境)

一、平滑升级核心原理

Nginx 平滑升级通过向主进程发送特定信号实现,核心优势是不中断现有请求处理

  • 新请求逐步由新版本 Worker 进程接管;
  • 旧 Worker 进程处理完现有连接后优雅退出;
  • 全程保持服务可用,无连接拒绝或请求中断;
  • 核心信号机制:通过 USR2/WINCH/QUIT 等信号实现新旧进程的无缝切换,而非直接重启服务。

二、前置准备

2.1 环境检查(核心基础)

  1. 查看当前 Nginx 版本和编译参数(新版本必须复用完全一致的编译参数,仅修复语法错误):

    bash 复制代码
    nginx -v  # 查看版本(示例:1.24.0)
    nginx -V  # 查看编译参数(完整复制,后续编译新版本用,关键!)

    实操示例输出:

    bash 复制代码
    root@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
  2. 确保 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 进程):

    bash 复制代码
    root@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 进程(核心步骤)

  1. 获取旧版本 Master 进程 PID:

    bash 复制代码
    old_pid=$(cat /run/nginx.pid)
    echo "旧 Master PID:$old_pid"

    实操示例输出:

    bash 复制代码
    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
  2. 发送 USR2 信号,启动新版本 Master 进程:

    bash 复制代码
    kill -USR2 $old_pid
  3. 验证进程状态(此时应存在新旧两个 Master 进程):

    bash 复制代码
    ps auxf | grep nginx
    ls /run/nginx.pid*  # 旧 PID 文件会被重命名为 nginx.pid.oldbin

    正常输出特征:

    bash 复制代码
    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;  # 旧 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 版本与参数规范

  1. 编译参数:仅移除 --with-ld-opt 末尾的 -fPIC,其余参数必须与旧版本完全一致,否则信号机制会失效;
  2. 版本选择:优先小版本迭代,跨大版本升级前必须在测试环境验证至少 72 小时;
  3. 模块兼容:第三方动态模块(如 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 生产环境最佳实践

  1. 升级前:备份配置文件(cp -r /etc/nginx /data/server/nginx/backup/nginx-conf-$(date +%Y%m%d))和二进制文件;
  2. 升级中:先在测试环境验证,再灰度升级(如先升级1台应用服务器),最后全量升级;
  3. 升级后:观察日志(tail -f /var/log/nginx/error.log)、进程状态、业务指标(QPS、响应时间)至少 24 小时;
  4. 清理:升级完成后清理编译源码(rm -rf /data/softs/nginx-1.25.0),仅保留二进制备份。

7.4 合规与安全

  1. 仅使用官方源下载 Nginx,避免第三方篡改包;
  2. 编译完成后验证二进制文件的属主和权限(必须为 root:root,权限 755);
  3. 升级后执行安全扫描(如 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 长期维护

  1. 定期备份 Nginx 配置和二进制文件;
  2. 关注官方安全更新,及时小版本升级修复漏洞;
  3. 建立升级操作手册,标准化流程,避免人工失误。
相关推荐
疯狂成瘾者1 分钟前
后端系统、服务稳定性里核心的指标有哪些
数据库
领尚6 分钟前
openclaw 极简安装(Ubuntu 24.04 server)
linux·运维·ubuntu
SPC的存折30 分钟前
openEuler 24.03 MariaDB Galera 集群部署指南(cz)
linux·运维·服务器·数据库·mysql
仲芒31 分钟前
[24年单独笔记] MySQL 常用的 DML 命令
数据库·笔记·mysql
SPC的存折43 分钟前
MySQL 8.0 分库分表
linux·运维·服务器·数据库·mysql
蓦然乍醒1 小时前
使用 DBeaver 还原 PostgreSQL 备份文件 (.bak) 技术文档
数据库·postgresql
XDHCOM1 小时前
Redis节点故障自动恢复机制详解,如何快速抢救故障节点,确保数据不丢失?
java·数据库·redis
QCzblack1 小时前
BugKu BUUCTF ——Reverse
java·前端·数据库
cyber_两只龙宝1 小时前
【Oracle】Oracle之DQL中WHERE限制条件查询
linux·运维·数据库·云原生·oracle
luis的妙妙屋1 小时前
主流数据库数据类型对比分析
数据库