Nginx 413 上传被拦:client_max_body_size 与多层限制联动排查

    发布时间:2026-09-23 05:00 更新时间:2026-09-23 05:00 阅读量:0

    给客户传个几百 MB 的素材包,浏览器进度条刚走一点就弹出 413 Request Entity Too Large;后台导入一个几十 MB 的 SQL,页面直接白屏加一行 nginx 错误页。很多站长第一反应是去 Nginx 里加 client_max_body_size,改完重启发现还是不行,于是开始怀疑人生。其实上传是一条多段流水线,浏览器、Nginx、PHP-FPM、PHP 自身各有一道门槛,413 只是 Nginx 这道门在报数,门后面的 PHP 层同样可能把请求打回来。这篇文章按请求经过的顺序,一层层确认到底是谁卡住了上传。

    先看 413 是谁返回的,别急着改配置

    413 这个状态码由 Nginx 直接生成,特征是响应体极短,通常是 Nginx 自带的错误页,日志里表现为请求还没交给 PHP-FPM 就被拒了。判断方法很简单,打开 Nginx 的错误日志(宝塔面板一般在站点目录的 log 文件夹,或 /www/wwwlogs/ 下),搜 client intended to send too large body 这类关键字,出现即说明是 client_max_body_size 拦下的。如果错误日志里同时出现 upstream sent too big header、FastCGI sent in stderr 之类内容,那问题已经越过 Nginx,跑到 PHP-FPM 那一层了。

    还要注意一个常见误判:浏览器控制台报 net::ERR_CONNECTION_RESET 或者进度条归零,未必是 413。此时先用 curl 从服务器本机或本地发一个测试请求,能拿到明确的 HTTP 状态码和响应头,比在浏览器里猜要靠谱得多。

    # 造一个 20MB 的测试文件,观察返回码与响应头
    head -c 20M /dev/zero > /tmp/test20m.bin
    curl -i -F "file=@/tmp/test20m.bin" https://www.example.com/upload.php
    

    返回 HTTP/1.1 413,基本锁定 Nginx;返回 200 但文件没落地,或者返回 502/504,就要往 PHP 方向查。以上命令与路径请按自己的实际域名、上传接口调整。

    client_max_body_size 该写在哪一层

    这个指令的作用域是 http、server、location 三级,就近覆盖。也就是说写在 http 块里是全局默认值,写在某个 server 里只对该站点生效,写在 location 里只对匹配到的路径生效。上传接口常常单独走一个 location,如果只在 server 里放大了值,而该 location 里又写了更小的值,实际生效的是 location 那一份,这就是"明明改了全局还是 413"的典型原因。

    另外要留意 include 进来的配置文件。宝塔面板的站点配置会 include 一个 rewrite 或扩展配置目录,里面如果存在同名指令,同样会盖掉你手改的值。排查时用下面的命令把最终生效的完整配置打印出来看,比在多个文件之间来回翻要快。

    # 打印合并后的完整配置,确认 client_max_body_size 的最终取值
    nginx -T | grep -n "client_max_body_size"
    

    语法检查通过后再平滑重载

    nginx -t && nginx -s reload

    值的写法支持 10m、500m、1g 这类单位,不区分大小写。注意它是单个请求体上限,不是整个连接的上限,也和并发无关。设置过大意味着 Nginx 要为每个上传请求预留缓冲,小内存机器上盲目写 0(不限制)并不明智,按业务真实需要给一个略有余量的值即可。

    如果 Nginx 前面还有 CDN 或反向代理,回源请求同样受这层限制约束,源站放行了但 CDN 侧没放行,用户看到的依然是 413,这一层别漏掉。

    越过 Nginx 之后:PHP 与 PHP-FPM 的两道闸

    Nginx 放行之后,请求会被转给 PHP-FPM 处理。这一段有两个容易踩的参数:Nginx 侧 fastcgi 相关缓冲,以及 PHP 自身的 upload_max_filesize 与 post_max_size。前者过小会出现 502 或 504 而不是 413,属于另一类问题;后两者过小时,PHP 会静默丢弃上传文件,表现为表单提交成功但文件没进来,或者 $_FILES 里报 UPLOAD_ERR_INI_SIZE。

    这里有个关键关系:post_max_size 必须大于等于 upload_max_filesize,否则大文件依然进不来;同时表单里如果还有其他字段,post_max_size 还要留出这些字段的空间。修改方式是在 php.ini 里调整,或者用面板的 PHP 配置界面改,改完记得重载 PHP-FPM 而不是只重启 Nginx。

    # 查看当前 PHP 实际生效值,注意区分 CLI 与 FPM,用 web 方式验证更准
    php -i | grep -E "upload_max_filesize|post_max_size|max_execution_time"
    

    重启对应版本的 PHP-FPM(版本号按实际环境替换)

    systemctl restart php-fpm-74

    max_execution_time 和 Nginx 的 fastcgi_read_timeout 也要一起看。大文件上传耗时较长,脚本执行时间到了会被中断,用户看到的是连接被重置,容易被误当成体积限制。上传接口这类长耗时操作,超时值可以单独放宽,但不要全局改得过大。

    三层联动排查的顺序与结论

    把顺序理顺就不容易乱:先用 curl 拿到明确的返回码,确定是不是 413;是 413 就用 nginx -T 确认 client_max_body_size 在 http、server、location 三处的最终取值,并检查是否被 include 的配置覆盖;Nginx 放行后如果文件仍不落地,再去查 PHP 的 upload_max_filesize、post_max_size 与超时参数;最后别忘了 CDN 回源这一层。每一步改完都要重载对应服务,并用同一个测试文件复测,避免凭感觉判断。

    实际运维中,把上传限制做成"接口级"而不是"全局级"更稳妥:只对上传路径所在的 location 放宽体积与超时,其余站点保持默认,既满足业务又不会让整台服务器长期承受超大请求的压力。具体参数取值以官方文档和你的实际业务需求为准,改完记得留一份配置备份,方便回滚。

    继续阅读

    📑 📅
    换服务器后百度收录掉了:改IP前后的抓取诊断与sitemap动作 2026-09-22
    服务器只开80/443:SSH端口转发访问面板与数据库 2026-09-22
    WordPress数据库utf8转utf8mb4:emoji问号的处理步骤 2026-09-22
    宝塔面板开CDN后日志全是节点IP:real_ip落地配置 2026-09-22
    Nginx 静态资源 304 与 200 反复切换:条件请求排查 2026-09-22
    WordPress站点健康提示REST API出错:loopback请求失败逐项排查 2026-09-23
    换硬盘不换IP:rsync增量同步与停机切换回滚全流程 2026-09-23
    网站备案主体与接入商变更:新增接入、注销重备顺序与访问影响 2026-09-23
    宝塔新建站点403 Forbidden:权限位、属主与open_basedir三重排查 2026-09-23
    WordPress后台自动更新失败:权限、FTP常量与目录属主逐项定位 2026-09-23