一次Nginx反向代理配置错误导致上传文件大小限制失效的排查实录
问题背景
某周一早上刚到公司,业务部门的同事就找过来反映,说他们的内部文档管理系统在上传大于 10MB 的文件时,总是弹出错误提示。之前这个系统运行一直正常,但上周刚完成了一次迁移,把原来跑在 Tomcat 上的应用挪到了新的 Docker 容器里,并在前端新增了一台 Nginx 作为反向代理。迁移完成后做了基本的冒烟测试,上传小文件没问题,但大文件的情况没有测试到,结果今天业务侧才发现问题。
影响范围较大,整个文档管理系统的使用人数大约 60 人,每天有大量合同、图纸、报告需要上传,部分文件超过 10MB,属于正常业务场景。
故障现象
用户在浏览器端上传文件时,当文件大小超过约 8MB 时,页面返回如下错误:
1 | 413 Request Entity Too Large |
浏览器 Network 面板可以看到请求直接被 Nginx 拒绝,HTTP 状态码 413,没有到达后端应用。
开发同事说他已经在应用的 application.properties 里把 Spring Boot 的上传限制改成了 100MB:
1 | spring.servlet.multipart.max-file-size=100MB |
容器重启后依然报 413,于是找到运维这边来排查。
排查过程
第一步:确认报错来源
先看 Nginx 的 error log:
1 | tail -f /var/log/nginx/error.log |
日志输出:
1 | 2022/03/15 09:12:43 [error] 1234#1234: *567 client intended to send too large body: 9437184 bytes, client: 192.168.10.88, server: docs.internal.company.com, request: "POST /api/upload HTTP/1.1", host: "docs.internal.company.com" |
很明确:是 Nginx 报的错,不是后端应用。说明请求根本没到 Java 应用这层就被 Nginx 拒掉了。
第二步:检查 Nginx 配置
查看当前生效的 Nginx 配置:
1 | nginx -T 2>/dev/null | grep -i "client_max_body_size" |
输出:
1 | client_max_body_size 8m; |
找到了!但配置文件里明明应该改过的……继续追查配置文件层级:
1 | find /etc/nginx -name "*.conf" | xargs grep -l "client_max_body_size" |
发现了三处:
/etc/nginx/nginx.conf(http 块):client_max_body_size 100m;/etc/nginx/conf.d/default.conf(server 块):client_max_body_size 8m;/etc/nginx/conf.d/docs.conf(location 块):未配置
第三步:理解 Nginx 配置继承规则
这里就需要了解 Nginx 配置的继承机制了。client_max_body_size 可以出现在三个层级:
http {}块server {}块location {}块
优先级规则是:子块的配置会覆盖父块。 也就是说,server {} 里配置了 8m,就会覆盖掉 http {} 里的 100m,即使 http {} 里的值更大。
追问负责这次迁移的同事,他说迁移之前的 default.conf 是从旧机器上直接拷过来的,旧环境里这个文档系统并不走那台 Nginx,所以 default.conf 里的 8m 限制之前没有影响,但迁移后新 Nginx 又用了同一个 default.conf,就埋下了这个坑。
第四步:验证其他 server 配置
既然 default.conf 里有残留的 8m 限制,那需要确认这个配置是否影响到了 docs.conf 里的 server 块。
查看 docs.conf:
1 | server { |
这个 server {} 块里没有配置 client_max_body_size,按理应该继承 http {} 的 100m。但实际上 default.conf 里的那个 server {} 块只影响它自己,不会影响其他 server {} 块。
那到底是哪里的 8m 在生效?
第五步:再次仔细检查继承关系
重新 nginx -T 全量输出,这次逐段仔细看:
1 | nginx -T 2>/dev/null |
在仔细阅读输出后,发现 docs.conf 里其实还有一段被注释掉但没有完全注释干净的配置:
1 | server { |
原来,那位同事确实改过,但他把新的值写成了注释,同时没把旧的 8m 那行删掉,导致 8m 依然生效。
解决方案
修改 docs.conf,移除多余的限制配置,直接在 server {} 块里设置正确的值:
1 | server { |
验证配置语法无误:
1 | nginx -t |
输出:
1 | nginx: the configuration file /etc/nginx/nginx.conf syntax is ok |
热重载:
1 | nginx -s reload |
测试上传 50MB 文件,成功。用户侧验证通过,问题解决。
根因分析
根本原因是配置迁移时遗留了旧配置,且修改时操作不规范(改了注释而没删除旧配置行)。client_max_body_size 8m; 这行代码实际上一直生效,在旧环境中没有问题是因为旧环境的这台 Nginx 不承载文档系统的流量,迁移后该配置直接生效并产生影响。
此外,该同事误认为在 http {} 块设置了 100m 后,server {} 块里的 8m 会被覆盖,对 Nginx 配置的优先级规则理解有误。
预防措施
1. 配置迁移规范化
迁移配置前应先整理清楚每项配置的作用,不应直接拷贝旧配置,特别是对限制类配置(大小、超时、速率)要逐一核对。
2. 搭建迁移验证 Checklist
关键迁移场景(如文件上传、超时、鉴权等)必须列入上线前测试清单,不能只做功能冒烟测试。
3. 定期 nginx -T 全量审计
可通过脚本定期输出 nginx -T 并做配置 diff,发现异常配置:
1 | nginx -T 2>/dev/null | grep -E "(client_max_body_size|proxy_read_timeout|proxy_send_timeout)" > /tmp/nginx_limit_audit.txt |
4. 统一配置管理
推荐将 Nginx 配置纳入 Git 版本管理,所有修改通过 MR/PR 审核,避免直接改配置文件后忘记清理。
总结
这次故障表面上是个很简单的 413 问题,但排查过程中踩了两个坑:一是对 Nginx 配置的层级覆盖规则不熟悉,二是配置文件里存在”半改”的残留配置,干扰了判断。
教训:迁移时不要直接照搬旧配置,要理解每一行配置的含义;修改配置时要彻底,不要留注释残骸;上线前的测试场景要覆盖到实际业务的边界情况(比如大文件上传、长时间操作等)。