All Unkept
Posted in: Web development, Django  —  December 23, 2011 at 12:05 PM

Starter fabfile and scripts for a Django project on Webfaction

by Luke Plant

Note: I now recommend using gunicorn for deployment, various things about this need changing for that setup


With the new 256 Mb limit for WebFaction Shared accounts, at a squeeze you could now host up to 10 Django apps on a single account without upgrades, for a very low price.

This was a game changer for me, and I realised I need to be able to start a new Django project quickly, including setup on WebFaction, either to be able to host a small client website for them, or to generate a demo.

There are a few parts required, one of which is a fabfile for fabric deployment. Since this is often a sticking point for other people, I created one that should be generic enough for most Django apps that run on shared hosting:

https://bitbucket.org/spookylukey/django-fabfile-starter/src/f4c87b0b2676911de2fa4a9784ca705f708b3bf1/

[Update: have a look at the most recent version of this file for an improved approach that uses gunicorn instead of Apache]

It requires some customisation, and is fairly simplistic, but should be a good starting point for more complex setups.

For quick project setup, there are other things you need:

  • Use of virtualenvwrapper
  • Use of django-admin.py startproject to get things going. Note some recent changes you should be aware of.
  • Scripts to create sites on WebFaction, which is simple with WebFaction API. Something like this:
#!/usr/bin/env python
import sys
import xmlrpclib
import random
import string


def main(domain, shortname):
    server = xmlrpclib.ServerProxy('https://api.webfaction.com/', verbose=0)
    session_id, account = server.login('MYUSERNAME', 'MYPASSWORD')

    print("Creating apps on webfaction")
    server.create_app(session_id, shortname + "_django", "djangotrunk_mw33_27", False, "")
    server.create_app(session_id, shortname + "_static", "static_only", False, "")
    server.create_app(session_id, shortname + "_usermedia", "static_only", False, "")

    print("Creating database on webfaction")
    l = list(string.letters + string.digits)
    random.shuffle(l)
    password = ''.join(l[0:16])
    db_name = "MYUSERNAME_%s" % shortname
    print("Remote database: %s" % db_name)
    print("Password: %s" % password)
    server.create_db(session_id, db_name, "postgresql", password)

    print("Creating domain on webfaction")
    server.create_domain(session_id, domain)
    server.create_domain(session_id, domain, 'www')

    print("Creating website entry on webfaction")
    server.create_website(session_id,
                          shortname,
                          'MY.IP.ADD.RESS',
                          False,
                          [domain, 'www.' + domain],
                          (shortname + '_django', '/'),
                          (shortname + '_static', '/static'),
                          (shortname + '_usermedia', '/usermedia'))

if __name__ == '__main__':
    if len(sys.argv) != 3:
        print "Usage: create_webfaction_site.py $DOMAIN $SHORTNAME"
        sys.exit(1)
    main(sys.argv[1], sys.argv[2])
  • Scripts for setup of your local database. Mine looks like this:

    #!/bin/sh
    
    sudo -u postgres psql -U postgres -d template1 -c "CREATE DATABASE $1;"
    sudo -u postgres psql -U postgres -d template1 -c "CREATE USER $1 WITH PASSWORD 'foo';"
    sudo -u postgres psql -U postgres -d template1 -c "GRANT ALL ON DATABASE $1 TO $1;"
    # Need create DB privileges to run tests.
    sudo -u postgres psql -U postgres -d template1 -c "ALTER USER $1 CREATEDB;"
    
    echo "Local database: $1"
    echo "Password: foo"
    
  • A script to bind it all together. Mine takes just two arguments - a short name for the project and domain name. A lot is fairly specific to my environment, so I won't share it, but the sake of completeness, I'll list what it does:

    • runs mkvirtualenv and creates some directories for the project

    • runs django-admin.py startproject

    • copies in the fabfile above, and modifies some settings

    • creates a basic requirements.txt

    • runs the local database creation script

    • prints a reminder for some Django settings.py that would be hard to fix automatically, and anything else which is still to be done, which includes: * Fixing the WebFaction Apache conf to point to myproject/wsgi.py * Fixing the WebFaction Apache start script to include the virtualenv generated by the fabfile

      Some of these things could be done automatically in the future

Having this written allows me to be massively more efficient with very small sites, so it is now feasible to use something like django-cms for a 5 page site, because the setup costs are so low.

Comments §

blog comments powered by Disqus