Nginx + PHP 上传大文件报 413 Request Entity Too Large:client_max_body_size 与 upload_max_filesize 双层限制详解
关键词: Nginx 413, client_max_body_size, upload_max_filesize, post_max_size, PHP-FPM, 文件上传, 大文件上传失败, multipart/form-data, Request Entity Too Large
问题背景
Nginx + PHP-FPM 的 Web 应用支持用户上传文件,但上传超过 1MB 的文件总是失败,返回 413 Request Entity Too Large。小文件(<1MB)正常。检查服务器磁盘空间充足、Nginx/PHP 运行正常,日志里也没有 PHP 报错——因为请求根本到不了 PHP。
复现步骤
# 1. 在 scenario/2026-09-08-0800 下启动环境
docker compose up -d --build
# 2. 生成一个 3MB 测试文件并 curl 上传
head -c 3145728 /dev/urandom > /tmp/big.bin
curl -i -F "file=@/tmp/big.bin" http://localhost:8080/upload.php
# 复现输出:HTTP/1.1 413 Request Entity Too Large
根本原因
这是一个 Nginx + PHP 双层上传限制 叠加导致的经典问题。请求从浏览器到文件落盘,要经过两层"关卡":
第 1 层:Nginx client_max_body_size(默认 1m)
Nginx 在 http/server/location 级别有 client_max_body_size 指令,默认值为 1m。当客户端 POST 的请求体(body)超过该值时,Nginx 直接返回 413 Request Entity Too Large,不会把请求转发给后端 PHP-FPM。
配置文件中的问题代码:
# nginx/default.conf
client_max_body_size 1m; # ← 这就是 413 的来源
第 2 层:PHP 自己的上传限制
就算把 Nginx 放行,PHP 也有两把锁:
upload_max_filesize:单个上传文件的最大字节数(默认 2M)post_max_size:整个 POST body 的最大字节数(默认 8M,必须 ≥ upload_max_filesize)
当 Nginx 放行但 PHP 超限时,PHP 拒绝文件,$_FILES['file']['error'] = 1(UPLOAD_ERR_INI_SIZE)。
解决办法
第 1 步:调大 Nginx client_max_body_size
编辑 nginx/default.conf:
client_max_body_size 20m; # 按需调整,如 20m/50m/100m
第 2 步:调大 PHP 上传限制
编辑 PHP 配置(本环境为 php/php.ini 通过 volume 覆盖):
upload_max_filesize = 20M
post_max_size = 25M # 必须 ≥ upload_max_filesize,且要容纳整个 multipart body
第 3 步:重启服务让配置生效
docker compose restart nginx php
# 或生产环境:nginx -s reload && systemctl restart php-fpm
验证
# 生成 3MB 测试文件并上传
head -c 3145728 /dev/urandom > /tmp/big.bin
curl -F "file=@/tmp/big.bin" http://localhost:8080/upload.php
# 修复前:HTTP 413 Request Entity Too Large
# 修复后:HTTP 200,响应 "上传成功!"
经验与避坑
- 413 的第一反应查 Nginx:
client_max_body_size默认仅 1m,比大多数人的想象要小得多。 - 两层都要调:只改 Nginx 不改 PHP,请求过了 Nginx 会在 PHP 层被拒(表现为
$_FILES['file']['error'] = 1);只改 PHP 不改 Nginx,请求在 Nginx 就被拦,PHP 根本收不到。 post_max_size必须 ≥upload_max_filesize:post_max_size限制的是整个 POST body,除文件内容外还有 multipart boundary、表单字段等额外开销,需要留出余量。- 改完配置必须重启/重载:Nginx 的
client_max_body_size需要nginx -s reload,PHP 配置需要重启 PHP-FPM,两者都不会热加载。 - 如何快速区分是哪层在拦:
- Nginx 返回 413(HTML 错误页来自 Nginx)→ 第 1 层 Nginx
- Nginx 返回 200 但页面提示"超过 PHP 限制"/
$_FILES['file']['error'] = 1→ 第 2 层 PHP - 检查响应头
Server: nginx/...可确认是 Nginx 层的 413
- Docker 场景注意:配置文件通过 volume 挂载时,
docker compose restart即可生效;如果配置文件在镜像构建时 COPY 进去,则需docker compose up -d --build重建。
相关文件
- 问题配置:
nginx/default.conf、php/php.ini - 上传处理:
app/www/upload.php - 验证脚本:
check.sh - 复现脚本:
reproduce.sh - 完整操作记录:
scenario/2026-09-08-0800/SOLUTION.md
