25th January 2010

Posted in

Blog :: Migrating from CentOS 4/cpanel to CentOS 5

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

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:

import os, sys, site, pwd

user = pwd.getpwuid(os.getuid())[0]
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...

Posted on January 25th 2010, 12:03 AM

blog comments powered by Disqus