Deploy a Python web application on Dreamhost with pyenv

28 May 2015

You want to deploy a Python web application on your Dreamhost shared hosting account. For greater control you will need to manage the version of the python executable and packages required for your app to run and, for this, pyenv is the right tool.

--- install pyenv and create your own temporary folder
you@dhs ~$ curl -L https://raw.githubusercontent.com/yyuu/pyenv-installer/master/bin/pyenv-installer | bash
you@dhs ~$ mkdir ~/.tmp

As instructed by the pyenv installation, and to use your own temporary folder, add the following to your .bash_profile.

export TMPDIR="$HOME/.tmp"
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

Start a new shell session for changes to take effect. Also note that, if you plan to run some scripts from your app as cron jobs, you’ll need to arrange something similar to be set up before actually running any Python scripts.

It’s probably a good idea to keep your app on its own git repository, so let’s do that.

--- create a new repository
you@dhs ~$ mkdir -p ~/repositories/my_app.git
you@dhs ~$ cd ~/repositories/my_app.git
you@dhs ~/repositories/my_app.git$ git init --bare
you@dhs ~/repositories/my_app.git$ cd ~
--- clone into the newly created repository
you@dhs ~$ git clone $HOME/repositories/my_app.git
you@dhs ~$ cd ~/my_app
you@dhs ~/my_app$ mkdir ~/temp
you@dhs ~/my_app$ touch temp/restart.txt # will be useful later

Now set up an environment for your app as follows (see pyenv-virtualenv for full docs).

you@dhs ~/my_app$ pyenv install 2.7.10 # get a recent python 2.7 version
you@dhs ~/my_app$ pyenv virtualenv 2.7.10 my_app_env # create a new environment
you@dhs ~/my_app$ pyenv local my_app_env # associate with the current directory

Keep a ~/my_app/requirements.txt file with your required python packages, e.g.

certifi
flask
requests
# ... anything else you might need

Install the required packages.

you@dhs ~/my_app$ pip install -r requirements.txt

Let’s get coding! For exmaple using Flask create a simple hello world app and save it into ~/my_app/my_app.py. If you are new to Flask, it’s probably a good idea to read and follow the Flask tutorial.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import flask

DEBUG = True

app = flask.Flask(__name__)
app.config.from_object(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

For your app to be picked up and served by Dreamhost, you also need to create a ~/my_app/passenger_wsgi.py file.

import sys, os
INTERP = os.path.join(os.environ['HOME'], '.pyenv', 'versions',
                      'my_app','bin', 'python')
if sys.executable != INTERP:
    os.execl(INTERP, INTERP, *sys.argv)
from my_app import app as application

# Comment out the next two lines to disable debugging when your app is ready
from werkzeug.debug import DebuggedApplication
application = DebuggedApplication(application, evalex=True)

Then login to your Dreamhost Panel, select Domains → Manage Domains, and add or edit a (sub-)domain for your app. Configure as desired, and make sure to set the following options:

Option Value
Web directory: /home/username/my_app/public
Passenger (Ruby/NodeJS/Python apps only): (checked)

Click on “Change settings” and wait for a few minutes. Your app will soon be accessible through http://your.domain.com/. Dreamhost will also create the public directory in your app where you can host any static content.

To restart the application after making any changes just type:

you@dhs ~/my_app$ touch temp/restart.txt

Don’t forget to git add, commit, and push all the relevant files of your new app. Clone the repository to develop and debug locally.

you@local ~$ git clone ssh://user@your.domain.com/~/repositories/my_app.git
you@local ~$ cd my_app
you@local ~/my_app$ ./my_app
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat