I recently completed a migration for a customer from a VPS with CentOS 4 and whm/cpanel to a new dedicated server with CentOS 5. The box had a variety of websites in PHP and Python/Django so I took the opportunity to switch from Apache proxied to Lighttpd for the Django sites to mod_wsgi. I can't guarantee that this is the best way to set things up - but it works for me.
Following are some of the steps necessary to complete the move:
First I compiled and installed a newer version of Python (CentOS 5 comes with Python 2.4) and compiled and installed mod_wsgi using this helpful guide - although I went for Python 2.6 and mod_wsgi 3.1. This also got MySQLdb and setuptools compiled and installed for my new python 2.6. No particular surprises here.
I'm reusing the Python environment customization I used on the last server - adding a simple sitecustomize.py file to the site-packages directory. See the site module docs for details. My sitecustomize.py:
import os, site site.addsitedir(os.path.expanduser("~/.python"))
Next up is hooking my django site into mod_wsgi. Cpanel has a heavily customized Apache setup - you can't directly edit the httpd.conf nor does it simply include vhost.conf files - instead it has a baroque system of include files. I added include files that get added to the bottom of the vhost section as documented at the cpanel website. So for "domain.com" and user "test" I added a .conf file at /usr/local/apache/conf/userdata/std/2/test/domain.com/. My django.conf file looks like:
WSGIDaemonProcess test user=test display-name=% WSGIProcessGroup test WSGIApplicationGroup %
If my site had an ssl cert CPanel had a separate VirtualHost section for port 443 so I needed an additional config file at /usr/local/apache/conf/userdata/ssl/2/test/domain.com/. I couldn't just duplicate the django.conf used for port 80 - this would try to create a duplicate wsgi process group and fail. Thanks to Graham Dumpleton's blog I realised I only need to duplicate the WSGIProcessGroup declaration to hook into the existing wsgi process group and have the same Django instance serve both virtualhost declarations. Unfortunately the cpanel command I was running to collect the include files (/scripts/ensure_vhost_includes --user=username as per Cpanel's documentation) now complained about duplicate declarations. Running /usr/local/cpanel/bin/build_apache_conf instead sucessfully rebuilt the httpd.conf file - I have no idea why. I really don't like the non-standard Apache config system...
Now I need to hook up my wsgi application. In my ~public_html directories I add a django.wsgi file that looks like this:
#!/usr/bin/python import os, sys, site, pwd user = pwd.getpwuid(os.getuid()) sys.stdout = sys.stderr site.addsitedir(os.path.expanduser("~%s/.python" % user)) os.environ['DJANGO_SETTINGS_MODULE'] = 'settings' #def application(environ, start_response): # start_response('200 OK', [('content-type', 'text/plain')]) # return (user,) import django.core.handlers.wsgi application = django.core.handlers.wsgi.WSGIHandler()
A few details about the code - I seemed to get hit by a bug (Apache? wsgi? python?) where python thought I was user nobody even though I have mod_wsgi configured to run each wsgi processgroup as the appropriate user. The os.getuid stuff is to sniff what my username actually is - os.path.expanduser("~") was yielding "/home/nobody" for whatever reason. I've also got sys.stdout set to stderr since for wsgi applications print to stdout causes an exception... And yeah - I've got a print statement or two buried in some code somewhere. I've also got a commented-out "world's simplest possible wsgi app" thanks to Eric Florenzano. Very useful for debugging (It's how I figured out the expanduser problem, for example). When I've got things figured out I comment it out and use the standard Django wsgi handler.
I then use mod_rewrite to hook up to my django.wsgi like so:
RewriteRule ^static/(.*)$ - [L] RewriteRule ^admin_media/(.*)$ - [L] RewriteCond % !-f RewriteCond % !(django.wsgi) RewriteRule ^(.*)$ /django.wsgi/$1 [QSA,PT,L]
And that's pretty much it...
blog comments powered by Disqus