Django documentation says to use:
WSGIScriptAlias / /path/to/mysite.com/mysite/wsgi.py
WSGIPythonPath /path/to/mysite.com
<Directory /path/to/mysite.com/mysite>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
To set environment variables which would be inherited by the Django application referred to by this, one can set them in the envvars
file created as part of the Apache installation. There are a few problems with that though.
The first is that Linux distributions created a completely different way of configuring Apache and ignored in large part how the Apache Software Foundations default Apache distribution works. How you would do the equivalent varies between Linux distributions but generally requires setting some other special file alongside the system init scripts. Unfortunately some Linux distributions didn't make this a separate file and instead require you to modify the init scripts themselves.
The second is that the envvars
file applies to the whole of Apache and cannot be made to apply to specific mod_wsgi daemon processes. This makes it unsuitable where hosting multiple Python web applications under the same Apache.
The much simpler way is to create a separate WSGI script file independent of the wsgi.py
that Django generates with its startproject
template. You might call this django.wsgi
, or you might have separate production.wsgi
and development.wsgi
files if have multiple environments. Place the WSGI script file in the same directory as the wsgi.py
file. In the file add something like:
import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
os.environ['DJANGO_CONFIGURATION'] = 'Production'
os.environ['DJANGO_SECRET_KEY'] = 'RANDOM_SECRET_KEY_HERE'
os.environ['DJANGO_AWS_ACCESS_KEY_ID'] = 'YOUR_AWS_ID_HERE'
os.environ['DJANGO_AWS_SECRET_ACCESS_KEY'] = 'YOUR_AWS_SECRET_ACCESS_KEY_HERE'
os.environ['DJANGO_AWS_STORAGE_BUCKET_NAME'] = 'YOUR_AWS_S3_BUCKET_NAME_HERE'
os.environ['SENDGRID_USERNAME'] = 'YOUR_SENDGRID_USERNAME'
os.environ['SENDGRID_PASSWORD'] = 'YOUR_SENDGRID_PASSWORD'
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
If you are concerned that you might have sensitive settings in a file which is part of your source code repository. Then have just the environment variables being set in a separate Python code file which you manually copy into place on the host in a directory such as /etc
.
For example, on OpenShift, you would place the file in ${OPENSHIFT_DATA_DIR}
and then use:
import os
OPENSHIFT_DATA_DIR = os.environ['OPENSHIFT_DATA_DIR']
os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'
execfile(os.path.join(OPENSHIFT_DATA_DIR, 'mysite-production-envvars.py'))
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
Alternatively, you could put the WSGI script file in a completely different location outside of the source code for your application, even putting it in a subdirectory under /etc
. In other words, tell your system adminstrator what needs to go in it and let them create it where they want to per their policies.
With the modified WSGI script file in place, change the name of the WSGI script file in the Apache configuration snippet to refer to it instead of the original wsgi.py
.
WSGIScriptAlias / /path/to/mysite.com/mysite/production.wsgi
WSGIPythonPath /path/to/mysite.com
<Directory /path/to/mysite.com/mysite>
<Files production.wsgi>
Require all granted
</Files>
</Directory>
Change the WSGIScriptAlias
and Directory
directive paths if you do put it under /etc
somewhere, but leave the WSGIPythonPath
setting alone as that still needs to refer to where the source code for the project resides.
If using mod_wsgi daemon mode as you should be, you would instead also have something like:
WSGIDaemonProcess example.com python-path=/path/to/mysite.com:/path/to/venv/lib/python2.7/site-packages
WSGIProcessGroup example.com
So you would be setting the python-path
option there to the location of your your source code instead. If using a modern version of mod_wsgi, use python-home
instead.
This method can be used for any environment variables with the exception of those which affect the operation of the processes as a whole at a system level. That is, you cannot set LANG
and LC_ALL
in this way. Modern versions of mod_wsgi though have lang
and locale
options on WSGIDaemonProcess
directive which achieve the same result. If not using daemon mode, you should be as embedded mode isn't generally recommended.
The only other problematic environment variable is LD_LIBRARY_PATH
. This is only a problem where shared libraries aren't installed in a proper system location. If this is unavoidable, set LD_RUN_PATH
to the library directory when installing any Python modules using the library and the location will be embedded in the Python module extension so that the shared library will be found whether or not LD_LIBRARY_PATH
is set properly.
In summary, ignore the Django generated wsgi.py
file. This never used to exist and that it started to be generated has caused problems with understanding how to set up Apache/mod_wsgi ever since. The first problem was that it used os.environ.setdefault()
which causes problems when running multiple Django applications in the same Apache process. Secondly, that wsgi.py
was auto generated, it gave users the impression that it would always be correct, must be used and wouldn't need modifying. Consequence was that people stopped seeing what one of the main roles of the WSGi script file was for, which was to set environment variables before the Django application got loaded.
@GrahamDumpleton Thanks fo this! One question, why not just add the env variables to the auto generated django wsgi.py?