jump to navigation

Developing with mod_wsgi 2 August 2009

Posted by manniwood in Programming.
trackback

Note: Graham Dumpleton, author of mod_wsgi, was nice enough to leave a comment about DirectoryIndex that says my commenting-out step is not necessary. Naturally, he was correct, and this post has been edited to reflect that. Much obliged, Graham Dumpleton!

Despite mod_wsgi having reasonably good documentation, getting it set up still involved some guessing and some experimentation. I learned some lessons along the way, and today’s blog entry is about sharing those lessons, to hopefully ease other people’s initial setup of mod_wsgi.

First off, the installation instructions are quite good, and the link to the Django-specific stuff is of high quality, too. (In fact, reading them first will make this blog most useful.) That being said, there are a few things that are only shown rather than shown and explained. I learned a few lessons about what is customisable to your environment, and what is set in stone.

First off, when putting this line in httpd.conf,

LoadModule wsgi_module modules/mod_wsgi.so

things seem to work fine if you add that line after all the other LoadModule lines, like so:

LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule logio_module modules/mod_logio.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule mime_module modules/mod_mime.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule wsgi_module modules/mod_wsgi.so

To the best of my knowledge, the order that modules are listed in httpd.conf used to matter in the 1.3.x days, but it looks like this no longer matters with the 2.x series. So listing mod_wsgi after all the other modules is convenient, at least if you like listing your custom modules last.

DirectoryIndex—Ignore this Section

Note: I’m leaving this section intact so that Graham Dumpleton’s comment in the comments section will make sense / have context. But you should ignore this section. Bottom line: the default “DirectoryIndex index.html” in your httpd.conf file can be left alone: mod_wsgi helpfully overrides it if your Django url mapping matches empty strings (r’^$’) or single slashes (r’^/$’) that you want to go to functions in your app, and not index.html.

The Django app that I’m working on is designed to be rooted at “/”, so, for instance, a call to


http://www.mywebapp.com/

should call into my Django app. I don’t bother putting my Django app in a sub-url, like so:


http://www.mywebapp.com/mywebapp/

This means that I want the following url mapping to work:

(r'^$', logon.show_logon),
(r'^/$', logon.show_logon),

By default, Apache will not let such URIs be handled by mod_wsgi, and It turns out the reason makes a lot of sense: Apache’s DirectoryIndex option handles index-like URIs, and it is turned on by default. All I had to do was comment out DirectoryIndex in my httpd.conf:

# DirectoryIndex index.html

and Django was then able to process ” and ‘/’ URIs.

wsgi.py

There’s a little python script that you have to write to liaise between mod_wsgi and Django, and I had to experiment with it a bit to get it working, despite the quite good instructions at Google Code.

First off, you can name the file whatever you want, which is good. I forget if you can keep the file wherever you want (for instance, maybe it would be nice to keep it in Apache’s conf directory instead of with the rest of your Python files), but I ended up keeping mine in its own subdirectory of my main python directory in my project directory.

That is, if my project directory looks like this:

/dev/project/myapp/__init__.py
/dev/project/myapp/settings.py
/dev/project/myapp/urls.py
/dev/project/myapp/...(other Python files)

I put my wsgi.py file (actually named myapp_wsgi.py) in its own subdirectory, like so:

/dev/project/myapp/mod_wsgi/myapp_wsgi.py

It turns out that mayapp_wsgi.py could not find any of my web app or its imports. As per a lot of Django coding style, the imports in my webapp are currently a bit lazy. I take advantage of Python’s relative imports, and sometimes do this

import somefeature

and sometimes do this

import myapp.somefeature

I had to tell myapp_wsgi.py about both path possibilities:

import os, sys

sys.path.append('/dev/project/myapp')
sys.path.append('/dev/project')

My whole /dev/project/myapp/mod_wsgi/myapp_wsgi.py file looks like this:

import os, sys

sys.path.append('/dev/project/myapp')
sys.path.append('/dev/project')

# Handy; prints to /logs/error_log
#print >> sys.stderr, sys.path

