úterý 9. února 2010

Running Django on shared hosting with mod_wsgi

I have recently started working on a new hobby project (internet cookbook - only in Czech, nothing to see yet). This is written in Django and runs on shared webhosting (Web4ce). Django contains reasonable deployment documentation but unfortunately it deals only with configuring the site directly on Apache.

I can only modify .htaccess files so the deployment was a little harder than just copying a few lines of code. I had to actually google what to do :)

In the end the site is running, and this is what I did. After a few tries getting just 500 error (and not knowing where the problem was) I began with more simple steps then trying to set everything at once.

Simple WSGI script


First, to make sure that mod_wsgi is correctly supported and running, I created file hello_wsgi.wsgi:

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

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

    return [output]


and .htaccess:

AddHandler wsgi-script .wsgi


Uploading these files to hosting and navigating to hello_wsgi.wsgi gave me my desired "Hello World!". At least something was working.
The scripts for this part were taken from http://www.rkblog.rk.edu.pl/w/p/mod_wsgi/.

Running django


Preparing django.wsgi seems simple enough once the WSGI is actually working, but the problem is when there are some other problems in configuration (as it was in my case :)).
To be able to debug these problems, I have modified the suggested WSGI configuration:

import os
import sys

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

sys.path.append('/path/to/my/www')

import django.core.handlers.wsgi
app = django.core.handlers.wsgi.WSGIHandler()

def application(environ, start_response):
    status = '200 OK'
        app(environ, start_response)
        output = 'ok'
    except Exception, e:
        output = 'error: %s ' % str(e)

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

    return [output]


Running on django.wsgi like this, I get all error messages and can fix the problems as they appear. After I got 'ok' as output, I only need to rename "def application" to something like "application_debug" and "app" to "application". And, voilà, I am running Django powered website.

Serving static files with Apache


The only problem remaining was to configure Apache to serve static files directly and not through Django (it's possible, but slow - see Big Fat Disclaimer here: http://docs.djangoproject.com/en/1.1/howto/static-files/#howto-static-files ). Again, the original documentation was not very helpful, so I digged into Apache mod_rewrite and this is what I came up with:


RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(site_media/.*)$ /edesia/$1 [QSA,PT,L]


These two lines put into .htaccess cause all the static content (stored under directory site_media) to be served directly by apache from /edesia/site_media directory.

The whole .htaccess file then for me (and for now) looks like this:


DirectoryIndex django.wsgi

AddHandler wsgi-script .wsgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(site_media/.*)$ /edesia/$1 [QSA,PT,L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /django.wsgi/$1 [QSA,PT,L]


And that's it. The deployment took a little longer than I anticipated (plus I still have a lot more to do regarding deployment - see http://djangobook.com/en/2.0/chapter12/). But the site is running and that's fine with me now. Now I can concentrate on the development, find someone who will do the design and fill recipes. Hopefully by the beginning of spring I will have some reasonably complete version.

See also:
http://code.google.com/p/modwsgi/wiki/IntegrationWithDjango
http://code.google.com/p/modwsgi/wiki/ConfigurationGuidelines

2 komentáře:

  1. I found this post after hours of banging my head against a wall. Thank you!!! May your beer always be cold!

    OdpovědětVymazat