部署于Apache2+mod_wsgi的Django应用出现400 Bad Request错误
Django部署Apache出现400 Bad Request(虚拟环境正常)排查方案
可能的问题点及修复步骤
1. Apache配置中WSGI脚本映射位置错误
你的WSGIScriptAlias和WSGIPythonPath写在了<VirtualHost>标签外部,会导致多应用的WSGI配置冲突(第一个应用可能已占用根路径的映射规则)。
修复方案:
将这两行移到<VirtualHost *:80>内部,同时修正静态/媒体目录的物理路径配置:
<VirtualHost *:80> ServerName prod-domain.de <Directory /opt/myproject/mysite/mysite> <Files wsgi.py> Require all granted </Files> </Directory> Alias /media/ /opt/myproject/mysite/media/ Alias /static/ /opt/myproject/mysite/base/static/ # 注意:这里要写实际物理路径,不是URL路径 <Directory /opt/myproject/mysite/base/static/> Require all granted </Directory> <Directory /opt/myproject/mysite/media/> Require all granted </Directory> # 把WSGI配置移到虚拟主机内部 WSGIScriptAlias / /opt/myproject/mysite/mysite/wsgi.py # 补充项目根目录到Python路径,确保Django能找到模块 WSGIPythonPath /opt/myproject/mysite/env/lib/python3.8/site-packages:/opt/myproject/mysite ErrorLog ${APACHE_LOG_DIR}/error-myproject.log CustomLog ${APACHE_LOG_DIR}/access-myproject.log combined </VirtualHost>
2. 多应用虚拟环境隔离不足
同一服务器上的两个Django应用可能共享了Apache的全局Python环境,导致第二个应用的虚拟环境未被正确加载。
修复方案:
使用WSGIDaemonProcess为每个应用创建独立的守护进程,彻底隔离环境:
<VirtualHost *:80> ServerName prod-domain.de # 创建独立守护进程,指定项目路径和虚拟环境路径 WSGIDaemonProcess myproject python-path=/opt/myproject/mysite:/opt/myproject/mysite/env/lib/python3.8/site-packages WSGIProcessGroup myproject <Directory /opt/myproject/mysite/mysite> <Files wsgi.py> Require all granted </Files> </Directory> Alias /media/ /opt/myproject/mysite/media/ Alias /static/ /opt/myproject/mysite/base/static/ <Directory /opt/myproject/mysite/base/static/> Require all granted </Directory> <Directory /opt/myproject/mysite/media/> Require all granted </Directory> WSGIScriptAlias / /opt/myproject/mysite/mysite/wsgi.py process-group=myproject ErrorLog ${APACHE_LOG_DIR}/error-myproject.log CustomLog ${APACHE_LOG_DIR}/access-myproject.log combined </VirtualHost>
3. 强制规范请求Host头
即使设置了ALLOWED_HOSTS,如果请求的Host头和配置的ServerName不匹配,也会触发400错误。
修复方案:
在虚拟主机配置中添加UseCanonicalName On,强制Apache使用配置的域名处理请求:
<VirtualHost *:80> ServerName prod-domain.de UseCanonicalName On # 其余配置保持不变 </VirtualHost>
4. 开启Django详细日志排查
如果Apache日志无有效信息,直接开启Django的调试日志,获取400错误的具体原因:
在settings.py中添加日志配置:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'file': { 'level': 'DEBUG', 'class': 'logging.FileHandler', 'filename': '/opt/myproject/mysite/django_debug.log', }, }, 'loggers': { 'django': { 'handlers': ['file'], 'level': 'DEBUG', 'propagate': True, }, }, }
重启Apache后访问应用,查看django_debug.log即可看到400错误的详细触发原因。
5. 验证静态文件收集状态
确保已执行collectstatic命令,将静态文件同步到STATIC_ROOT目录:
cd /opt/myproject/mysite source env/bin/activate python manage.py collectstatic
操作顺序建议
- 修正Apache配置中的路径和WSGI脚本位置
- 添加守护进程实现环境隔离
- 执行
collectstatic同步静态文件 - 开启Django日志排查剩余问题
内容的提问来源于stack exchange,提问作者gilgamesh
相关产品推荐
相关产品推荐

