Setting Up Bottle with Apache mod_wsgi and virtualenv on Debian

Deploying bottle on apache took me some time today which I hope to not repeat. Due to some of my mistakes and errors, I tripped myself up in a mess. I screwed up a new vhost entry on apache because it defaulted back to my default entry. It took me a while to realize I needed a ServerName entry in my new vhost file...

From there I copied some crazy configurations I found through google. They seemed geared towards some other distributions. At the end, I was able to slim my configuration down to several simple files that work.

Lets go over the system I am working on:

  1. debian squeeze - fresh install of 6.0.5
  2. apache - Apache/2.2.16 (Debian) This is the special apache setup
  3. bottle - latest one from github
  4. virtualenv - 1.4.9

First step is first... make sure you can get the default vhost entry operational. I know you want to skip that step, but don't skip it. Sometimes other things break. Make sure you can at least get that setup. Additionally, you should create a second vhost entry with a different ServerName.

The reason you found this article is because you have many projects you want to host on a server. You have different virtual environments for each python project with different libraries. Keeping these projects isolated is a great idea but serving them up isolated is better.

  1. Let's go into the /opt directory as root and create a directory for my user jarvis:

    root@palmtree:~$ cd /opt
    root@palmtree:/opt$ mkdir jarvis
    root@palmtree:/opt$ chown -R jarvis:jarvis jarvis
  2. Let's create the virtualenv in the /opt directory:

    jarvis@palmtree:/opt/jarvis$ virtualenv --no-site-packages test
    jarvis@palmtree:/opt/jarvis$ cd test
    jarvis@palmtree:/opt/jarvis/test$ source bin/activate
    jarvis@palmtree:/opt/jarvis/test$ mkdir src
    jarvis@palmtree:/opt/jarvis/test$ cd src
    jarvis@palmtree:/opt/jarvis/test/src$ touch
    jarvis@palmtree:/opt/jarvis/test/src$ touch dispatch.wsgi
  3. Create a file for bottle to run:

    from bottle import route, run, request
    @route('/', method='GET')
    def index1():
        return '<h1>HELLO</h1>'
    @route('/hello/:name', method='GET')
    def index(name='World'):
        return '<b>Hello %s!</b>' % name
  4. Create a dispatch.wsgi file for apache to run:

    import sys, os
    # ... build or import your bottle application here ...
    import bottle
    import test
    # Do NOT use with mod_wsgi
    application = bottle.default_app()
  5. Go to your apache sites-available directory and copy the default vhost into a new entry:

    root@palmtree:~# cd /etc/apache2/sites-available/
    root@palmtree:~# cp default test
  6. Grab your favorite editor and edit the new vhost entry called test:

    <VirtualHost *:80>
    WSGIDaemonProcess ptest display-name=%{GROUP}\
     threads=4 \
    WSGIProcessGroup ptest
    WSGIScriptAlias / /opt/jarvis/test/src/dispatch.wsgi
    Alias /robots.txt /opt/jarvis/test/src/apache_static/robots.txt
    Alias /favicon.ico /opt/jarvis/test/src/apache_static/favicon.ico
    <Directory /opt/jarvis/test/src>
    Order allow,deny
    Allow from all
    ErrorLog ${APACHE_LOG_DIR}/test_error.log
    # Possible values include: debug, info, notice, warn, error, crit,
    # alert, emerg.
    LogLevel warn
     CustomLog ${APACHE_LOG_DIR}/test_access.log combined
  7. Activate the conf file, and restart Apache:

    root@palmtree:~# a2ensite test
    root@palmtree:~# services apache resart

The key to getting this simple configuration to work is in step 6. The line with python-path needs the path to the bottle file and the site-packages directory for the virtualenv that was created. Hopefully this works for you!