我见过不少人一看到 403,就先去改 DNS、重启服务器、甚至怀疑 VPS 被墙。其实 403 Forbidden 跟“连不上”不是一回事。
如果浏览器能打开页面,但显示 403 Forbidden,说明请求已经到了你的 VPS,Nginx 或 Apache 也收到了,只是它判断:这个路径不允许访问。
最常见的原因就这几类:目录没有 index 文件、文件权限不对、站点目录 owner 不对、Nginx/Apache 配置写了 deny、SELinux 拦截、WordPress 或面板规则把请求挡掉。
下面按实际排查顺序来,不要一上来就乱改权限。
先用 curl 看一下返回码:
curl -I https://example.com
如果看到类似:
HTTP/1.1 403 Forbidden
Server: nginx
说明 Web 服务已经响应,只是拒绝访问。
如果是:
404 Not Found:路径或文件不存在;502 Bad Gateway:Nginx 后面的 PHP-FPM、Node、Gunicorn 之类出问题;521/522:Cloudflare 连源站失败或超时;403 Forbidden:重点查权限、目录、规则和安全策略。
这个区别很重要。403 不是先查网络,而是先查 Web 服务器为什么不让访问。
Nginx:
sudo tail -n 80 /var/log/nginx/error.log
Apache:
sudo tail -n 80 /var/log/apache2/error.log
CentOS / AlmaLinux / Rocky Linux 上 Apache 可能是:
sudo tail -n 80 /var/log/httpd/error_log
常见日志大概长这样:
directory index of "/var/www/site/" is forbidden
或者:
open() "/var/www/site/index.html" failed (13: Permission denied)
这两种含义完全不同。
第一种是目录没有 index 文件,服务器又不允许列目录;第二种是文件存在,但 Web 服务器用户没有权限读。
很多 403 就是因为你访问了目录,但目录里没有默认首页。
看一下站点目录:
ls -lah /var/www/site
至少应该有一个:
index.html
index.htm
index.php
Nginx 配置里也要写对:
index index.html index.htm index.php;
Apache 可以看 DirectoryIndex:
DirectoryIndex index.html index.php
如果目录里确实没有 index 文件,Nginx 返回 403 是正常的。它不是打不开,而是不允许把整个目录列表展示给别人。
临时测试可以放一个文件:
echo 'ok' | sudo tee /var/www/site/index.html
再访问网站。如果 403 消失,问题就在 index 文件或站点根目录配置。
很多人只看 index.html 权限,忽略了父目录。
Web 服务器读一个文件,不只要读文件本身,还要能进入上级目录。比如 /var/www/site/index.html,/var、/var/www、/var/www/site 每一级目录都要有可执行权限。
用这个命令最直观:
namei -om /var/www/site/index.html
正常情况大概是:
drwxr-xr-x root root /
drwxr-xr-x root root var
drwxr-xr-x root root www
drwxr-xr-x www-data www-data site
-rw-r--r-- www-data www-data index.html
常用建议:
sudo find /var/www/site -type d -exec chmod 755 {} \;
sudo find /var/www/site -type f -exec chmod 644 {} \;
不要一把梭 chmod -R 777。这确实可能让 403 消失,但也把安全性一起干没了。
如果是 Ubuntu / Debian,Nginx 和 Apache 常见用户是 www-data。可以这样设置 owner:
sudo chown -R www-data:www-data /var/www/site
如果是 CentOS / AlmaLinux / Rocky Linux,Apache 常见用户是 apache,Nginx 可能是 nginx:
sudo chown -R nginx:nginx /var/www/site
不确定用户是谁,可以看进程:
ps aux | grep -E 'nginx|apache|httpd'
Nginx 403 很多时候不是 Linux 权限,而是配置里直接写了不允许访问。
先测试配置:
sudo nginx -t
再看站点配置:
sudo nginx -T | grep -nE 'server_name|root|location|deny|allow|try_files|autoindex'
重点看这些:
location / {
try_files $uri $uri/ =404;
}
如果请求 /,Nginx 找到的是一个目录,而目录里没有 index 文件,就可能出现 directory index is forbidden。
还要找这种规则:
deny all;
或者某个 location 把目录挡住:
location /uploads/ {
deny all;
}
如果 403 只发生在某个路径,比如 /admin/、/uploads/、/.well-known/,那就重点查对应 location。
改完配置后:
sudo nginx -t
sudo systemctl reload nginx
Apache 的 403 经常出现在这几处。
站点目录必须允许访问:
<Directory /var/www/site>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
如果你看到:
Require all denied
那就很明显了,它就是在拒绝访问。
还有 .htaccess。WordPress、Laravel、旧项目迁移后,.htaccess 很容易把路径规则搞乱。
可以临时改名测试:
sudo mv /var/www/site/.htaccess /var/www/site/.htaccess.bak
sudo systemctl reload apache2
如果 403 消失,问题就在 .htaccess。别急着删,慢慢把规则加回来。
Apache 配置测试:
sudo apachectl configtest
Ubuntu / Debian 重载:
sudo systemctl reload apache2
CentOS 系列:
sudo systemctl reload httpd
如果你用的是 Rocky Linux、AlmaLinux、CentOS Stream,权限看起来都对,但还是 403,很可能是 SELinux。
先看状态:
getenforce
如果返回:
Enforcing
就继续查上下文:
ls -Z /var/www/site
Web 内容通常需要类似 httpd_sys_content_t 的上下文。
常见修复:
sudo restorecon -Rv /var/www/site
如果你的站点目录不在标准位置,比如放在 /home/deploy/site,需要额外设置上下文。不要直接关 SELinux 当永久方案。临时验证可以用:
sudo setenforce 0
如果关掉后 403 立刻消失,就说明方向对了。验证完记得恢复:
sudo setenforce 1
然后再用正确的 context 或 boolean 处理。
如果你用的是 WordPress,403 还可能来自插件、防火墙规则或伪静态。
可以按这个顺序试:
- 临时改名安全插件目录;
- 重新生成固定链接;
- 检查
.htaccess或 Nginx 伪静态规则; - 检查
wp-content/uploads权限; - 看 Web 服务器 error log,而不是只看浏览器页面。
宝塔面板用户也要检查:
- 网站目录是否选错;
- 防盗链是否误拦截;
- URL 重写规则是否匹配错;
- WAF 或安全插件是否拦截;
- 站点根目录是否有
index.html或index.php。
面板能降低操作门槛,但 403 的根因还是那几类:目录、权限、规则、安全策略。
| 现象 | 最可能原因 | 先查什么 |
|---|---|---|
| 首页 403,日志写 directory index is forbidden | 没有 index 文件 | ls -lah、Nginx/Apache index 配置 |
| 日志写 Permission denied | 文件或父目录权限不够 | namei -om、owner、chmod |
| 只有某个目录 403 | location / .htaccess 拦截 | Nginx location、Apache Directory、.htaccess |
| CentOS 权限正常但仍 403 | SELinux 上下文不对 | getenforce、ls -Z、restorecon |
| WordPress 后台或上传目录 403 | 插件/WAF/伪静态/目录权限 | 插件、.htaccess、uploads 权限 |
| Cloudflare 前面显示 403 | 源站或 Cloudflare 规则拦截 | 源站日志、WAF、防火墙规则 |
真遇到 403,我一般不会先重装环境,也不会马上改 777。
我会按这个顺序来:
curl -I https://example.com
sudo tail -n 80 /var/log/nginx/error.log
ls -lah /var/www/site
namei -om /var/www/site/index.html
sudo nginx -T | grep -nE 'root|index|location|deny|try_files'
如果是 Apache,就换成:
sudo tail -n 80 /var/log/apache2/error.log
sudo apachectl configtest
grep -R "Require all" /etc/apache2/sites-enabled /etc/apache2/apache2.conf
CentOS 系列再加:
getenforce
ls -Z /var/www/site
按这个顺序,基本能在十几分钟内定位到是哪一层的问题。
403 Forbidden 最容易被误判成“网站挂了”。其实它往往是好消息:请求已经到 VPS 了,Web 服务也活着,只是某个规则或权限不让它读文件。
别一上来重装 Nginx、重启 VPS、改 DNS。先看 error log,再查 index、权限、配置和 SELinux。只要日志里出现 directory index is forbidden 或 Permission denied,方向就很明确了。
