I'm trying to run multiple Django projects on one server. The server is Windows and I am using mod_wsgi with Apache.
Normally, each project lives on it's own server and everything works great - but for dev/staging purposes I am trying to just serve them all from the same server (I've done this successfully with other groups of projects on another server, but they were Flask applications)
My structure looks similar to this:
ProjectA (this project contains the authentication / login / logout)
- appa1 (shared templates / static files)
- appa2
ProjectB
- appa1 (shared templates / static files)
- appb1
- appb2
ProjectC
- appa1 (shared templates / static files)
- appc1
- appc2
My VirtualHost setup is pretty straightforward:
<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>
When I access ProjectA
in the browser (https://dev.projecta.mydomain.com) everything fires up and works as I would expect. I login and everything works.
When I visit a link to ProjectB
I get a 500 error - the error is recorded in projectb_error.log
and states this:
[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/
There is no appa2
in ProjectB
; so I'm not sure why it's still trying to access it.
If I restart Apache and visit ProjectB
first? Everything loads fine for ProjectB (this is important to keep in mind).
When I visit a link to any other project (for example: ProjectA
) I get a 500 error - the error is recorded in projecta_error.log
and states this:
[Wed May 10 09:15:49.594211 2023] [wsgi:error] [pid 17300:tid 1400] [client 9.26.10.10:15429] ModuleNotFoundError: No module named 'appb1'\r, referer: https://dev.projecta.mydomain.com/
In essence, when I restart Apache - the first site I visit loads fine, but the subsequent sites I visit show a similar error in the logs (stating that it can't find a module that is specific to the previous site).
It works when these projects are on different servers - but not on the same server. That's the only difference.
The .wsgi
for each project isn't very complex either:
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()
I've double checked my .env
files to ensure they are correct.
I'm not sure how best to continue troubleshooting this - I am not sure if this error is related to Apache and how it's setup, or more related to Django and perhaps sessions or cookies causing an issue? Maybe it's mod_wsgi
?
I've not ran into something as odd as this before.
TL;DR: Apache loads first site fine - 500's on all subsequent projects because it's trying to reference a module specific to the first site visited. If Apache is restarted the second site will load fine, but any other site will 500 with references to a module specific to the second site.
try to add different application groups for each app
WSGIScriptAlias / "d:/.... /wsgi.py" application-group=app_name1
and some more hints about mod_wsgi and virtual hosts in the answer here: How to deploy multiple django apps on apache in Windows?
update: most certainly this has to do with wrong settings.py file.
try the following:
change:
# 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"
to simply
os.environ["DJANGO_SETTINGS_MODULE"] = "projecta.settings.base"