Setting up Django on Ubuntu 12.04 with virtualenv and mod_wsgi


Setting up Django on Ubuntu with Apache and mod_wsgi and virtualenv

Published on by nick

Tags: ubuntu, mod_wsgi, virtualenv, apache

Thanks to Ayman Farhat for the starting points.

Since I wrote this article quite a while ago, I have deployed several Apache servers running mod_wsgi and Django since. While this article can probably get you going to run your own Django web site and application, it is missing some key ingredients. I know this because I frequently reference this article and Ayman's. To this effect, I have edited this post to reflect some new tips and tricks I have learned in the last couple years.

First thing you need is a server running Ubuntu (I've deployed this on 12.04, but I'm sure the process is very similar on 13.04/13.10). I created an account at Digital Ocean and then made myself a droplet with Ubuntu 12.04 64-bit. This VM is ready to go with Python 2.7 pre-installed.

I'm running as root on the VM so I will leave out sudo but keep in mind that if you aren't running as root, the sudo command will be required in some cases.

Start by updating the repository:

apt-get update

I use vim throughout, so make sure your editor is installed:

apt-get install vim

Then let's install PIP:

apt-get install python-pip python-dev build-essential

You may need to run with --fix-missing if the command doesn't work.

Let's update PIP:

pip install --upgrade pip

You will also need MySQL or another SQL database. Check Django's docs for databases. I'm using MySQL for this tutorial:

apt-get install mysql-server

Another great choice that includes a web UI for administration of MySQL databases is Bitnami's Lampstack.

If required, follow the prompts to set up your MySQL database. Later on, we will create a database and user, if required, for the Django project.

virtualenv is a tool for creating isolated Python environments. My experience with virtualenv is limited but you can read more about it here.

Then on top of that there is virtualenvwrapper, which can help us manage our virtual environments. When you install virtualenvwrapper, virtualenv is installed as a dependency.

Let's install it, then...

pip install virtualenvwrapper

NOTE: in my case, I had to run pip from the complete path: /usr/local/bin/pip, although this certainly is not required in all cases. When your virtual environment is set up correctly, and installed in the default location in your development directory (this should be in your /home/user path somewhere), it's only necessary to run pip. COnfirm it's in your path as well.

Next, let's set the location where to save these virtual environments (I like vim):

vim ~/.bash_profile

To make activating the virtual environment easier, you can run the bin/activate command with a shortcut. Set the following (depending where you set up your virtual environment. In this example, I chose /home/django):

export WORKON_HOME=/home/django/virtualenv
source /usr/local/bin/virtualenvwrapper.sh

Reload your bash_profile file:

source ~/.bash_profile

Now, let's create a virtual environment to work with:

mkvirtualenv /home/django/virtualenv/mysiteenv --no-site-packages

At this point you are ready to install Django or upload existing Django projects and then install Django. Let's run through this briefly.

First, switch to your virtual environment:

workon mysiteenv

To install Django with PIP:

pip install Django==1.5.1

To verify Django was installed, launch the interactive python shell and run these commands:

>>> import django
>>> print(django.get_version())
1.5.1

I should note here that sometimes you will have a Django project already started. In this case, hopefully you have a requirements.txt file already with all the dependencies for your project. If this is the case, you can easily install everything you need into your virtual environment by issuing the following command:

pip install -r requirements.txt

This will install all dependencies, including the version of Django specified.

If you haven't created a project or if you didn't bring one to the server, let's create one now. Create and change directory into where you want to store your projects. I chose /home/django_projects. Then, use Django to create the project files:

mkdir /home/django_projects
cd /home/django_projects
django-admin.py startproject mysite

Pretty much the first thing you want to do next is set up your database.

First, log in to MySQL and create a database:

mysql -u root -p******

At the MySQL command prompt:

CREATE DATABASE mysite;
SHOW DATABASE;

Depending on your setup, you probably want to create a user and credentials for accessing the database you created:

CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
GRANT ALL ON mysite.* TO 'user'@'localhost';

Then edit your project's settings.py file (from where you were):

vim mysite/mysite/settings.py

NOTE: Sometimes it's easier to cd into the base of the project and then work from there. The commands would be this instead:

cd /home/django_projects/mysite
vim mysite/settings.py

Edit the settings.py file with the database information we want:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # Using 'mysql' for this tutorial.
        'NAME': 'mysite',                     # Database name.
        'USER': 'root',                       # or 'user', described above
        'PASSWORD': '******',
        'HOST': '',                           # Empty for localhost.
        'PORT': '',                           # Empty string for default.
    }
}

Be sure to read the section notes on MySQL on the Django website. This gives information about installing the Python module for MySQL, MySQLdb.

Briefly, you need to run these commands (the order is important here for dependencies):

apt-get install python-mysqldb
apt-get install libmysqlclient-dev
pip install mysql-python

