Monday, January 14, 2008

How to simulate webfaction's apache/django setup in ubuntu.

I was recently interested in profiling my personal website which is a django application. Unfortunately, I use a shared hosting account on Webfaction. I haven't asked but I'm sure they don't appreciate having their servers hammered by an ab or siege process. Not to mention that it would use up your own bandwidth unecessarily. Also I wanted to be able to quickly and easily see the affects that various tweaks might have on performance and memory usage of my apache processes.

So I set about trying to replicate the basic apache setup that they provide. Typically, Webfaction provides the end-user with their own apache instance and config which runs the long running process, and then Webfaction proxies to this application for requests that come in on this domain. I don't have access to their proxy-server configuration so I haven't yet bothered setting one up, and for the purposes of this post will assume that profiling the application using just the long-running process apache to which the user has a configuration is good enough.

First, I set about installing mod_python, which (as always with Debian based systems) was dead simple:
sudo apt-get install libapache2-mod-python

Then I grabbed a copy of my current config:
ServerRoot "/home2/lakin/webapps/lakin_weckers_net/apache2"
LoadModule python_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_python.so
LoadModule cgi_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_cgi.so
LoadModule log_config_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_log_config.so
LoadModule mime_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_mime.so
LoadModule env_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_env.so
LoadModule dir_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_dir.so
LoadModule autoindex_module /home2/lakin/webapps/lakin_weckers_net/apache2/modules/mod_autoindex.so
Listen 3077
User lakin
Group lakin
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog /home2/lakin/webapps/lakin_weckers_net/apache2/logs/access.log combined
Errorlog /home2/lakin/webapps/lakin_weckers_net/apache2/logs/error.log
ServerLimit 2
DocumentRoot /home2/lakin/webapps/lakin_weckers_net/lcw_trunk/htdocs
<location>
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE lcw.settings
PythonPath "['/home2/lakin/webapps/lakin_weckers_net/lcw_trunk', '/home2/lakin/webapps/lakin_weckers_net/swim_trunk', '/home2/lakin/webapps/lakin_weckers_net/django_trunk'] + sys.path"
PythonDebug On
</location>
<locationmatch>
SetHandler None
AllowOverride None
</locationmatch>

The ServerRoot for apache2 in ubuntu is "/etc/apache2". All of the modules can be loaded using two lines. The following example is for the mime_module. I would suggest you follow this method when there is an appropriate .load and .conf file in /etc/apache2/mods-available/. Although updating the module's .so location is possible some (like the mime) module require some extra configuration:
Include /etc/apache2/mods-available/mime.load
Include /etc/apache2/mods-available/mime.conf

Others, like the log_config_module are built-in. Which means our apache setup won't be exactly like webfaction but it'll be close. Also, for those modules which don't have an entry in the mods-available directory, you'll need to update their path. The log directory locations need to be updated as do the user and group that the server runs as and you'll need to add a line which specifies where to put the PIDFile. To finish, you'll need to modify the PythonPath line to update this configuration to where your code lives. My final result was:

ServerRoot "/etc/apache2"
LoadModule python_module /usr/lib/apache2/modules/mod_python.so
Include /etc/apache2/mods-available/cgi.load
Include /etc/apache2/mods-available/mime.load
Include /etc/apache2/mods-available/mime.conf
Include /etc/apache2/mods-available/env.load
Include /etc/apache2/mods-available/dir.load
Include /etc/apache2/mods-available/dir.conf
Include /etc/apache2/mods-available/autoindex.load
Include /etc/apache2/mods-available/autoindex.conf

Listen 8080
User lakin
Group lakin
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog /home/lakin/Desktop/lcw_test/logs/access.log combined
Errorlog /home/lakin/Desktop/lcw_test/logs/error.log
PidFile /home/lakin/Desktop/lcw_test/apache2.pid

ServerLimit 2

DocumentRoot /home/lakin/Projects/lakin.weckers.net/trunk/htdocs
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE lcw.settings
PythonPath "['/home/lakin/Projects/lakin.weckers.net/trunk', '/home/lakin/Projects/swim/trunk', '/home/lakin/Projects/django/trunk'] + sys.path"
PythonDebug On
</Location>

<LocationMatch "\.(css|js|jpg|gif|png|ico)$">
SetHandler None
</LocationMatch>

The syntax of the config file can be checked with a single command:
apache2 -t -f webfaction_django_lcw.conf


And the server can be started and stopped easily as well using:

apache2 -f webfaction_django_lcw.conf -k start
apache2 -f webfaction_django_lcw.conf -k stop

No comments: