Nginx 所有文件都报 403 Forbidden 怎么排查?
Nginx 全站 403 的系统排查:文件与目录权限链、SELinux 上下文、root 指向错误、deny 规则误伤,按命中率排序的检查清单与 FAQ。
全站 403 按命中率从高到低排查:① Nginx 用户对文件/目录无权限;② SELinux 上下文不对;③ root 指向了错误目录;④ deny/allow 规则误伤。 先看 error.log 里的具体原因,能省一半时间。
第 0 步:先看 error.log 说什么
tail -50 /var/log/nginx/error.log
日志会直接告诉你性质:
Permission denied→ 权限问题(走第 1、2 步)directory index of ... is forbidden→ 目录无默认文件(配 index 或 autoindex)access forbidden by rule→ 被自己的 allow/deny 规则拦了
第 1 步:权限链检查(最常见)
# Nginx 以谁运行?
ps aux | grep nginx # 通常是 www-data 或 nginx
# 逐级检查路径
namei -l /var/www/html/index.html
要求:文件可读,路径上每一级目录有 x(进入)权限。常见踩坑:把站点放在 /root/ 或某用户家目录下——父目录 700,Nginx 根本进不去。
修复模板:
# 先确认此目录只有可公开读取的静态内容;保留部署账户所有权
# 按实际worker用户配置只读ACL/组权限,不要把整站可写权限交给worker
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
第 2 步:SELinux(CentOS/RHEL 高频)
getenforce # Enforcing 就要查
ls -Z /var/www/html/ # 看文件上下文
Web 内容需要 httpd_sys_content_t 上下文。修复:
sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/html(/.*)?"
sudo restorecon -Rv /var/www/html
检查 audit.log 中对应请求的 AVC 拒绝记录并修正具体标签或策略;不以全局关闭 SELinux 作为常规排障步骤。
第 3 步:root 指向对不对
nginx -T | grep -A5 'server_name'
ls -la <root 指向的目录> # 目录真的存在吗?里面有文件吗?
部署脚本改路径、符号链接失效都会让 root 悬空——不存在的路径通常返回 404;已存在目录缺少 index 且禁止列表才常见 403,仍需结合实际 location 和日志。
第 4 步:allow/deny 规则
location / {
allow 192.168.1.0/24;
deny all; # ← 误伤全站就是这么来的
}
nginx -T 全局搜 deny,确认没有过宽的拒绝规则。
修复后重试首页、静态资源和受限路径,核对预期允许与拒绝的请求是否都正确。使用观测云时,可把 HTTP 拨测设为检查关键 URL 的预期状态码;若已采集访问日志,再按 URI 查看 403 分布,区分权限配置错误与正常访问控制。
常见问题(FAQ)
Q:chmod 777 能解决问题吗?
A:不一定,SELinux 或访问规则等仍会拒绝;而且等于开门揖盗——任何进程都能改你的网站文件。正确答案是 755/644 + 正确属主,永远不要用 777 掩盖权限问题。
Q:只有 PHP 文件 403,静态文件正常?
A:仍可能是脚本/父目录权限或 PHP-FPM 那一层(看 listen 的 socket/端口权限、security.limit_extensions 配置)。
Q:docker 容器里的 Nginx 也按这套查?
A:思路一样,但权限映射更绕:宿主机目录挂载进容器后,容器内 nginx 用户需具备宿主机文件及父目录的有效读取/搜索权限,UID 不同本身不必然导致 403。应核对容器内 worker 的 UID/GID、只读挂载和宿主机标签;-u 改的是容器进程用户,并不会自动修复 worker 权限或 SELinux 标签。