Note that I have encountered issues when setting up new virtual environments when I don't install python-mysqldb and libmysqlclient-dev before mysql-python. This has caught me a few times, so make sure this order is maintained.

Please note that this tutorial is based on Linux, but I know that some folks will end up here wanting details on how to make this work on Windows. Heck, I actually come back to this article myself from time to time for reminders. I also develop on Windows, so this is helpful for me too. Anyway, MySQLdb is easy to set up on Windows too:

easy_install mysql-python

For the INSTALLED_APPS to function in Django, you need database tables for them:

python manage.py syncdb

Now, let's install and configure Apache and mod_wsgi:

apt-get install apache2 apache2.2-common apache2-mpm-prefork apache2-utils libexpat1
apt-get install libapache2-mod-wsgi

This should automatically restart Apache but just to be sure, issue this command:

service apache2 restart

We need to now create a virtual host and set up WSGI. First, let's create the site in the Apache configuration:

Apache can be tricky to configure and each distribution can be set up differently by default. The first thing you want to do is investigate how your version was set up when you installed it. For example, Bitnami's Lampstacks use completely different file structure than the default version installed with Ubuntu's package manager. Depending on what file is the master Apache configuration, you may need to use different configuration files.

For instance, in my case, I'm using /etc/apache2/apache2.conf as main configuration, /etc/apache2/httpd.conf as user configuration and /etc/apache2/sites-enabled for virtual host configuration.

vim /etc/apache2/sites-enabled/mysite

The contents of this file should look like this:

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName mysite.com
    ServerAlias www.mysite.com
    WSGIScriptAlias / /home/django_projects/mysite/mysite/wsgi.py

    <Directory /home/django_projects/mysite/mysite>
        <Files wsgi.py>
            Allow from all
        </Files>

        Options FollowSymLinks
        AllowOverride None
    </Directory>

    Alias /static/ /var/www/mysite/static/
    <Location "/static/">
        Options -Indexes
    </Location >
</VirtualHost >

Then, the user defined configuration file:

vim /etc/apache2/http.conf

Should look something like this...

WSGIScriptAlias / /home/django_projects/mysite/mysite/wsgi.py
WSGIPythonPath /home/django_projects/mysite/mysite/
# you should add the virtual environment as well:
# /home/django_projects/virtualenv/mysiteenv/lib/python2.7/site-packages/

<Directory /home/django_projects/mysite/mysite>
    <Files wsgi.py>
        Order deny,allow
        Allow from all
    </Files>
</Directory>

There are different ways to set up the WSGI part. The Django docs are a good place to start. And, as Ayman Farhat describes, you can create an index.wsgi and place this in the sites-available file for your site. In this case, I think going with the Django method is best, using the file referred to in the Virtual Host setup above:

vim /home/django_projects/mysite/mysite/wsgi.py

In it, add these lines (Django sets some default values, so consider this carefully):

import os
import sys
import site

# Add the site-packages of the chosen virtualenv to work with
site.addsitedir('~/.virtualenvs/mysiteenv/local/lib/python2.7/site-packages')

# Add the app's directory to the PYTHONPATH
sys.path.append('/home/django_projects/mysite')
sys.path.append('/home/django_projects/mysite/mysite')

os.environ['DJANGO_SETTINGS_MODULE'] = 'mysite.settings'

import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Let's then set where static files go for Django:

mkdir /var/www/mysite/static
vim /home/django_projects/mysite/mysite/settings.py

Make sure these lines are set:

STATIC_ROOT = '/var/www/mysite/static/'
STATIC_URL = '/static/'

Note that at this point, it might be necessary to edit permissions on your /var/www/mysite folder so static files can be written. To do this, you can edit permissions or change group access for Apache:

sudo chown root:www-data -R /var/www/mysite

Next, we need to tell Django to collect the static files for use on the site:

python manage.py collectstatic --noinput

Restart Apache again and you should be good to go:

service apache2 restart

Comments

Comments powered by Disqus

 Blog Search

  Popular Tags

django, ubuntu, mod_wsgi, apache, authentication, python, tls, linux, forms, ssl, virtualenv, dell, uwsgi, bash, nginx, raid, customer-service, centurylink, ux, software-companies, rais, form, centos, password, certificates, tinymce, mdadm, dual-boot, file-server, virtualhost, gluster, IT, blog, get, networking, piplight, distributed-file-system, big companies, bitnami, cygwin, windows, samba, scripting, pygments, post, programming-language, ui, lampstack, outsourcing, isp, security, usabillity, provision, php, shared-hosting, netflix, git, flatpages, syntax-highlighting, virtualbox, hg, redirect, usability, prg, acls, change-password, complex, view tags...

 Questions/Comments?

Drop me a line... [email protected]
Follow me on Twitter... @nicorellius
Share on Facebook...