You want to set up a Django application in production with the Apache web server and WSGI.
Install Apache and the mod_wsgi module. Configure the mod_wsgi module to locate your Django application and Python virtualenv with the
Create a separate Apache instance to serve static content for your Django application and update the application's
STATIC_URL variable to pick-up static content from this Apache instance. Alternatively, you can define Apache
Alias directives to leverage the same Apache instance running WSGI to also serve static content for the same Django application.
Apache is one of the most popular web servers to deploy web applications in production environments. It supports a wide array of applications written in different programming languages, so the core server is one of the most robust and secure offerings in the market. For Python applications, the Apache server supports WSGI through the mod_wsgi module. WSGI or 'Web Server Gateway Interface' is the Python programming language standard approach that defines a simple and universal interface between web servers and Python web applications or frameworks.
|Avoid using mod_python, FastCGI and CGI|
Besides mod_wsgi, Apache can also run Python applications with other approaches that you should avoid. CGI or 'Common Gateway Interface' was the first approach -- dating back to 1993 -- to run web applications in general. CGI is extremely inefficient because it requires to spawn a language interpreter (e.g. Python or other) to run the web application code on behalf of the web server. FastCGI is an improved version of CGI -- hence the preceding 'Fast' in its name -- but which nevertheless still provides sub-optimal conditions to run Python web applications.
mod_python emerged to address the shortcomings of CGI/FastCGI. mod_python embeds a Python interpreter into the Apache web server, which makes applications run faster than traditional CGI/FastCGI (e.g. Apache keeps things 'closer' in its processes, things like database connections and other data between hits and processing). However, mod_python's main advantage can also be a drawback, particularly for high-traffic applications. Because a Python interpreter is loaded into Apache's processes, the Apache processes become heavyweight and can suffer handling high amounts of traffic. In addition, mod_python is an Apache specific solution, which therefore can't be used with other web servers.
Because WSGI is the standard set forth by the Python language (http://www.python.org/dev/peps/pep-3333/) to promote common ground for portable communication between Python applications and web servers, it should be the preferred approach. And in the case of Apache, this means making use of the mod_wsgi module.
The easiest way to install mod_wsgi is through an OS package manager like
apt-get on Debian or Ubuntu. You can execute the command
apt-get install libapache2-mod-wsgi to trigger the installation. If you're on a different OS, then you'll need to download the mod_wsgi source code from http://code.google.com/p/modwsgi/downloads/list and follow the installation instructions.
Once you install mod_wsgi using any of the previous methods, you'll need to verify it's loaded on Apache. To verify which modules are loaded in Apache execute the command
apache2ctl -t -D DUMP_MODULES as illustrated in listing 1. In the list you should see a line
If you don't see the
wsgi_module (shared) line after you execute the command in listing 1, it means the mod_wsgi module still isn't loaded in Apache, even though it may be installed. To load Apache modules in an OS like Debian or Ubuntu you can use the
a2enmod command (e.g.
a2enmod wsgi). If you use another OS, consult the Apache documentation on how to load shared modules.
Once you're sure the mod_wsgi module is loaded into Apache, you'll need to configure a parameter specific to the Django application and Python virtualenv. If you're not using Python virtualenv or don't know what it's, I strongly recommend you use it because it makes application deployment much cleaner and simpler. The recipe Install Django contains full details on how to use Python virtualenv with Django.
mod_wsgi requires access to a project's Python modules (i.e.files). The way Python locates modules is through an environment variable called
PYTHONPATH which defines directories for the Python interpreter to look in. If a Python module is located in a directory not defined in
PYTHONPATH, then the Python interpreter won't be able to locate it. The same thing happens with mod_wsgi, if you don't tell mod_wsgi where the Django application and Python packages are located, it won't be able to run correctly.
mod_wsgi uses the
WSGIPythonPath parameter to define directories in which to search for Python modules. If you're using Apache on an OS like Debian or Ubuntu, the mod_wsgi has a configuration file called
wsgi.conf located in the directory
/etc/apache2/mods-available/ to configure this and other mod_wsgi parameters. For other OS Apache installations and if mod_wsgi is enabled, you should find the mod_wsgi configuration in an Apache configuration file surrounded by the XML tags
<IfModule mod_wsgi.c>. Listing 2 illustrates a sample setup with the
Notice in listing 2 how the value of the
WSGIPythonPath parameter is a directory list separated by
:. The first directory
/python/djangorecipes/lib/python2.7/site-packages/ corresponds to a Python virtualenv directory -- which gives mod_wsgi access to Django modules installed in the virtualenv. The second directory
/www/STORE/ corresponds to a BASE_DIR of a Django project or where a project's
manage.py file is located. Under
/www/STORE/ you would also find a sub-directory for the project name or PROJECT_DIR (e.g.
/www/STORE/coffeehouse/) and inside this sub-directory you would find Django's standard project files like
There are many other
WSGI* type variables you can modify to customize mod_wsgi, but for the moment you only need to set
WSGIPythonPath to get everything running.
|Don't define |
Although it's possible to define the mod_wsgi
Once you configure and setup mod_wsgi for your Django application, you can setup an Apache site configuration. Listing 3 illustrates an Apache virtual server site configuration.
The only Python/Django specific thing about the Apache site configuration in listing 3 is the
WSGIScriptAlias line. This line tells Apache to mount the application root
/ with the
/www/STORE/coffeehouse/wsgi.py script, the last of which corresponds to the WSGI script of a Django project. You can add any other Apache site configuration as you would for any other Apache site. Also note the
wsgi.py script is created by default when you start a Django project and there's no need to change anything in this file for a standard setup.
|ImportError: No module named django.core.wsgi|
(Cause: Apache can't locate the Django installation)
|ImportError: Could not import settings '<project_name>.settings' (Is it on sys.path?): No module named <project_name>.settings|
(Cause: Apache can't locate the Django application)
When you use Django's built-in web server (i.e.
python manager.py runserver) and have
DEBUG=True, the application's static resources are mounted as a convenience under the URL definition of the
STATIC_URL variable -- which defaults to
/static/. The use of the
DEBUG=False with Django's built-in web server or change to a different web server altogether (e.g. Apache), this convenience disappears and no static resources are served automatically.
Next, I'll describe two Apache alternatives. One uses two separate Apache server instances -- one for WSGI and the other for static resources -- which is the option I strongly recommend. And the other option describes how to setup an Apache WSGI server instance to also dispatch a Django application's static resources, in case you can't run multiple Apache instances on your hosting service or you simply don't want to monitor multiple server instances.
Keep in mind the following steps assume you have already consolidated your static resources into a single folder defined in
STATIC_ROOT. If you haven't made this consolidation or don't know what
Listing 4 illustrates a modified version of the Apache site configuration in listing 3. Listing 4 shows multiple Apache site configurations, one to run the main (WSGI) Django application and the other to run Django's static resources.
The first site configuration in listing 4 belongs to the WSGI server instance and is identical to the one described in listing 3, so there's isn't much left to explain about this configuration.
The second site configuration in listing 4 is used to dispatch static resources through the
static.coffeehouse.com domain. The
DocumentRoot directive tells Apache to dispatch resources located in the server's file system
/www/STORE/coffeestatic/, which represents the consolidation folder for static resources defined in
STATIC_ROOT. This means if a request is made to the
/css/bootstrap.css URL or the full URL
http://static.coffeehouse.com/css/bootstrap.css, Apache dispatches the file under the server's file system
<Directory> directives are just a standard Apache configurations to define permissions on the files located under
/var/www/. Where as the
CustomLog directives are standard Apache logging configurations.
Although the previous approach of using separate web servers for dynamic and static content is ideal, sometimes you may not want or cant run multiple Apache instances. For such a scenario you can use a single web server instance to handle all traffic.
Listing 5 illustrates a modified version of the Apache site configuration in listing 3, which is the 'quick & dirty' approach of dispatching static resources with the same WSGI instance. Use this option only if you can't or don't want to run multiple instances.
Alias /robots.txt /www/STORE/coffeestatic/robots.txt line in listing 5 tells Apache that when a URL request comes in for
/robots.txt -- or full URL
www.coffeehouse.com/robots.txt -- that it dispatch the file located in the server's file system
/www/STORE/coffeestatic/robots.txt -- where
/www/STORE/coffeestatic/ represents the consolidation folder for static resources defined in STATIC_ROOT. The other
Alias line uses the same technique but to dispatch requests made to the
Alias /static/ /www/STORE/coffeestatic/ line is different because it maps full-directory requests made to the
/static/ URL to the server's file system
/www/STORE/coffeestatic/. This means if a request is made to the
/static/bootstrap/bootstrap.css URL, Apache dispatches the file under the server's file system
Essentially what the Apache
Alias directive does is intercept certain URLs and dispatch files from the server's file system. The remaining
<Directory> directive is just a standard Apache configuration to define permissions on the files located under
Once you setup Apache to serve the static resources in either of the previous configurations under
/www/STORE/coffeestatic/ remember you'll also need to update the
STATIC_URL variable in your project's
|AWS S3 and WhiteNoise offer good alternatives to dispatch Django static files bypassing web server configurations|