Apache+mod_wsgi部署多Django项目加载错误模块问题求助
问题描述
在Windows服务器上通过Apache+mod_wsgi部署多个Django开发/测试项目,此前成功部署过多Flask项目。
项目结构
ProjectA(含认证/登录/登出功能) - appa1(共享模板/静态文件) - appa2 ProjectB - appa1(共享模板/静态文件) - appb1 - appb2 ProjectC - appa1(共享模板/静态文件) - appc1 - appc2
Apache VirtualHost配置
<VirtualHost dev.projecta.mydomain.com:80> ServerName dev.projecta.mydomain.com Redirect / https://dev.projecta.mydomain.com </VirtualHost> <VirtualHost dev.projecta.mydomain.com:443> ServerName dev.projecta.mydomain.com WSGIScriptAlias / "C:/projecta/projecta.wsgi" CustomLog "logs/projecta_access.log" common ErrorLog "logs/projecta_error.log" SSLEngine on SSLCertificateFile "C:/path/to/projecta_cert/cert.cer" SSLCertificateKeyFile "C:/path/to/projecta_cert/project.key" <Directory C:\projecta> Require all granted </Directory> </VirtualHost> <VirtualHost dev.projectb.mydomain.com:80> ServerName dev.projectb.mydomain.com Redirect / https://dev.projectb.mydomain.com </VirtualHost> <VirtualHost dev.projectb.mydomain.com:443> ServerName dev.projectb.mydomain.com WSGIScriptAlias / "C:/projectb/projectb.wsgi" CustomLog "logs/projectb_access.log" common ErrorLog "logs/projectb_error.log" SSLEngine on SSLCertificateFile "C:/path/to/projectb_cert/cert.cer" SSLCertificateKeyFile "C:/path/to/projectb_cert/project.key" <Directory C:\projectb> Require all granted </Directory> </VirtualHost> <VirtualHost dev.projectc.mydomain.com:80> ServerName dev.projectc.mydomain.com Redirect / https://dev.projectc.mydomain.com </VirtualHost> <VirtualHost dev.projectc.mydomain.com:443> ServerName dev.projectc.mydomain.com WSGIScriptAlias / "C:/projectc/projectc.wsgi" CustomLog "logs/projectc_access.log" common ErrorLog "logs/projectc_error.log" SSLEngine on SSLCertificateFile "C:/path/to/projectc_cert/cert.cer" SSLCertificateKeyFile "C:/path/to/projectc_cert/project.key" <Directory C:\projectc> Require all granted </Directory> </VirtualHost>
问题表现
- 访问ProjectA正常,但访问ProjectB出现500错误,日志报错:
[Wed May 10 09:13:49.594211 2023] [wsgi:error] [pid 17300:tid 1400] [client 9.26.10.10:15429] ModuleNotFoundError: No module named 'appa2'\r, referer: https://dev.projectb.mydomain.com/
- ProjectB中并无appa2模块;重启Apache后先访问ProjectB则正常,但访问其他项目(如ProjectA)会报错找不到appb1模块。
各项目WSGI文件配置
import os import platform import sys from pathlib import Path # Activate the project specific virtual environment path = Path(__file__).resolve().parent.parent # Set the path to the project root in the system PATH sys.path.insert(0, str(path)) activate_dir = "Scripts" if platform.system() == "Windows" else "bin" activate_script = "activate_this.py" activate_path = path / "venv" / activate_dir / activate_script if activate_path.is_file(): exec( compile(open(activate_path).read(), activate_path, "exec"), dict(__file__=activate_path), ) # Import django-environ which is installed in the venv import environ ROOT_DIR = Path(__file__).parent.parent # `projecta` is changed to `projectb` and `projectc` in each project appropriately env = environ.Env( DJANGO_SETTINGS_MODULE=(str, "projecta.settings.base"), ) env.read_env(ROOT_DIR / ".env") # Load up the django application settings_module = env.str("DJANGO_SETTINGS_MODULE") if not settings_module: # `projecta` is changed to `projectb` and `projectc` in each project appropriately os.environ["DJANGO_SETTINGS_MODULE"] = "projecta.settings.base" from django.core.wsgi import get_wsgi_application application = get_wsgi_application()
已确认各项目.env文件配置正确,需排查并解决该问题。
排查与解决方法
核心原因
mod_wsgi默认以嵌入式模式运行,所有VirtualHost的WSGI应用共享同一个Apache进程。第一个项目加载后,其模块路径和已加载的模块会被后续项目继承,导致模块查找逻辑混乱(比如ProjectA加载的appa2会被ProjectB的Python解释器误查找)。
解决步骤
1. 启用守护进程模式,实现项目进程隔离
在每个项目的443 VirtualHost配置块中添加守护进程配置,让每个项目运行在独立的进程组:
以ProjectA为例修改配置:
<VirtualHost dev.projecta.mydomain.com:443> ServerName dev.projecta.mydomain.com # 新增守护进程配置 WSGIDaemonProcess projecta python-home=C:/projecta/venv python-path=C:/projecta WSGIProcessGroup projecta WSGIScriptAlias / "C:/projecta/projecta.wsgi" CustomLog "logs/projecta_access.log" common ErrorLog "logs/projecta_error.log" SSLEngine on SSLCertificateFile "C:/path/to/projecta_cert/cert.cer" SSLCertificateKeyFile "C:/path/to/projecta_cert/project.key" <Directory C:\projecta> Require all granted </Directory> </VirtualHost>
同理修改ProjectB和ProjectC的配置,将projecta替换为projectb/projectc,并确保python-home指向对应项目的虚拟环境根目录,python-path指向项目根目录。
2. 优化WSGI文件,避免路径污染
当前WSGI文件的sys.path.insert(0, str(path))会把项目路径插入全局路径最前面,在共享进程下会干扰后续项目。修改WSGI文件,重置路径并仅添加当前项目路径:
import os import sys from pathlib import Path # 重置sys.path,保留系统默认路径,避免继承其他项目的路径 sys.path = sys.path[:] # 添加当前项目根路径到sys.path path = Path(__file__).resolve().parent.parent sys.path.insert(0, str(path)) import environ ROOT_DIR = Path(__file__).parent.parent # 替换为对应项目的默认设置 env = environ.Env( DJANGO_SETTINGS_MODULE=(str, "projecta.settings.base"), ) env.read_env(ROOT_DIR / ".env") settings_module = env.str("DJANGO_SETTINGS_MODULE") if not settings_module: # 替换为对应项目的设置路径 os.environ["DJANGO_SETTINGS_MODULE"] = "projecta.settings.base" from django.core.wsgi import get_wsgi_application application = get_wsgi_application()
可以去掉原WSGI文件中的虚拟环境激活逻辑,因为WSGIDaemonProcess的python-home已经指定了虚拟环境,mod_wsgi会自动使用该环境的Python解释器。
3. 重启Apache并验证
修改配置后重启Apache服务,依次访问所有项目,确认模块找不到的错误是否消失。
额外检查点
- 确认每个项目的
INSTALLED_APPS配置正确,未引用其他项目的应用。 - 检查Apache进程对各项目目录的访问权限,确保文件可读取。
- 验证各项目的虚拟环境独立,依赖无交叉安装。
内容的提问来源于stack exchange,提问作者UpDawg
相关产品推荐
相关产品推荐

