Quick Configuration Guide

This document describes the steps for configuring mod_wsgi for a basic WSGI application.

If you are setting up mod_wsgi for the very first time, it is highly recommended that you follow the examples in this document. Make sure that you at least get the examples running to verify that mod_wsgi is working correctly before attempting to install any WSGI applications of your own.

WSGI Application Script File

WSGI is a specification of a generic API for mapping between an underlying web server and a Python web application. WSGI itself is described by Python PEP 3333:

The purpose of the WSGI specification is to provide a common mechanism for hosting a Python web application on a range of different web servers supporting the Python programming language.

A very simple WSGI application, and the one which should be used for the examples in this document, is as follows:

def application(environ, start_response):
    status = '200 OK'
    output = b'Hello World!'

    response_headers = [('Content-type', 'text/plain'),
                        ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]

This sample application will need to be placed into what will be referred to as the WSGI application script file. For the examples presented here, the WSGI application will be run as the user that Apache runs as. As such, the user that Apache runs as must have read access to both the WSGI application script file and all the parent directories that contain it.

Note that mod_wsgi requires that the WSGI application entry point be called ‘application’. If you want to call it something else then you would need to configure mod_wsgi explicitly to use the other name. Thus, don’t go arbitrarily changing the name of the function. If you do, even if you set up everything else correctly the application will not be found.

Mounting The WSGI Application

There are a number of ways that a WSGI application hosted by mod_wsgi can be mounted against a specific URL. These methods are similar to how one would configure traditional CGI applications.

The main approach entails explicitly declaring in the main Apache configuration file the URL mount point and a reference to the WSGI application script file. In this case the mapping is fixed, with changes only being able to be made by modifying the main Apache configuration and restarting Apache.

When using mod_cgi to host CGI applications, this would be done using the ScriptAlias directive. For mod_wsgi, the directive is instead called WSGIScriptAlias:

WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi

This directive can only appear in the main Apache configuration files. The directive can be used at server scope but would normally be placed within the VirtualHost container for a particular site. It cannot be used within either of the Location, Directory or Files container directives, nor can it be used within a “.htaccess” file.

The first argument to the WSGIScriptAlias directive should be the URL mount point for the WSGI application. For this case the URL should not contain a trailing slash. The only exception to this is if the WSGI application is to be mounted at the root of the web server, in which case ‘/’ would be used.

The second argument to the WSGIScriptAlias directive should be an absolute pathname to the WSGI application script file. It is into this file that the sample WSGI application code should be placed.

Note that an absolute pathname must be used for the WSGI application script file supplied as the second argument. It is not possible to specify an application by Python module name alone. A full path is used for a number of reasons, the main one being so that all the Apache access controls can still be applied to indicate who can actually access the WSGI application.

Because the Apache access controls will apply, if the WSGI application is located outside of any directories already configured to be accessible to Apache, it will be necessary to tell Apache that files within that directory can be used. To do this the Directory directive must be used:

<Directory /usr/local/www/wsgi-scripts>
<IfVersion < 2.4>
    Order allow,deny
    Allow from all
</IfVersion>
<IfVersion >= 2.4>
    Require all granted
</IfVersion>
</Directory>

Note that it is highly recommended that the WSGI application script file in this case NOT be placed within the existing DocumentRoot for your main Apache installation, or the particular site you are setting it up for. This is because if that directory is otherwise being used as a source of static files, the source code for your application might be able to be downloaded.

You also should not use the home directory of a user account, as to do that would mean allowing Apache to serve up any files in that account. In this case any misconfiguration of Apache could end up exposing your whole account for downloading.

It is thus recommended that a special directory be setup distinct from other directories and that the only thing in that directory be the WSGI application script file, and if necessary any support files it requires.

A complete virtual host configuration for this type of setup would therefore be something like:

<VirtualHost *:80>

    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@example.com

    DocumentRoot /usr/local/www/documents

    <Directory /usr/local/www/documents>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

    WSGIScriptAlias /myapp /usr/local/www/wsgi-scripts/myapp.wsgi

    <Directory /usr/local/www/wsgi-scripts>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

</VirtualHost>

After appropriate changes have been made Apache will need to be restarted. For this example, the URL ‘http://www.example.com/myapp’ would then be used to access the the WSGI application.

Note that you obviously should substitute the paths and hostname with values appropriate for your system.

Mounting At Root Of Site

If instead you want to mount a WSGI application at the root of a site, simply list ‘/’ as the mount point when configuring the WSGIScriptAlias directive:

WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi

Do note however that doing so will mean that any static files contained in the DocumentRoot will be hidden and requests against URLs pertaining to the static files will instead be processed by the WSGI application.

In this situation it becomes necessary to remap using the Alias directive, any URLs for static files to the directory containing them:

