Sunday, January 20, 2013

The easy way to serve static content in Django with apache2

Struggling with how to serve static content (e.g., images referenced from your site template files, like logos) on both the django development server and apache2, without changing code?

A simple approach that does not involve changs to your django project is to add the following to /etc/apache2/apache2.conf:

Alias /static/ /foo/bar/djangoproject/djangoapplication/static/

This would correspond to the following settings in (located in /foo/bar/djangoproject):

STATIC_URL = '/static/'

Doing this allows you to run on the dev server (e.g., python runserver) and when deployed on an apache2 host without any changes to the project.

Backing up an EC2 instance with rsync.

To back up an EC2 instance, you can use rsync.

My strategy is pretty simple. I want to backup to a server in my home. I don't want to expose my server at home via dynamic DNS, so the only option would be to start the backup locally and pull from the EC2 instance.

Fortunately, this is very easy to do. Here are the steps:
  • Figure out what local server you want to do your backups to. In my home, the server is a fairly old (e.g., 2005 model) Mac Mini. To that Mac Mini, I've attached a 2TB drive for holding backups. Let's call that system "A". We'll call the EC2 instance hostname "B".
  • Create a directory on A to hold the backup. I give the name of the directory the same name as the ec2 instance, makes it easy to know which backup is which. I put it on the 2TB drive since I use that drive for backups. Thus, I issue 'mkdir /Volumes/My2TBDrive/B' to create the directory where the backup will be maintained.
  • Copy your private key file (.pem) over to the ~/.ssh directory of machine A, if not already there. This is the key file you generated using the EC2 console before creating the EC2 instance, and it is the same one you use when logging in. Before you copy the keyfile to any .ssh directory, of course, make sure it has a unique name so you don't blow away a key file already there with the same name. Run 'chmod 400 filename' on this file to give it suitable permissions. Let's call the file keyfile.pem.
  • Make sure rsync is installed on both the ec2 instance and machine A.
To do the backup, log onto machine A, issue a command like the following (assuming your login on A is yourusernameA and on B is yourusernameB, you certainly will need to change these values):

$ sudo rsync -avz -e 'ssh -i /Users/yourusernameA/.ssh/keyfile.pem' yourusernameB@B:/  /Volumes/My2TBDrive/B

(Note, since I am using MacOS X, my home directory is under /Users, and mounted drives are found under /Volumes. On Linux, this would be /home/yourusernameA and /mnt/My2TBDrive/B, respectively. Windows users, sorry, I don't discuss Windows in this post).

The 'ssh -i /Users/yourusernameA/.ssh/keyfile.pem' gives you password-less ssh authentication (and associated encryption of the bits on the wire as they are copied from B to A). This is essential if you want to do the backup from a cron job without having to type passwords (and the keyfile is, as best I can tell, required anyway for getting a login to your EC2 instance).

The yourusernameB@B:/ determines what gets backed up. Here, I am backing up from /. The /Volumes/My2TBDrive/B is the location on machine A where the resulting backup will be located.

Making snapshots of EC2 instances

Following is a link that seems to provide solid advice, and is clearly written, but only regarding backups to snapshots:

This method is a bit risky if Amazon has a complete failure, so additionally, would want to use a method such as rsync to do traditional OS backups to an offsite machine. Such as rsync (which I will cover in a subsequent post).

I only use snapshots to record major events in the system lifetime, like initial configuration. Which is good because you don't want a lot of snapshots, anyway. OS backups using rsync are done twice daily from cron.

To restore a failed system, I would create a new instance from a snapshot, then restore from my latest rsync backup.

EC2 Django MySQL phpmyadmin

Here are some notes for getting Django/MySQL/phpmyadmin stack up and running on an EC2 instance. Instructions here are for Django 1.3, and Ubuntu 12.04 LTS.

Django is an excellent framework for building database backed websites, sites are largely built using python, and it takes care of a lot of stuff you'd otherwise have to write by hand (as I did in php years ago). I don't know about you, I'd rather use someone else's user authentication and session management packages: it was ok rolling my own in php (I learned a lot), but I am done with that. Plus, python is without question a much better language than php (all due credit to the php folks). Lots of other advantages as well (rich python libraries, django and otherwise; database tables and forms described as classes).

mysql is an excellent database, of course.

And phpmyadmin is an excellent  tool for configuring and managing MySQL databases.

So, it is natural to want to use them together. Django supports MySQL of course. But django wants to own / on apache, and to get phpmyadmin, you would need to set up virtual hosts. Maybe not a big deal (I did it once before), but I found an easier way. Let django own Apache, fine. Just run phpmyadmin on a different web server (lighttpd) that's listening on port 81. If you search the web a bit, you'll see that it's pretty common to do this. And you can put all your non-Django served content off of lighttpd (docs, etc..), and get some isolation between the two as well.

First, get Django up:
  • Make sure when you create the EC2 instance that you create a security group that enables TCP port 81. This allows you to run two web servers - apache for Django, and lighttpd for phpmyadmin. 
  • Install apache2, django, mysql packages using apt-get. Plenty of resources on the web describe this step. You will be prompted for an admin password when installing MySQL. Remember it, as this is your login to myphpadmin
  • Create an empty django project (plenty of docs on that too).
  • Hack on the settings file to enable MySQL for the django project.
  • Visit and follow instructions.
  • Make sure you can see the default Django page on port 80.
 Next, set up lighttpd and phpmyadmin:
  • Install lighttpd package
  • Install php5 package
    • apt-get install php5-fpm php5
  • Hack on /etc/lighttpd/lighttpd.conf 
  • Install phpmyadmin package
  • system mysql start
  • system lighttpd force-restart
  • Visit http://server:81/phpmymyadmin - it should be running
  • Login using the user and password configured when you installed the MySQL package.