背景

Nginx近期被爆出有高危漏洞,漏洞版本CVE-2026-42945,https://nvd.nist.gov/vuln/detail/CVE-2026-42945。对有运维经验的小伙伴来说,这其实已经司空见惯了,毕竟像Nginx这种使用规模如此广泛的软件,随着时代的发展,时不时的爆出点漏洞来,非常正常。而Nginx的设计者们很早就考虑到了这个问题,因此Nginx的漏洞修复和升级操作,非常完善,甚至都不会影响线上服务,就可以实现热更新。

正好我这前几天也遇到了需要给客户服务器升级Nginx的情况,整理了一下相关流程,跟大家分享一下。

*小坑坑

注意,再开始聊升级步骤之前,我还是想先把几个小坑坑说明一下。

我这里nginx的安装方式是通过编译源码的方式进行,如果你使用的是官方包管理器(yum/dnf/apt)安装的,那升级方式就是两行命令;

# 检查是否有可用的更新
yum check-update nginx

# 直接升级 Nginx
yum update nginx

那既然官方包这么简单,为什么还要用编译源码的方式?

这个我觉得有2个点,一个是,源码编译的方式自由度较高,而这可以真正做到升级时生产无中断,而包管理器升级是会中断个几秒中的,而且升级过程对运维或者开发工程师来说,完全是黑盒子。

另一个重要的点是,包管理器安装,nginx的核心依赖基本都是依赖操作系统,比如openssl,如果用包管理器升级,你nginx的openssl版本完全依赖系统,如果系统的版本恰好也比较低,低到新版的nginx无法升级,就麻烦了。

而使用静态编译的方式,就不存在这个问题,我们可以把openssl打包进nginx的编译过程,使的nginx变得更加独立,后续即便你升级系统的openssl造成了ssh链接断开之类的问题,nginx也不会收到影响,当然了,如果未来某天openssl版本爆出漏洞,系统的自动安全修复,比如yum update,也管不到你的nginx,我们也必须用同样的方法,再下载openssl源码,然后重新编译nginx并替换。

总之就是各有利弊,具体怎么选择还是看场景,目前看,通过静态编译的方式来管理nginx还是相对普遍的做法,但如果是测试或者开发环境就无所谓了,怎么顺手怎么来即可。还有部分场景是用容器管理nginx这种本篇不再赘述,自行GPT即可。

升级步骤

准备新版本的安装包

# 下载源码包
wget http://nginx.org/download/nginx-1.30.1.tar.gz

# 解压
tar -zxvf nginx-1.30.1.tar.gz

#进入目录
cd nginx-1.30.1

配置编译参数&编译

如果是升级操作,我们可以通过nginx -V查看之前的nginx编译参数,为了确保兼容性,升级的时候要确保原来的参数不丢失。

# 查看原版本的编译参数
nginx -V

# 关于openssl,前面小坑坑部分提到
# 如果担心操作系统的openssl版本过低,可以在编译时保持上述参数的前提下,额外增加一个openssl的源码地址,这样静态编译出来的nginx就包含了一个独立的openssl库,不再依赖系统的openssl,在centos7.x这类系统上,这样尤为推荐
wget https://www.openssl.org/source/openssl-1.1.1w.tar.gz --no-check-certificate
# 解压
tar -zxvf openssl-1.1.1w.tar.gz

# 编译
./configure --prefix={这里还写之前Nginx -V输出的参数,确保兼容性} --with-openssl=/usr/local/src/openssl-1.1.1w #<--额外增加上这一个

# 新版本目录下
make

如果我们在编译的时候,引入了openssl,make的时候会输出相关的提示,如下图“OpenSSL has been successfully configured”…

备份&替换二进制文件

# 备份
mv /{路径省略}/nginx /{路径省略}/nginx.old

# 替换
cp objs/nginx /{路径省略}/nginx

注意:此命令需要在新版Nginx的解压源码目录下执行,也就是我们前面编译的路径下。

测试

# 测试原来的配置是否有效,确保升级后100%兼容
nginx -t
# 预期输出
# nginx: the configuration file ... syntax is ok
# nginx: configuration file ... test is successful

进程替换

# 触发热升级:向旧Master进程发送USR2信号此时旧pid文件会自动重命名为nginx.pid.oldbin,并启动全新的1.30.1进程组
kill -USR2 `cat /{路径省略}/logs/nginx.pid`

# 查看进程状态,确认新旧两套 Master/Worker 共同存在
ps -ef|grep nginx

# 停止旧Worker
kill -WINCH `cat /{路径省略}/logs/nginx.pid.oldbin` 

# 彻底退出旧Master
kill -QUIT `cat /{路径省略}/logs/nginx.pid.oldbin`  

注意,上面的过程,也可以先查看nginx进程,根据服务启动日期,获取到准确的进程id,再在发送信号,如下图

验证结果

除了nginx版本变成了最新版本,openssl版本也使用了我们打包进来的版本。

而如果我们升级的时候不打包openssl进来,那输出结果如下,openssl还是依赖的系统的ssl,这个如果你的服务器linux内核版本较高的话,对应的openssl版本也会比较高,就没问题,如果是一些老一点的系统,比如我这里是Centos 7.9,openssl版本就低一点,升级的时候打包进来会更安全一点。

结语

好了,nginx的平滑升级至此就完成了,说起来这次Nginx的漏洞也挺戏剧性,竟然是被AI大模型发现的,波及范围也很广泛,具体来说,就是只要你在nginx配置里使用了rewrite特性,就可以通过特殊的方式完成入侵。

这也说明AI的发展越来越迅猛,作为开发者,我们的观念还是要迅速转变,合理,高效的利用AI,提高我们的开发能力和开发效率。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