import myapp.settings

os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'

import django.core.handlers.wsgi

application = django.core.handlers.wsgi.WSGIHandler()

File Locations and Permissions

With my particular project, I ended up with two locations for static files. I needed one location for static files that had to be at the root URI, such as


http://www.myapp.com/favicon.ico

http://www.myapp.com/robots.txt

and they were kept in my project at

/dev/project/htdocs

whereas all other static files would be served from URIs beneath “/static/”:


http://www.myapp.com/static/css/mycss.css

and they were kept in

/dev/project/static

Here’s how I made that happen. First, DocumentRoot was set to my project’s htdocs dir:

# This is always in httpd.conf;
# I just modified it to have the correct path:
DocumentRoot "/dev/project/htdocs"
...
# This is also always in httpd.conf;
#I just modified it to have the correct path:
<Directory "/dev/project/htdocs">
    Options Indexes FollowSymLinks
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>
...
# This whole stanza is new;
# I added it myself at the bottom
# of httpd.conf:
<Directory "/dev/project/static">
    Options Indexes FollowSymLinks
    Order allow,deny
    Allow from all
</Directory>
Alias "/static" "/dev/project/static"

Finally, I had to add the config for mod_wsgi itself. I was hoping that putting this line at the very end (even after the /static directory directive that I also put at the end) of httpd.conf would do the trick:

WSGIScriptAlias "/" "/dev/project/myapp/mod_wsgi/myapp_wsgi.py"

A one line configuration of an Apache module would have been sweet.

Unfortunately (from the standpoint of simplicity) or fortunately (from the standpoint of security), I had to tell Apache that it was allowed to read that Python file, so I ended up with this instead:

WSGIScriptAlias "/" "/dev/project/myapp/mod_wsgi/myapp_wsgi.py"
# yes, you really do need to make this allowable
# even though it contains executable code
<Directory "/dev/project/myapp/mod_wsgi">
Order deny,allow
Allow from all
</Directory>

On the plus side, this made me more confident that Apache and mod_wsgi did not have access to the rest of my filesystem. Also, because I put myapp_wsgi.py in its own directory (mod_wsgi/), and gave Apache access to only that directory, my other python files in my project were safe from reading. (In other words, /dev/project/myapp/*py files were safe from being read.)

Developing with the Whole Stack

I’ve found that running Apache/mod_wsgi/Django on my Linux dektop and using the whole software stack as my development server is a nice way of keeping bugs from getting into production. It means I have to do a bit more starting and stopping of the server than with Django’s build-in dev server, but knowing everything works in the full stack is worth the starting and stopping of Apache. (Besides, once you have the start/stop commands in your Bash history, you just up-arrow. No big deal.)

Also, because I just came from a lifetime of waiting for Java to compile and Tomcat to start up, I still feel way more productive developing with the whole Apache/mod_wsgi/Django software stack. Apache starts and stops instantaneously (especially compared to Tomcat) and Python, of course, doesn’t really compile in the Java sense of the word.

I’m still not missing my J2EE days…

Comments»

1. Graham Dumpleton - 2 August 2009

Commenting out DirectoryIndex shouldn’t have been necessary. The WSGIScriptAlias directive will take precedence over that.

For automatic source code reloading and avoiding manual restarts of Apache, see:

http://code.google.com/p/modwsgi/wiki/ReloadingSourceCode

manniwood - 2 August 2009

First comment from the author of mod_wsgi! Thanks so much!

Commenting out DirectoryIndex was the only thing that worked for me… is it because these notes are based on version 2.3 of mod_wsgi? I’ve upgraded to 2.5 without changing my configuration settings. Now you’ve got me curious. I’ll go back and test…

manniwood - 3 August 2009

I’ve done more testing. Naturally, you were right. I’ll be posting corrections shortly…

2. Developing with mod_wsgi—Corrected « Manni Wood - 3 August 2009

[...] 3 August 2009 Posted by manniwood in Uncategorized. trackback My post Developing with mod_wsgi has been [...]