Addohm Addohm - 1 month ago 31
Apache Configuration Question

apache mod_wsgi error with django in virtualenv

I can't seem to find a good answer to this. Who needs to own the virtualenv when running it as a WSGIDaemon? I assume on my OS (Ubuntu 16) www-data, but I want to be sure. Trying some new things to get this thing working based off of the answer from this post...

django apache configuration with WSGIDaemonProcess not working

Does the django project, the virtualenv folder, or both need to be owned by the apache group? What ownerships need to be in place to serve a django project without specifying a port? Why do I get the following?

The root problem:

Call to 'site.addsitedir()' failed for '(null)'


When I start apache, I get this error. I've followed several different guides, including:
http://modwsgi.readthedocs.io/en/develop/user-guides/virtual-environments.html
and
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/modwsgi/
but have had zero success.

My virtual environment path is
/usr/local/virtualenvs/servicesite


My django project path is
/home/addohm/projects/rtservice/servicesite

this is where manage.py resides,
which leaves
/home/addohm/projects/rtservice/servicesite/servicesite
as the location of my wsgi.py.

wsgi.py:

SERVICESITE = ['/usr/local/virtualenvs/servicesite/lib/python3.5/site-packages']

import os
import sys
import site

prev_sys_path = list(sys.path)

for directory in SERVICESITE
site.addsitedir(directory)

new_sys_path = []
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path

""" **Doesn't seem to work, throwing error in apache logs**
site.addsitedir('/usr/local/virtualenvs/servicesite/lib/python3.5/site-packages')
"""

from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "servicesite.settings")
application = get_wsgi_application()
DJANGO_PATH = os.path.join(os.path.abspath(os.path.dirname(__file__)), '..')
sys.path.append(DJANGO_PATH)


apache2.conf

[...]

WSGIDaemonProcess servicesite python-path=/home/addohm/projects/rtservice/servicesite:/usr/local/virtualenvs/servicesite/lib/python3.5/site-packages
WSGIProcessGroup servicesite
WSGIScriptAlias / /home/addohm/projects/rtservice/servicesite/servicesite/wsgi.py

Alias /static/ /home/addohm/projects/rtservice/servicesite/static/
<Directory /home/addohm/projects/rtservice/servicesite/static/>
Require all granted
</Directory>

<Directory /home/addohm/projects/rtservice/servicesite/servicesite>
<Files wsgy.py>
Require all granted
</Files>
</Directory>


[...]

Answer

You should not have need to change anything in the original wsgi.py generated by Django for you. It is generally sufficient to have:

import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "servicesite.settings")
application = get_wsgi_application()

Your Apache configuration should then preferably be:

WSGIDaemonProcess service site python-home=/usr/local/virtualenvs/servicesite \
    python-path=/home/addohm/projects/rtservice/servicesite
WSGIProcessGroup servicesite
WSGIScriptAlias / /home/addohm/projects/rtservice/servicesite/servicesite/wsgi.py

Alias /static/ /home/addohm/projects/rtservice/servicesite/static/
<Directory /home/addohm/projects/rtservice/servicesite/static/>
        Require all granted
</Directory>

<Directory /home/addohm/projects/rtservice/servicesite/servicesite>
        <Files wsgy.py>
                Require all granted
        </Files>
</Directory>

That is, use python-home for the location of the directory specified by sys.prefix for the virtual environment. Avoid using python-path and referring to the site-packages directory. Using python-home has been preferred way for a very long time and using it ensures that things fail in a more obvious way when you don't do things the correct way.

A few very important things.

The first is that mod_wsgi must be compiled for the specific Python major/minor version you want to use.

Second, the Python virtual environment must be created from the same Python installation as mod_wsgi was compiled for. You can't have mod_wsgi compiled against a system Python installation, but have your virtual environment based off a separate Python installation for same major/minor version in /usr/local.

Third, the user that Apache runs your code as must have read access to any directories/files for the main Python installation, the virtual environment and your application code. When you stick stuff under a home directory, it will not generally have access as the home directory prohibits others from reading anything in the home directory.

Fourth, if the mod_wsgi daemon process group is set to run as a different user than the Apache user, the Apache user still must at least have ability to read the wsgi.py file and all the directories down to that point.

Further reading on virtual environments which is more up to date: