I also just implemented Django with mod_wsgi on a WHM/cPanel host, starting with mandric's tutorial instructions above. I encountered a few things that weren't covered there, so am posting my personal knowledgebase article here in case anyone finds useful tidbits in it.
Install Pyton 2.5 in a separate location.
I used /opt/python but am told that /opt/local/python is more standard for alternate python installations.
After grabbing source...
Code:
configure --enable-shared --prefix=/opt/python
make install
Environment
Put in root’s ~/.bash_profile:
Code:
alias python='/opt/python/bin/python'
You don’t want to be using $LD_LIBRARY_PATH to make python load its libs. Otherwise you’ll hit problems when installing mod_wsgi . But without LD_LIBRARY_PATH you can’t even launch python. The trick is this:
Code:
cat /etc/ld.so.conf.d/python2.5.conf
/opt/python2.5/lib
then run
. You can now just run “python” and get python 2.5 (rather than cpanel system 2.4) without library load errors.
Also install setuptools from source:
Code:
sh setuptools-0.6c9-py2.6.egg --prefix=/opt/python
MySQL and sqlite bindings
Compiled these from source and built :
Code:
python setup.py build
python setup.py install
Should now be able to launch python and :
Code:
import sqlite3
import MySQLdb
without errors.
mod_wsgi
Django professionals prefer mod_wsgi over mod_python by a wide margin, and hosts should too - it's less memory intensive, and much faster. We've found it 100% stable in a production Django environment.
It’s important to read the
mod_wsgi docs on building with shared libs - mod_wsgi should compile to around 140k. If it comes out 3MBs, then it’s got libraries baked in and will be resource wasteful.
Code:
./configure --with-apxs=/usr/local/apache/bin/apxs \
--with-python=/opt/python/bin/python
creates:
Code:
/usr/local/apache/modules/mod_wsgi.so
In WHM | Apache Setup, in Pre VirtualHost Include, add:
Code:
LoadModule wsgi_module /usr/local/apache/modules/mod_wsgi.so
AddHandler wsgi-script .wsgi
WSGISocketPrefix run/wsgi
Apache should not complain about missing libs. If it does… see section above about environment.
Apache will need a “run” dir to store the .pid files in:
Code:
mkdir -p /usr/local/apache/run
chmod a+w /usr/local/apache/run
Client setup
Each client gets their own django installation - not sharing a system-wide one. This way different users can make their own decisions on whether to use bleeding edge trunk or an older version, etc. Clients are pointed to a public Django FAQ for
their part of the setup. Root needs to set up a vhost definition and a wsgi bootstrap script for the domain, after learning the client’s project dir.
Technically the customer could do some of this, but to make it easier to get them bootstrapped, we’ll do most of it for them. If they want to create a project “foobar” on domain.com, do:
Code:
mkdir -p /home/[user]/sites/[domain]
cd /home/[user]/sites/[domain]
svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
ln -s django-trunk/django django
mkdir .python-eggs
chmod 777 .python-eggs
/home/[username]/sites/domain.com/django/bin/django-admin.py startproject foobar
cd /home/[username]
chown -R [username]: sites
Add to the user’s .bash_profile:
Code:
# Use python 2.5
alias python='/opt/python/bin/python'
# Set python path
export PYTHONPATH='$PYTHONPATH:/home/[username]/sites/[domain.com]'
User should now get Python 2.5 when launching Python, and should be able to:
Code:
import MySQLdb
import sqlite3
import django
without errors. Now to set up the vhost and the wsgi bootstrap:
Bootstrap
Create
Code:
/home/[username]/public_html/something.wsgi
:
Code:
#!/opt/python/bin/python
import os, sys
sys.path.insert(0,'/home/[username]/sites/domain.com')
os.environ['DJANGO_SETTINGS_MODULE'] = 'foobar.settings'
os.environ['PYTHON_EGG_CACHE'] = '/home/[username]/sites/domain.com/.python-eggs'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
Note: This assumes project name “foobar” created above, or by user.
Set up the vhost
Code:
mkdir -p /usr/local/apache/conf/userdata/std/2/[username]/domain.com
vi /usr/local/apache/conf/userdata/std/2/[username]/domain.com/vhost.conf
Contents:
Code:
<IfModule mod_alias.c>
Alias /robots.txt /home/[username]/sites/domain.com/foobar/media/robots.txt
Alias /site_media /home/[username]/sites/domain.com/foobar/media
Alias /admin_media /home/[username]/sites/domain.com/django/contrib/admin/media
</IfModule>
<IfModule mod_wsgi.c>
# See the link below for an introduction about this mod_wsgi config.
# http://groups.google.com/group/modwsgi/browse_thread/thread/60cb0ec3041ac1bc/2c547b701c4d74aa
WSGIScriptAlias / /home/[username]/public_html/something.wsgi
WSGIDaemonProcess [username] processes=7 threads=1 display-name=%{GROUP}
WSGIProcessGroup [username]
WSGIApplicationGroup %{GLOBAL}
</IfModule>
# This fixes the broken ErrorDocument directive we inherit that breaks auth
# if we use a WSGI app.
ErrorDocument 401 "Authentication Error"
ErrorDocument 403 "Forbidden"
Now tell main apache conf to start including this vhost definition:
Code:
/scripts/verify_vhost_includes
/scripts/ensure_vhost_includes --user=[username]
User should now be good to go, and domain.com should be serving a Django site. From here on out they’ll be able to restart their django instance with:
Code:
touch ~/public_html/something.wsgi