Tuxcoder Blog

A place for random code postings, tips, and how-tos for Linux.


Hosting Python WSGI Apps Using Dreamhost

written on Thursday, September 8, 2011

This article is a setup guide for creating a working Python WSGI container inside of the standard Dreamhost environment. This should be very helpful to anyone trying to build a Python webapp using one of the many WSGI frameworks.

First thing to know, is that Dreamhost is not going to support this config for you, and they don't make any guarantee that it work work in the long term. Therefore, if you want a bullet proof system, your best bet is to get a virtual server on which you can fully control the OS stack.

In my case, I experimented with the Flask framework, which is considered pretty basic. This is not a bad thing, since it is easy to get something working quickly, and has some great documentation.

Dreamhost Documentation

Dreamhost has setup a Passenger WSGI wiki page that describes the overall process. You should read over this to get some additional background on how all the various pieces fit together. After you read/skim that, come back here.

Virtualenv Setup (Optional)

Before you begin, make sure to log into your Dreamhost SSH account.

ssh user@machine.dreamhost.com

Your first step should be to create a Python virtualenv environment. This creates a local Python environment that will allow to install and upgrade modules that are not currently installed on the hosted machine.

virtualenv ~/env
. ~/env/bin/activate    # activate the new 'env' environment
pip install virtualenv --upgrade

Note

After this step, every time you need to use or modify the environment, you have to source the . ~/env/bin/active script to configure your shell.

Domain Setup

You'll need a registered domain name to run this configuration on. I don't recommend testing this out on a production domain, however it should be OK to create a new sub-domain for testing.

Using the web interface, go to the Domains → Manage Domains. From the Web Hosting column, select Edit.

/static/posts/008.dreamhost/panel.png

The image above shows the necessary changes:

  • Append /public to the default Web Directory. This is where static files can be served from.
  • Enable Passenger, by checking the box.

Don't forget to click Save when you are finished.

Python WSGI Setup

Now the final step is to add a script into your domain root directory. These will be executed on each HTTP request by the server. This is where we will delegate our Python app to handle the request and return the necessary response data.

The name of the script must be passenger_wsgi.py. It does not have to be executable. Depending on your WSGI framework, you might need to update a few things, as mine is currently targeted at the Flask framework.

Note

The job of this script is to import and create a Python variable to your WSGI app named application.

passenger_wsgi.py

import sys, os

DEBUG   = True
ROOT    = os.path.dirname(os.path.abspath(__file__))
INTERP  = '/home/USERNAME/env/bin/python'  # fix 'USERNAME'

sys.path.insert(1,ROOT)
if sys.executable != INTERP:
   os.execl(INTERP, INTERP, *sys.argv)

from myapp import app as application

if DEBUG:
   application.debug=True
   from werkzeug_debugger_appengine import get_debugged_app
   application = get_debugged_app(application)

Let me go over a few of the details:

  • The first main code block updates your sys.path define. This allows the execution environment make use of any virtualenv packages you have installed.

  • The next block pulls in your WSGI application. In this case, it's called myapp and sitting in the domain root directory. As long as its somewhere in your Python path, it should be fine. Notice that it imports the app as application.

  • The final block is a trick for people using Flask and/or Werkzeug. This provides a work-around for the runtime debugger on Dreamhost. See the next section for additional setup.

    Warning

    Do not run a production system in debug mode. It very likely will not be secure.

Important

The WSGI application container is not restarted for every request. When you make changes to your app, you should reset the session by running touch tmp/restart.txt. This will work in most cases, but if not, the other option is to run pkill python.

Enabling the Werkzeug Debugger

If you plan to do any active development on the Dreamhost side, this step will simplify your efforts. Werkzeug comes with a really nice debugging engine, but it does not work with the Dreamhost configuration by default.

For example, if you have a simple Python coding error in your app, it will result in the following:

/static/posts/008.dreamhost/werkzeug_default.png

Default Dreamhost WSGI HTTP response on Python error.

In this mode, you're out of luck. The only option is to startup a local server where you can go back and test the app. In some cases it might be a big effort just to replicate the bug.

With the Werkzeug Debugger enabled and patched, you'll get a much nicer output:

/static/posts/008.dreamhost/werkzeug_patch.png

Patched Dreamhost WSGI HTTP response on Python error.

The patched version will not give you any interactive UI, but you get a pretty nice stack trace, file name and line number where the error occurred.

There are few steps for enabling this:

  1. Download and install the patch source code from github.

    mkdir ~/src
    cd ~/src
    git clone https://github.com/nshah/werkzeug-debugger-appengine.git
    cd werkzeug-debugger-appengine
    python setup.py install
    
  2. If you followed all the previous steps, thats it. If not, you have to go back and edit your passenger_wsgi.py script to enable the patch. At the end of the file, modify the application reference:

    application.debug=True
    from werkzeug_debugger_appengine import get_debugged_app
    application = get_debugged_app(application)
    

This entry was tagged dreamhost, flask, python, webapp, werkzeug and wsgi



© Copyright Patrick C. McGinty 2011. All Rights Reserved.

powered by rstblog