Search code examples
pythondjangoapachemod-wsgi

Multiple Django Projects on Apache Server with mod_wsgi is trying to load wrong project libraries?


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.


Solution

  • 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"