Django 3.2 部署 Nginx 报 403 Forbidden 错误怎么解决?

文章导读
大多数情况下,Nginx 报 403 是因为文件权限不对、配置文件路径错误或缺少静态文件收集。先查 Nginx 错误日志定位具体原因,再调整权限或配置。
📋 目录
  1. 命令速用版
  2. 核心原因分析
  3. 分步解决方案
  4. 怎么验证是否生效
  5. 常见坑
A A

大多数情况下,Nginx 报 403 是因为文件权限不对、配置文件路径错误或缺少静态文件收集。先查 Nginx 错误日志定位具体原因,再调整权限或配置。

先说结论:403 错误通常是 Nginx 进程用户没有权限读取项目文件,或者配置中指定的根目录与实际不符。优先检查文件归属、Nginx 错误日志及 Django 静态文件收集状态。

  • 先确认:查看 Nginx 错误日志中具体的 permission denied 记录
  • 先处理:修正项目目录的所有者组和读写权限(避免全权交给 web 用户)
  • 再验证:执行 collectstatic 后重载 Nginx 配置,用 curl 测试访问

命令速用版

如果你需要快速排查,可以先执行以下命令查看权限、配置及静态文件状态:

# 查看 Nginx 错误日志最后 10 行
tail -n 10 /var/log/nginx/error.log

# 检查 Nginx 配置文件语法
nginx -t

# 重载 Nginx 配置
nginx -s reload

# 查看项目目录权限(假设项目在 /var/www/myproject)
ls -ld /var/www/myproject

# 收集 Django 静态文件(在项目目录下执行)
python manage.py collectstatic `--noinput`

核心原因分析

HTTP 403 Forbidden 表示服务器理解了请求,但拒绝执行。在 Django 配合 Nginx 的场景中,常见原因有三个:

  • 文件权限:Nginx 运行用户(通常是 www-data 或 nginx)对项目文件没有读取权限。
  • 配置路径:Nginx 配置中的 root 或 alias 指向了一个不存在或不允许访问的目录。
  • Django 设置:Django 的 ALLOWED_HOSTS 配置错误也可能导致请求被拒绝,虽然通常表现为 400,但在某些代理配置下可能混淆为 403。

此外,如果开启了 SELinux,安全上下文不对也会拦截访问。

分步解决方案

按照以下顺序逐步排查,每步做完后观察日志变化:

Django 3.2 部署 Nginx 报 403 Forbidden 错误怎么解决?

1. 查看错误日志
这是最关键的一步。打开 Nginx 错误日志,通常位于 /var/log/nginx/error.log。寻找包含 "permission denied" 或 "directory index of ... is forbidden" 的行。这会直接告诉你是哪个文件或目录出了问题。

2. 修正文件权限(安全做法)
确保 Nginx 用户有权读取项目文件,但不要将代码所有权完全交给 web 用户。假设你的登录用户是 $USER,Nginx 运行用户是 www-data,项目目录是 /var/www/mysite

# 修改所有者为当前用户,组为 www-data
chown -R $USER:www-data /var/www/mysite

# 目录赋予执行权限(进入权限),文件只读
find /var/www/mysite -type d -exec chmod 750 {} \;
find /var/www/mysite -type f -exec chmod 640 {} \;

注意:生产环境严禁为了方便直接给 777 权限,这会带来严重的安全风险。

3. 收集静态文件
Django 部署前必须收集静态文件,否则 Nginx 无法找到 CSS/JS 资源,可能导致页面加载失败或特定路径 403。在项目目录下执行:

python manage.py collectstatic `--noinput`

确保 Nginx 配置中的静态文件路径与 STATIC_ROOT 设置一致。

4. 检查 Nginx 配置
打开你的站点配置文件(通常在 /etc/nginx/sites-available//etc/nginx/conf.d/)。确保 location 块中的 alias 路径真实存在。参考配置示例:

Django 3.2 部署 Nginx 报 403 Forbidden 错误怎么解决?
server {
    listen 80;
    server_name example.com;

    # 静态文件配置
    location /static/ {
        alias /var/www/mysite/static/;
    }

    # 动态请求转发
    location / {
        include uwsgi_params;
        uwsgi_pass unix:/tmp/uwsgi.sock;
    }
}

注意:使用 alias 时,路径末尾的斜杠要保持一致,避免路径拼接错误。

5. 检查 Django 设置
检查 settings.py 中的 ALLOWED_HOSTS。如果设置为特定域名,确保 Nginx 转发的 Host 头匹配。生产环境建议明确列出域名:

ALLOWED_HOSTS = ['example.com', 'www.example.com', '127.0.0.1']

6. 检查 SELinux(仅限 CentOS/RHEL)
如果系统是 CentOS 且权限正确但仍报 403,可能是 SELinux 拦截。临时测试可执行 setenforce 0,如果恢复正常,则需要正确设置 SELinux 上下文,而不是长期关闭 SELinux。

怎么验证是否生效

完成调整后,不要只刷新浏览器,建议用命令行验证状态码:

curl -I http://你的域名或 IP
curl -I http://你的域名或 IP/static/css/style.css

观察返回的第一行,如果是 HTTP/1.1 200 OK 说明问题解决。同时再次查看 Nginx 访问日志,确认没有新的 403 记录。

常见坑

  • 父目录权限:有时候项目目录权限对了,但父目录没有执行权限(x),Nginx 用户依然无法进入该目录。
  • 索引文件:如果访问的是目录而不是具体文件,确保 Nginx 配置了 index index.html index.htm;,且该目录下确实存在这些文件。
  • 符号链接:如果项目目录是通过符号链接挂载的,确保 Nginx 配置中允许跟随符号链接,或者权限已正确设置到真实路径。
  • Socket 文件权限:如果使用 uWSGI/Gunicorn,确保 Nginx 用户有权限访问 socket 文件(通常需将 Nginx 用户加入应用运行用户组)。