当前位置:首页 >  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 规则这类“看起来一样、病根不同”的故障按层拆开,总纲建议收藏备查。

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

相关文章

  • PHP Allowed memory size exhausted:真泄漏还是配额太小

    日志里刷Fatalerror:Allowedmemorysizeof134217728bytesexhausted,后台某个导出功能一跑就挂。134217728字节就是128M,这是php.ini里memory_limit的官方默认值。很多人第一反应是把数字改大,先别急——内存溢出有两种完全不同的病

    标签:
    网站服务器
  • 重定向循环与 HTTPS 识别错乱:X-Forwarded-Proto 那些坑

    HTTPS证书配好、Nginx强制跳转也配好了,浏览器打开却提示ERR_TOO_MANY_REDIRECTS,重定向次数超限。这个故障的高发场景非常固定:网站前面挂了CDN、负载均衡或者第二层反向代理。浏览器到CDN是HTTPS,但CDN回源到你的Nginx走的是HTTP,于是循环就来了。拆开看这个

    标签:
    网站服务器
  • Nginx 413 Request Entity Too Large:三处上传限制一起改才算改完

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

  • SSL 证书过期与证书链不完整:openssl s_client 验证与续期监控

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

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

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

热门排行

信息推荐