返回首页

Nginx 1.18→1.28 零停机升级:JSON 日志 + http2 修复,5 个坑一次讲透

Nginx 1.18→1.28 零停机升级:JSON 日志 + http2 修复,5 个坑一次讲透

大家好,我是老张。

前两天给服务器做了一次 Nginx 升级,从 Ubuntu 自带的 1.18.0 一路升到官方源的 1.28.0,顺带搞定了 JSON 格式访问日志。

本来以为 apt-get install 一把梭就完事了,结果踩了 5 个坑——签名密钥、http2 弃用语法、error_log 不支持 JSON、配置覆盖……

今天把完整过程整理出来,下次谁要升级 Nginx,照着这篇走就行。


📊 升级速览

项目升级前升级后
Nginx 版本1.18.0 (Ubuntu 源)1.28.0 (Nginx 官方源)
访问日志默认格式JSON 格式
JSON 错误日志❌(等后续版本)
http2 语法listen ... http2;http2 on;(消除弃用警告)
网站服务正常运行正常运行 ✅

一、为什么要升级?

三个原因:

  1. JSON 格式日志:Nginx 默认日志格式虽然能用,但程序化解析很痛苦。JSON 日志可以让 Prometheus、Filebeat、ELK 直接消费
  2. 错误日志也要 JSON:错误日志的解析比访问日志更麻烦,但 Nginx 1.25.1+ 支持 error_log 自定义格式
  3. 版本差太大:1.18.0 是 2020 年的版本,1.28.0 是 2025 年底发布的,中间跨了 10 个大版本,安全补丁和性能优化都值回票价

Ubuntu Focal (20.04) 官方源最高只提供 1.18.0,要装新版必须切到 Nginx 官方源。


二、升级全过程

1. 添加 Nginx 官方源

# 导入 Nginx 签名密钥
curl -sS https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
  -o /usr/share/keyrings/nginx-archive-keyring.gpg

# 添加官方 stable 源
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
  http://nginx.org/packages/ubuntu/ focal nginx" \
  > /etc/apt/sources.list.d/nginx-official.list

# 更新源
apt-get update -qq

2. 备份当前配置

cp -r /etc/nginx /etc/nginx.bak.$(date +%Y%m%d)

这步绝对不能省。后面万一翻车,恢复就靠它。

3. 安装新版 Nginx

这里有个关键点——不能直接 apt-get install nginx,否则官方包会覆盖你现有的配置文件。必须用 --force-confold

apt-get install -y nginx=1.28.0-1~focal \
  -o Dpkg::Options::="--force-confdef" \
  -o Dpkg::Options::="--force-confold"
  • --force-confdef:如果配置没被本地修改,用新版默认配置
  • --force-confold:如果配置被本地修改过(你肯定改过),保留你的版本

两个参数一起用,实现平滑升级 + 配置不丢失

4. 修复 http2 弃用警告

升级后 nginx -t 会报警告:

nginx: [warn] the "http2" directive is deprecated,
use the "http2" directive instead in ...

Nginx 1.25+ 弃用了 listen 443 ssl http2; 语法,改为独立指令:

# 旧语法(弃用)
listen 443 ssl http2;

# 新语法
listen 443 ssl;
http2 on;

改完 nginx -t && nginx -s reload,警告消失。

5. 验证升级

$ nginx -V
nginx version: nginx/1.28.0

$ curl -s -o /dev/null -w "%{http_code}" https://example.com/
200

三、JSON 访问日志配置

升级完就该配 JSON 日志了。直接上配置:

# JSON 格式日志
log_format json escape=json '{"time":"$time_local","remote_addr":"$remote_addr","remote_user":"$remote_user","request":"$request","status":$status,"body_bytes_sent":$body_bytes_sent,"http_referer":"$http_referer","http_user_agent":"$http_user_agent","request_time":$request_time,"upstream_status":"$upstream_status","upstream_response_time":"$upstream_response_time","http_x_forwarded_for":"$http_x_forwarded_for"}';
access_log /var/log/nginx/access_json.log json buffer=32k flush=5s;

三个关键参数:

参数作用
escape=json自动转义 JSON 特殊字符(引号、换行等),没有这个你的 JSON 就是非法格式
buffer=32k缓冲写入,减少磁盘 IO,高并发场景必备
flush=5s最多 5 秒强制落盘,兼顾实时性

输出效果:

{
  "time": "29/Jul/2026:17:00:51 +0800",
  "remote_addr": "x.x.x.x",
  "request": "GET /api/posts?page=1&page_size=10&status=published HTTP/2.0",
  "status": 200,
  "body_bytes_sent": 34433,
  "request_time": 0.113,
  "upstream_status": "200",
  "upstream_response_time": "0.065"
}

标准 JSON,可以直接喂给任何日志采集系统。


四、5 个坑,别踩

坑 1:signed-by 语法

Ubuntu 20.04 要求 source.list 中必须用 signed-by= 指定 GPG 密钥路径,否则 apt-get update 直接报错。

不是你配置的问题,是 apt 安全策略升级了。

坑 2:http2 弃用不是报错是警告

很多人会忽略 nginx -t 输出的 warning。

但不修复的话,这个警告会在每次 reload 时出现,时间久了容易埋雷——万一哪天 Nginx 直接移除旧语法支持,你的站点就挂了。

坑 3:error_log JSON 开源版不支持(最大遗憾)

开头说"错误日志也要 JSON",结果翻车了:

  • Nginx 开源版 1.28.0 不支持 error_log 的 JSON 格式输出
  • 这是 Nginx Plus 特性,开源版需要 1.29.8+ 才有
  • 目前 apt 源未提供该版本

未来能用的配置留在这,等版本更新:

# 未来可用(Nginx 1.29.8+ 或 Nginx Plus)
error_log /var/log/nginx/error_json.log notice json;

教训:动手前先查 changelog,别凭"我记得"做判断。

坑 4:logrotate 的坑

老手都知道配置 logrotate,但新手容易漏——JSON 日志是新文件,logrotate 管不管?

答案是:如果你之前的 logrotate 配置用的是 /var/log/nginx/*.log 通配符,新 JSON 日志会自动被覆盖。但如果你写死了文件名,就得手动加一行 access_json.log

坑 5:--force-confold 别忘了

不加这个参数,apt 会提示你"配置文件有修改,要保留还是用新版?"——如果你在非交互式脚本里跑,可能会卡住或误覆盖配置。


💡 老张的总结

  1. 升级前必备份cp -r /etc/nginx /etc/nginx.bak.$(date +%Y%m%d),这是运维的基本功
  2. 平滑升级 = --force-confold + --force-confdef:两个参数缺一不可,否则配置丢失或安装中断
  3. JSON 日志的关键是 escape=json:没有这个,生成的 JSON 可能包含未转义字符,解析直接翻车
  4. 开源版 ≠ Plus 版:Nginx 的 error_log JSON、动态模块等高级功能都是 Plus 专属,做方案前先确认你用的版本支不支持

💬 互动话题

  • 你平时用什么方式解析 Nginx 日志?GoAccess、ELK 还是自己写脚本?
  • 有没有遇到过 --force-confold 翻车的情况?怎么救回来的?
  • Nginx 升级你最担心什么?欢迎评论区聊聊
A

Admin

用文字记录生活与思考。

评论 (0)
暂无评论,来抢沙发吧
Nginx 1.18→1.28 零停机升级:JSON 日志 + http2 修复,5 个坑一次讲透 | 山外云的Vlog