26 January 2013
From time to time, I see people in the #django IRC channel on Freenode asking for tutorials on how to deploy Django in production, so here is my tutorial on how to do that.
First, make sure all your big dependencies are installed. For example, my list of big dependencies contains:
python python-dev (headers required to build other packages) pip virtualenv virtualenvwrapper (really useful, although not required) postgresql postgresql-server-dev nginx libjpeg8-dev zlib1g-dev libfreetype6-dev liblcms1-dev rabbitmq (for celery) memcached
I'm using Ubuntu, btw, so these are the name of the packages specific to this platform. There are a few more things I want to say about this list. First, postgresql-server-dev is required to be able to install psycopg2, the Python drivers for PostgreSQL. If you're using MySQL, you'll need the equivalent package, most likely. Second, the four libs under nginx are required to enable support for several features in PIL or Pillow. You most likely need these when working with Django and ImageField model fields. I'm not going into detail here about how to install everything, but keep in mind that for virtualenvwrapper for example, you need to make some extra steps which are covered by the docs.
After you've installed everything, you should create a new user for your project with the same name as your project. I'm talking about an OS user here, the one that you would create with adduser on Ubuntu. I prefer this approach over having a webapps directory somewhere, because it offers more isolation. Make sure you also add your user to the same group as the user running your web server.
Let's say I'm deploying a web app called tasker. I create a user named tasker and add it to the group of the web server user, www-data:
sudo adduser tasker ... fill in password and other info sudo adduser tasker www-data
Then I clone the application in the user's home, create a virtualenv and install all project requirements:
hg clone path/to/repo tasker mkvirtualenv tasker pip install -r tasker/requirements/production.pip
Next, I create a database called tasker and a database user called tasker as well. I put these credentials in my local settings file and then I sync the database to create the tables and run the migrations, if any, by running ./manage.py syncdb --migrate.
Then I symlink my configuration files for postgresql, nginx, memcached and rabbitmq in place of the default ones and restart the applications so that they reload the new configs. Finally, I just start supervisord which handles uwsgi and celery.
As always, make sure that the file permissions are right, so the server can access the files. For examples of configuration files, have a look at django-startproject, which is my Django project template. Let me know if something's not clear, so I can explain it better.