生产环境最稳妥的做法是在反向代理(如 Nginx)层终止 SSL,再通过 HTTP 头告知 Django 当前是 HTTPS 请求,最后开启 Django 的安全设置强制跳转。
先说结论:不要直接在 Django 内部处理证书,而是配合反向代理完成跳转,同时修正代理头配置避免重定向循环。
- 先判断:确认架构是 Django 直连 HTTPS 还是前方有 Nginx/Apache 代理
- 优先做:配置 ALLOWED_HOSTS、SECURE_SSL_REDIRECT 和 SECURE_PROXY_SSL_HEADER
- 再验证:使用 curl 测试 HTTP 请求是否返回 301 跳转且无循环,检查是否出现 400 错误
Django 配置修改 (settings.py)
生产环境必须显式声明允许的域名,否则 Django 会拒绝所有请求返回 400 Bad Request。同时开启安全设置强制 HTTPS。
# settings.py
ALLOWED_HOSTS = ['your-domain.com', 'www.your-domain.com', '127.0.0.1']
# 强制 HTTPS 跳转
SECURE_SSL_REDIRECT = True
# 告知 Django 信任代理传来的 HTTPS 标识
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# 防止 Cookie 通过 HTTP 泄露
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# 可选:生产环境建议开启,防止客户端 JS 读取 Cookie
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
Nginx 完整配置示例
需要在 Nginx 中配置两个 server 块:一个监听 80 端口强制跳转 HTTPS,另一个监听 443 端口处理 SSL 并传递协议头。
server {
listen 80;
server_name your-domain.com www.your-domain.com;
# 强制跳转 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name your-domain.com www.your-domain.com;
# SSL 证书路径
ssl_certificate /etc/nginx/ssl/your-domain.com.crt;
ssl_certificate_key /etc/nginx/ssl/your-domain.com.key;
location / {
proxy_pass http://127.0.0.1:8000; # 根据实际 Django 运行端口修改
# 关键:传递协议头,防止 Django 无限重定向
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
防火墙与服务重启
配置完成后,需确保防火墙开放 80 和 443 端口,并重启服务使配置生效。
1. 开放防火墙端口(以 UFW 为例):
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
2. 检查配置语法并重启 Nginx:
sudo nginx -t
sudo systemctl restart nginx
3. 重启 Django 服务(根据实际部署方式):
# 示例:Gunicorn
sudo systemctl restart gunicorn
# 示例:uWSGI
sudo systemctl restart uwsgi
验证是否生效
使用 curl 命令分别测试 HTTP 和 HTTPS 请求,观察响应头和状态码。
1. 测试 HTTP 自动跳转:
curl -I http://your-domain.com
预期返回 301 Moved Permanently,且 Location 头以 https:// 开头。
2. 测试 HTTPS 正常访问:
curl -I https://your-domain.com
预期返回 200 OK,且不再出现跳转。
常见故障排查
- 无限重定向循环:通常是
SECURE_PROXY_SSL_HEADER未配置或 Nginx 未传递X-Forwarded-Proto头。Django 始终认为请求是 HTTP 而不断跳转。 - 400 Bad Request:检查
ALLOWED_HOSTS是否包含当前访问的域名。生产环境默认不允许空主机头。 - 健康检查失败:负载均衡器的 HTTP 健康检查可能被 301 重定向干扰,需配置豁免路径或改用 HTTPS 检查。
- HSTS 谨慎开启:
SECURE_HSTS_SECONDS设置后浏览器会强制记住 HTTPS,一旦证书出问题很难恢复,建议稳定运行后再开。