Alias /robots.txt /usr/local/www/documents/robots.txt
Alias /favicon.ico /usr/local/www/documents/favicon.ico

Alias /media/ /usr/local/www/documents/media/

A complete virtual host configuration for this type of setup would therefore be something like:

<VirtualHost *:80>

    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@example.com

    DocumentRoot /usr/local/www/documents

    Alias /robots.txt /usr/local/www/documents/robots.txt
    Alias /favicon.ico /usr/local/www/documents/favicon.ico

    Alias /media/ /usr/local/www/documents/media/

    <Directory /usr/local/www/documents>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

    WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi

    <Directory /usr/local/www/wsgi-scripts>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

</VirtualHost>

After appropriate changes have been made Apache will need to be restarted. For this example, the URL ‘http://www.example.com/’ would then be used to access the the WSGI application.

Note that you obviously should substitute the paths and hostname with values appropriate for your system.

Delegation To Daemon Process

By default any WSGI application will run in what is called embedded mode. That is, the application will be hosted within the Apache worker processes used to handle normal static file requests.

When embedded mode is used, whenever you make changes to your WSGI application code you would generally have to restart the whole Apache web server in order for changes to be picked up. This can be inconvenient, especially if the web server is a shared resource hosting other web applications at the same time, or you don’t have root access to be able to restart the server and rely on someone else to restart it.

On UNIX systems when running Apache 2.X, an option which exists with mod_wsgi and that avoids the need to restart the whole Apache web server when code changes are made, is to use what is called daemon mode.

In daemon mode a set of processes is created for hosting a WSGI application, with any requests for that WSGI application automatically being routed to those processes for handling.

When code changes are made and it is desired that the daemon processes for the WSGI application be restarted, all that is required is to mark the WSGI application script file as modified by using the ‘touch’ command.

To make use of daemon mode for WSGI applications hosted within a specific site, the WSGIDaemonProcess and WSGIProcessGroup directives would need to be defined. For example, to setup a daemon process group containing two multithreaded process one could use:

WSGIDaemonProcess example.com processes=2 threads=15
WSGIProcessGroup example.com

A complete virtual host configuration for this type of setup would therefore be something like:

<VirtualHost *:80>

    ServerName www.example.com
    ServerAlias example.com
    ServerAdmin webmaster@example.com

    DocumentRoot /usr/local/www/documents

    Alias /robots.txt /usr/local/www/documents/robots.txt
    Alias /favicon.ico /usr/local/www/documents/favicon.ico

    Alias /media/ /usr/local/www/documents/media/

    <Directory /usr/local/www/documents>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

    WSGIDaemonProcess example.com processes=2 threads=15 display-name=%{GROUP}
    WSGIProcessGroup example.com

    WSGIScriptAlias / /usr/local/www/wsgi-scripts/myapp.wsgi

    <Directory /usr/local/www/wsgi-scripts>
    <IfVersion < 2.4>
        Order allow,deny
        Allow from all
    </IfVersion>
    <IfVersion >= 2.4>
        Require all granted
    </IfVersion>
    </Directory>

</VirtualHost>

After appropriate changes have been made Apache will need to be restarted. For this example, the URL ‘http://www.example.com/’ would then be used to access the the WSGI application.

Note that you obviously should substitute the paths and hostname with values appropriate for your system.

As mentioned previously, the daemon processes will be shutdown and restarted automatically if the WSGI application script file is modified.

For the sample application presented in this document the whole application is in that file. For more complicated applications the WSGI application script file will be merely an entry point to an application being imported from other Python modules or packages. In this later case, although no change may be required to the WSGI application script file itself, it can still be touched to trigger restarting of the daemon processes in the event that any code in the separate modules or packages is changed.

Note that only requests for the WSGI application are handled within the context of the daemon processes. Any requests for static files are still handled within the Apache worker processes.

Debugging Any Problems

To debug any problems one should take note of the type of error response being returned, but more importantly one should look at the Apache error logs for more detailed descriptions of a specific problem.

Being new to mod_wsgi it is highly recommended that the default Apache LogLevel be increased from ‘warn’ to ‘info’:

LogLevel info

When this is done mod_wsgi will output additional information regarding when daemon processes are created, when Python sub interpreters related to a group of WSGI applications are created and when WSGI application script files are loaded and/or reloaded. This information can be quite valuable in determining what problem may be occuring.

Note that where the LogLevel directive may have been defined both in and outside of a VirtualHost directive, due to the VirtualHost declaring its own error logs, both instances of the LogLevel directive should be changed.

This is because although the virtual host may have its own error log, some information is still logged to the main Apache error log and the LogLevel directive outside of the virtual host context needs to be changed for that additional information to be recorded.

In other words, even if the VirtualHost has its own error log file, also look in the main Apache error log file for information as well.