Deploy with Fabric to Webfaction

For the past few years I’ve been deploying my Django projects to Webfaction with Fabric. Fabric is an amazing tool very similar to Capistrano for Rails that allows you to run a series of shell commands in sequence. While this is going to be a simple example of Fabric usage, it shows how it can save time.

Let’s look at a typical Django project that you’ve been developing and its now live in production and you make some changes to your stylesheet. Typically you would now commit your changes using your favorite version control system. You would then log into the production server via ssh. Switch to the production directory. Run a git pull or svn up or whatever. And you would still need to run another command to collect the static files. And possibly restart the server if needed to pull in any settings or other changes. If you’re counting at home that is at least 6 commands just to update a production site. Who does that?

Instead we’re going to automate all of that with Fabric. First, switch to your development environment and install fabric.

pip install fabric

Now in your main project directory add a file named fabfile.py and add the following. Note that this fabfile is built for use with Webfaction but you could easily adapt it for use elsewhere.

from fabric.api import *

prod_server = 'accountname@accountname.webfactional.com'

def prod():
    env.hosts = [prod_server]
    env.remote_app_dir = '~/webapps/django/appname'
    env.remote_apache_dir = '~/webapps/django/apache2'

def commit():
    message = raw_input("Enter a git commit message:  ")
    local("git add -A && git commit -m \"%s\" % message)
    local("git push origin master")
    print "Changes have been pushed to remote repository..."

def collectstatic():
    require('hosts', provided_by=[prod])
    run("cd %s; python2.7 manage.py collectstatic --noinput" % env.remote_app_dir)


def restart():

    "Restart apache on the server."
    require('hosts', provided_by=[prod])
    require('remote_apache_dir', provided_by=[prod])
    run("%s/bin/restart;" % (env.remote_apache_dir))

def deploy():
    require('hosts', provided_by=[prod])
    require('remote_app_dir', provided_by=[prod])

    # First lets commit changes to bitbucket
    commit()

    # Now lets pull the changes to the server
    run("cd %s; git pull" % env.remote_app_dir)

    # And lastly update static media files
    collectstatic()

Save that, changing the server and account information of course and now we can deploy a site in a single command. One thing to note is the way this is setup fabric wants to handle making a commit to git (if you’re not using git you’ll need to adjust that part) first, so if there is nothing to commit it will fail. Also, this assumes your project is already set up with a remote git server like Bitbucket or Github.

To deploy your site now simply go to your development directory and

fab prod deploy

Enter a git commit message and watch the magic. If you have ssh keys setup you won’t have to enter a remote password every time as well. It will save you at least 10 seconds per day!

You can also easily restart the server by running:

fab prod restart
comments powered by Disqus