当前位置:首页 >  IDC >  服务器 >  正文

Nginx 403 Forbidden:权限、SELinux 与 deny 规则三层排查法

 2026-09-06 10:59  来源: 互联网   我来投稿 撤稿纠错

  一键部署OpenClaw

新站刚部署,首页打开 403 Forbidden。403 和 404 不一样,404 是“没找到”,403 是“找到了但不给你看”,所以问题一定出在服务端某一层权限上。Nginx 报 403 的原因集中在三层:文件系统权限、SELinux、Nginx 自身的访问控制规则,按这个顺序查,基本不会漏。

先说最常见的文件系统权限。Nginx worker 进程通常以 nginx 用户跑,它要能穿过站点目录的每一级父目录(父目录必须有 x 执行位),还要能读目标文件(至少 r 位)。你用 root 把文件解压出来的场景最容易踩:文件属于 root 且权限是 600,nginx 用户自然读不到。

# 看 worker 进程的运行用户

ps aux | grep "nginx: worker" | grep -v grep

# 检查站点目录链路上每一级的权限

namei -l /www/example.com/public/index.html

# 修正属主与权限(目录 755、文件 644 是底线)

chown -R nginx:nginx /www/example.com

chmod -R u=rwX,g=rX,o=rX /www/example.com

权限没问题还 403,就要怀疑 SELinux。CentOS、Rocky 这类发行版默认 enforcing,就算你 chmod 777,SELinux 的策略不放过照样 403。验证方法很简单:临时切到 permissive 看 403 是否消失,同时去 audit.log 里确认是否有 denied 记录。确认是 SELinux 后别图省事直接关掉,正确做法是给目录打上 httpd_sys_content_t 上下文。

 
getenforce # Enforcing 说明在生效
setenforce 0 # 临时放行,403 消失即基本锁定
ausearch -m avc -ts recent | tail -5 # 看审计日志里的 denied 明细

# 确认后恢复 enforcing 并打上下文标签
setenforce 1
semanage fcontext -a -t httpd_sys_content_t "/www/example.com(/.*)?"
restorecon -Rv /www/example.com

前两层都排完还 403,剩下的就是 Nginx 自己的规则了。两种情况:一是配置里有 deny 指令,ngx_http_access_module 的 allow/deny 按顺序匹配,一条 deny all 写在后面会覆盖前面所有 allow;二是请求命中的目录下没有 index 指令指定的文件,而 autoindex 又是默认的 off,Nginx 不愿意给你列目录,就回 403。

# 检查访问控制规则与 index 配置
nginx -T 2>/dev/null | grep -nE "deny|allow|autoindex"

# 用 curl 看响应头,403 前面若有 WWW-Authenticate 是另一回事(auth_basic)
curl -I https://你的域名/

# 快速确认是不是“目录没 index”这种情况:手动访问一个存在的文件
curl -I https://你的域名/index.html # 这个能 200 就是 index 没配对

排查 403 有个原则:从外往里剥。先 curl -I 拿到状态码,再按文件权限、SELinux、Nginx 规则的顺序逐层排除,每改一层验证一次,不要三层一起动。动态权限变更别忘了一步:改完 chmod 或 SELinux 上下文不需要 reload Nginx,它每次请求都会重新走一遍 open,立即生效;改了配置才需要 nginx -t 加 reload。

相关阅读:403 是接入层排查的经典案例。《服务器故障排查总纲:按现象反查的五层定位法》把权限、SELinux、deny 规则这类“看起来一样、病根不同”的故障按层拆开,总纲建议收藏备查。

申请创业报道,分享创业好点子。点击此处,共同探讨创业新机遇!

相关标签
网站服务器

相关文章

  • Nginx 413 Request Entity Too Large:三处上传限制一起改才算改完

    用户后台传一张3MB的图,页面转半天最后白屏,什么提示都没有。你去看浏览器请求,状态码413RequestEntityTooLarge。这个错误有个讨厌的特性:官方文档里明确写了浏览器没法正确渲染它,所以用户端看到往往不是413页面,而是一片白或者连接被重置,报障的时候只会说“传不上去”。根因就一句

    标签:
    网站服务器
  • SSL 证书过期与证书链不完整:openssl s_client 验证与续期监控

    证书过期这事,一旦发生就是全站级别的红色警告。浏览器直接拦截,访客看到的不是你的网站,是一屏吓人的安全提示。更气人的是它完全可以避免——免费证书加自动续期,配好了就再也不用管。Let'sEncrypt的证书有效期是90天,这个短期限是刻意设计的,目的是逼着大家把续期自动化。Certbot是它官方推荐

  • 进程被 OOM Kill:dmesg 定位与关键进程保护

    有一种故障特别难查:服务莫名其妙消失了,应用日志里什么都没留下,没有崩溃堆栈,没有异常退出记录。进程就这么凭空不见。碰到这种情况,十有八九是内核干的——内存不够了,OOMKiller挑中它杀了。OOM的全称是OutofMemory,它是内核的最后手段。Linux默认采用乐观的内存分配策略,进程申请内

  • Linux 磁盘满排查:df 到 du,定位大文件与日志轮转

    网站突然写不进数据,上传图片报失败,数据库开始拒绝写入。登上机器df一看,使用率100%。这种故障不复杂,但它有个特别坑的地方:你按常规思路用du去找大文件,把所有目录的大小加起来,发现远远小于磁盘用量。两个数对不上。对不上通常有三个原因。第一个最常见:文件被删了,但还被某个进程占着。Linux下删

    标签:
    网站服务器
  • MySQL 慢查询拖垮 CPU:processlist 到 pt-query-digest

    服务器CPU突然打满,网站慢得像拨号上网。登上机器一看,MySQL占了大头。这时候最忌讳的是直接重启数据库——重启完负载确实掉了,但过不了多久它还会爬回来,因为那条慢SQL还在那儿等着被执行。第一步是抓现行。SHOWPROCESSLIST能看到此刻正在跑的语句,但默认只显示前100个字符,长SQL会

热门排行

信息推荐