Nginx 报 "stat() failed (13: Permission denied)" 怎么办?
Nginx stat() failed (13: Permission denied) 的修复:路径上每一级目录都需要 x 权限、文件需要 r 权限;namei -l 逐级定位断点、SELinux 上下文检查与 FAQ。
这个错误表示 Nginx 想 stat()(读取元信息)某个文件/目录时被系统拒绝——本质是路径权限链上某一环把 Nginx 用户(www-data/nginx)挡在了外面。 用 namei -l 逐级查权限是最快的定位法。
修复步骤
1. 逐级检查权限链
namei -l /var/www/site/uploads/avatar.jpg
输出示例:
drwxr-xr-x root root /
drwxr-xr-x root root /var
drwxr-xr-x root root /var/www
drwxr-x--- deploy deploy /var/www/site ← 断点在这
drwxr-xr-x deploy deploy /var/www/site/uploads
-rw-r--r-- deploy deploy /var/www/site/uploads/avatar.jpg
规则:每一级目录都要有 x(进入)权限,目标文件要有 r(读)权限,对象是上层的"others"或 Nginx 所属组。上例中 /var/www/site 是 750 deploy:deploy,www-data 进不去 → stat 失败。
2. 修复断点
两种思路:
# 思路 A:放开目录权限(简单粗暴,注意家目录别这么干)
chmod 755 /var/www/site
# 思路 B:把 Nginx 用户拉进属组(更精细)
usermod -aG deploy www-data
chmod 750 /var/www/site # 组有 x 即可
systemctl restart nginx # 组成员变更要重启 worker 生效
3. 高频场景:站点放在用户家目录
/home/alice/site/ 这类布局几乎必踩——/home/alice 默认 700 或 750,www-data 进不来。优先把站点挪到 /var/www/;必须留在家目录就给 /home/alice 加 x(chmod o+x /home/alice 即可,不需要给读权限)。
4. SELinux(CentOS/RHEL)
权限链全对还报 13:
getenforce
ls -Z /var/www/site/ # 上下文应是 httpd_sys_content_t
sudo restorecon -Rv /var/www/site/
观测云对照
权限类 403/stat failed 常由"别人动了服务器"引发——部署脚本改了属主、新同事 chmod 了一把。把 Nginx error.log 接入观测云,对 Permission denied 关键字设告警,权限漂移引发的故障分钟级可见;结合访问日志按 URI 看 403 分布,影响范围立刻圈定。
常见问题(FAQ)
Q:chmod 777 是不是万能解?
A:它能消除报错,但任何本地用户都能改你的站点文件——永远不要拿 777 当排障终点。正确答案是目录 755(或组 750)+ 文件 644 + 正确属主/属组。
Q:docker 挂载目录里也报这个?
A:容器内 nginx 用户的 UID 与宿主机文件属主不一致导致。要么调宿主机目录属主,要么容器以匹配 UID 运行,要么挂载时显式处理权限。
Q:stat() failed 和 open() failed 有区别吗?
A:stat 失败通常是路径中间某级目录进不去;open 失败是最后一级文件本身读不了。namei -l 一次把两层都看清。