Deploying a Flask Project on WebFaction

Warning! This blog post is pretty old, and some of the steps might be different now. Follow at your own risk!

I've been thoroughly enjoying my exodus from PHP to Python. My first self-assignment was to develop a Flask project, which came easily enough. The more difficult step was deploying it to WebFaction. The below guide are the steps I took to go from 0 - site, hopefully they'll come in useful.

Assumptions

This guide assumes a few things:

  • You have a WebFaction account (you can get one here)

  • Your Flask project is using a Virtual Environment (it should be)

  • You've already set up your Virtual Environment on your Webfaction server

  • You have SSH access to your WebFaction server (if not, get that going here)

Okay, let's get going.

Step 1: Add your site to Your WebFaction Account

I'm going to assume you're familiar with your WebFaction console, so this should be pretty simple:

  1. Log into your WF Console

  2. Go to your "Websites" tab, click the "Add New Website" button

  3. Enter the website name and domains as needed for your project

  4. Under the Contents section, choose Add an Application > Create a New Application

    1. Set App Category to "mod_wsgi"

    2. App Type should be the most recent version of mod_wsgi that supports your Python version. Make sure that your Python version matches with your mod_wsgi choice (I used "mod_wsgi 3.4/Python 2.7" for this guide).

    3. Click the Save button to add that application

  5. Click the Save button to save your website

Now your WebFaction account should have a new domain, website, and mod_wsgi application.

Step 2: SSH into your new application

First, you'll need to SSH into your webfaction account. Once you're there, cd into your newly created application:

cd ~/webapps/application_name

In this directory, you'll see two folders:

- apache2/      # This contains all of your Apache config and action files
- htdocs/       # This is the folder Apache looks into (by default) to launch your project

All following instructions will assume you're still in this directory.

Step 3: Edit apache2/conf/httpd.conf

Using your favorite command line editor, open up the apache2/conf/httpd.conf file:

vim apache2/conf/httpd.conf

Load Alias module

You'll see a section where Apache Modules are being loaded. I had to manually add the Alias module to the bottom of the list (shown below).

LoadModule dir_module        modules/mod_dir.so
LoadModule env_module        modules/mod_env.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule mime_module       modules/mod_mime.so
LoadModule rewrite_module    modules/mod_rewrite.so
LoadModule setenvif_module   modules/mod_setenvif.so
LoadModule wsgi_module       modules/mod_wsgi.so
LoadModule alias_module      modules/mod_alias.so       # <-- What I added

Your version of mod_wsgi might not need to add this, but mine did.

Modify <Directory>

Add the following parameters to your <Directory> section:

<Directory /home/your_username/webapps/application_name/htdocs>
    AddHandler wsgi-script .py  
    RewriteEngine On             # <-- What I added
    RewriteBase /               # <-- What I added
    WSGIScriptReloading On      # <-- What I added
</Directory>

Now for the final edit of the config file.

Add Aliases

Finally, at the end of the file, add the following lines:

# This will ensure that www.yourdomain.com/static points to your flask static directory
Alias /static/ /home/your_username/webapps/application_name/app/main/static/

# This points to the file that launches our site, which we'll get to next
Alias / /home/your_username/webapps/application_name/htdocs/index.py/

Now to upload our files.

Step 4: Upload your Flask project

My prefered Flask structure matches the following format:

- My_Flask_Project
    - fabfile.py
    - project/
        - config.py
        - libs/
        - main/
            - static/
            - templates/
            - __init__.py
            - views.py
            - models.my

I upload my project/ folder to my application directory, and rename it to "app" - I don't really know why I feel the need to rename it, in retrospect:

scp -r ~/flask_files/project webfaction:~/webapps/application_name/app

Now, my ~/webapps/application_name directory list looks like the following:

- apache2/
- app/
    - config.py
    - libs/
    - main/
        - static/
        - templates/
        - __init__.py
        - views.py
        - models.my
- htdocs/

Next, we'll get our project's init file in order.

Step 5: Make sure your init.py file is right

Ensure that, whatever your structure, your project's __init__.py file is launching your Flask application. In the struct I provided above, this is what my file at app/main/__init__.py looks like:

from flask import Flask

# Setting up the App
app = Flask(__name__)
app.config.from_object('config')

# Importing the views for the rest of our site
from main import views

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

This will work nicely with our htdocs/index.py file, which we'll set up next.

Step 6: Modify the htdocs/index.py file

WebFaction should have created this file. In it are a few scripts, but you can completely remove those. Here is what the htdocs/index.py file should contain:

import sys

# Active your Virtual Environment, which I'm assuming you've already setup
activate_this='/home/username/.virtualenvs/venv_name/bin/activate_this.py'
execfile(activate_this, dict(__file__=activate_this))

# Appending our Flask project files
sys.path.append('/home/username/webapps/application_name/app')

# Launching our app
from main import app as application

And finally,

Step 7: Restart Apache

The last step will be to restart apache, like so:

apache2/bin/restart Note: you call this script directly and do not need to source it

Troubleshooting

If you're having trouble, take a look at your logs in the ~/logs/users/ directory. Often my issues come from my Virtual Envs being misaligned.

Hope this guide helps. Please let me know if I missed an important step, or I'm way off on the process