Tag Archives: django

HOWTO: Deploy a fault tolerant Django app on AWS – Part 2: Moving static and media files to S3

In the last article, I discussed our attempt to remove points of failure in our infrastructure, and increase redundancy. We moved our single database instance running locally to RDS where fault tolerance is built-in through their multi-zone offering.

In this article, I’ll continue this journey by moving our Django static and media files from local file system to S3. Static files are files in the [app]/static folder where typically Javascript, CSS, static images and 3rd party Javascript libraries are stored. Media files that are user generated, through the use of FileField and ImageField in Django model, e.g. profile picture of a user, or a photo of an item. By default, when you created a Django application using the standard “django-admin.py startproject”, all the media files are stored in the [app]/media folder and static files in the [app]/static folders. The locations are controlled by the following parameters in settings.py:

# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/media/"

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash.
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"

# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"

# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'

So, why do we need to move these files out of the EC2 local file system? It’s a pre-requisite to spinning up multiple EC2 instances that host the Django application. Specifically, we can’t have media files sitting in two locations. For example, when a user updates his or her profile picture, the POST request goes to one server and hence the new image would be stored in that server’s local file system, which is bad because the other app server won’t have access to it (unless you setup some shared folder between the instances – which is what’s typically done before Jeff Bezos gave us S3). By moving the static and media files to S3, both servers will be using the same S3 end-points to store and retrieve these files. Another HUGE plus is that the web servers (apache or nginx) don’t have to handle these static file requests anymore, and the disk and network load on the web servers will be drastically reduced.

Enough talking. First thing’s first. We need to download and install django-storages and boto.

pip install django-storages boto

Now, create a S3 bucket. This part is easy. Log into AWS console, click over to S3 and click on Create Bucket. Give it a name. For this example, we’ll use “spotivate”. All our static and media files be accessed through http://spotivate.s3.amazonaws.com/static/... and http://spotivate.s3.amazonaws.com/media/... respectively.

Also, we need to get the AWS Key and Secret which boto needs to access S3. You can find that from your AWS Security Credentials page.

Now we have all the info to change Django settings. The instructions here are loosely based on various articles I’ve read, but Phil Gyford’s article has been most helpful. Following his instructions, I first created spotivate/s3utils.py with the following content:

from storages.backends.s3boto import S3BotoStorage

StaticS3BotoStorage = lambda: S3BotoStorage(location='static')
MediaS3BotoStorage = lambda: S3BotoStorage(location='media')

Then, in settings.py, I added storages as one of the INSTALLED_APPS and a bunch of other variables that tells Django where to put and read media and static files:



# s3 storage

DEFAULT_FILE_STORAGE = 'spotivate.s3utils.MediaS3BotoStorage' 
STATICFILES_STORAGE = 'spotivate.s3utils.StaticS3BotoStorage' 


S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME

Voila. We are almost done. To upload all the static files to S3, run the following command:

python manage.py collectstatic

This will copy all the files in your current static folder to S3. What about media files? We need to upload that at least once to S3. Why only once? Because after the settings above is deployed, users who update their profile pics will be posted to S3. I found a great python package call boto-rsync that does the job beautifully.

pip install boto_rsync
boto-rsync media s3://spotivate/media -a [AWS_ACCESS_KEY_ID] -s [AWS_SECRET_ACCESS_KEY]

Verify in AWS console that all static and media files have indeed been copied to S3. Deploy the server, and hit a page. You should see that all references to Javascript, CSS and media files all point to S3.

It actually didn’t turn out so easy for me the first time around. I found that many CSS are still served from local file system. After looking at the template, I realized that I had this in the template:

<link href="/static/web/bootstrap230/css/bootstrap.css" rel="stylesheet" type="text/css" charset="utf-8">
<link href="/static/web/jcarousel/css/style.css" rel="stylesheet" type="text/css" charset="utf-8">
<link href="/static/web/css/spotivate_new.css" rel="stylesheet" type="text/css" charset="utf-8">

I am not using the Django “staticfiles” functionality properly. I had effectively hard-coded the static path, when I should be using the static template tag instead. The above line should be changed to:

{% load staticfiles %}
<link href="{% static "web/bootstrap230/css/bootstrap.css" %}" rel="stylesheet" type="text/css" charset="utf-8">
<link href="{% static "web/jcarousel/css/style.css" %}" rel="stylesheet" type="text/css" charset="utf-8">
<link href="{% static "web/css/spotivate_new.css" %}" rel="stylesheet" type="text/css" charset="utf-8">

The server is now functioning properly, but we are not done yet. What if we need to modify Javascript? How do changes get copied to S3 during deployment? This doc provides good instructions on this topic.

Now, with the static and media files moved over the S3, and database moved over to RDS, I’ve effectively remove all state from app server. Now I can spin up another EC2 instance, drop my code there and hence spreading all the traffic to two servers. If one goes down, we are still in business! And did I mention that the page loads a lot faster too?

HOWTO: Deploy a fault tolerant Django app on AWS – Part 1: Migrate local MySQL to AWS RDS

For a while, Spotivate was running on a single EC2 instance. Everything was in it — MySQL, Django, static files, etc. Yes, we know this is a terrible setup. Single point of failure, bad performance, etc. Here comes the excuses. We had better things to do, like customer development, sales, design, product development, etc. We had no time for ops! Plus, our traffic wasn’t really that high especially in the beginning. Our CPU / IO load was low. And we knew we can fix things fairly easily. Then one day, our EC2 instance went down for half an hour. Ooops! Called AWS support. They had a disk failure. Our last snapshot was a day old. So our site was down this whole time.

We figured we had to do it right. And EC2 makes it super easy. Our goal:

  • Remove all single points of failure, thus making the system fully fault tolerant.
  • As a result, the response time should go up, especially when under load.

Here’s the plan:

In this article, I’ll talk about the steps we took to move our MySQL to RDS.

If you don’t know what RDS is, read more about it here. Basically it’s AWS’s version of database server. RDS comes loaded with features. Here’s summary of what’s relevant:

  • Easy to deploy via the Management Console or command line.
  • Automatic backup (you get to choose how many days and when).
  • Multi-availability zone deployment means AWS automatically creates a primary DB instance and synchronously replicates the data to a standby instance in a different Availability Zone, thereby removing this as a single point of failure.
  • Replication that allows you to create read-only replicas. This is especially valuable for Spotivate, since our personalized email server put a heavy load on the DB. By having this, the performance of our website won’t be affected while we send out our weekly emails.

Well, let’s get on with it.

Step 1: Goto your management console and select RDS

Launch Database Instance


Step 2: Find a database server that fits your bill. In our case, MySQL.

Select database type


Step 3: Here’s where you pick the MySQL version and the instance size.

RDS Step 3

Multi-AZ Deployment Select “Yes” which creates a standby instance in a different AZ. That’s the whole point of this article, right?
Allocated Storage Choose a storage size that’s appropriate. Go small, as you can easily upgrade later with minimal down time. Generally, estimate enough for 3 months down the road.
DB Instance Identifier This is just the prefix to the public DNS.
Master Username Your database user name, typically “root”
Master Password Your database root user password


Step 4: Here you specify the database name, port, etc.

You also get to create (or assign) a database security group for this database. This is a little different from the EC2 security group. For database security group, you assign which EC2 security group to use. And any EC2 instance that belongs to that EC2 security group has access to the database. By default, everything else is turned off including ping. For more info, visit here.

RDS Step 4


Step 5: Backup Settings

Here, you specify the backup retention period, and when to backup. Make sure your backup window and maintenance window don’t overlap.

RDS Step 5


Step 6: That’s it. Review and Launch.

RDS Step 6


Step 7: Test it out.

After the DB has been launched (takes several minutes – enough time for coffee), you can find the public DNS from the detail page. This machine is accessible externally and within EC2. However, the security group by default prohibits any external access to the database server. Only EC2 instances that belong to the security group have access. From my web server, I can use my typical “mysql” command to connect to the new RDS instance.

RDS Step 7


Step 8: Import.

Our database is fairly small, so we can just dump the database and pipe it to the new instance. Here’s a fun command that you can use (make sure you stop your web server first to avoid consistency issue).

mysqldump [your current db] | mysql --host=[rds host name] --user=root --password [root password]

That’s it! All you need to do now is change your Django settings to use the new database instance. Bring down your local MySQL and restart your Django server to see if everything is running properly. If so, change chkconfig to keep the local MySQL from restarting.

Next time, I’ll talk about the migration of our static files to S3.

HOWTO: Share a Nav Bar between Django and WordPress

At Spotivate, we used Django as our backend infrastructure. A few months ago, we wanted to put up a blog and WordPress was the obvious choice due to the amount of tools and plugins available. We also needed some amount of WordPress customization that neither WordPress.com nor Tumblr can provide. Ideally, both Django and WordPress are hosted on the same server and accessible through the same domain name (www.spotivate.com). Not a lot has been written about how Django and WordPress can live happily under one roof. Even less so on how to share UI components between the two. In our case, we wanted to share the main nav bar between the two frameworks, so that users don’t feel that they are leaving the Spotivate experience when they are reading our blog.

Here were the design requirements:

  1. Django and WordPress both running in the same (EC2) instance. Both through Apache HTTP Server. Both using the same MySQL instance.
  2. There is a main nav bar on the Spotivate web site. We wanted this nav bar to be on our blog. The nav bar indicates whether the current user is logged in (and if so, a user thumbnail), the currently selected tab, and various statistics about the logged in user.
  3. URL Namespace
    • /blog goes to WordPress
    • Everything else goes to Django

Here’s what our main nav bar looks like:

Spotivate Main Nav Bar

Spotivate Main Nav Bar

A bit of background. Our Django environment runs under Apache through WSGI. Before WordPress, we had it setup so that all traffic goes to Django (with the exception of static files). Here’s a snippet from our httpd.conf file that enabled this.

<VirtualHost *:80>
ServerName www.spotivate.com
WSGIScriptAlias / "/home/ec2-user/src/spotivate/server/apache/django.wsgi"

<Directory "/home/ec2-user/src/spotivate/server/apache">
Order allow,deny
Allow from all

Alias /static/admin/ "/usr/lib/python2.6/site-packages/django/contrib/admin/static/admin/"
<Directory "/usr/lib/python2.6/site-packages/django/contrib/admin/static/admin/">
Order allow,deny
Allow from all

Alias /static/ "/home/ec2-user/src/spotivate/server/static/"
<Directory "/home/ec2-user/src/spotivate/server/static/">
Order allow,deny
Allow from all


We installed WordPress under our Django “statics” folder, but it can be any folder really. We followed the normal installation procedure of WordPress and installed the database in our current MySQL instance.

Then we changed our httpd.conf by adding the following directives to our existing VirtualHost block:

<VirtualHost *:80>
# wordpress blog
Alias /blog "/home/ec2-user/server/static/blog"
<Directory "/home/ec2-user/server/static/blog">
Order allow,deny
Allow from all
AllowOverride FileInfo

Restart the httpd server. Now, we are able to go to http://www.spotivate.com/blog/wp-admin and log in. Next step is to tell WordPress that it belongs under blog by going to Settings >> General. There, change both WordPress Address and Site Address to www.spotivate.com/blog.

Spotivate Blog General Settings

Spotivate Blog General Settings

At this point, we have ourselves a fairly functional stand-alone WordPress blog, showing the default Hello World post under http://www.spotivate.com/blog. Also, all our Django code still works. Great! Now, onto the harder task. Add our nav bar to WordPress by mucking around with header.php and footer.php. We are using Genesis WordPress framework, but this trick should work for most.

The nav bar and any accompanying logic (CSS / Javascript) will be served from Django. Before we had the blog, the nav bar was a piece of HTML in our base template, which also contains reference to CSS file that controls how it looks, and reference to Javascript file that handles hover events, drop down menu, event logging, etc. We want to host all of this code in Django still, since only Django know who the logged in user is. To make nav bar work externally, we need to chop up our base template so that the nav bar can be re-used in WordPress. Then over in WordPress, we will modify header.php and footer.php to call Django to get the nav bar code, and add it to the page dynamically via Javascript.

On Django side, we create two URL mappings:


This will return stuff that will go into thetag of the blog. This will include our CSS and all necessary Javascript (i.e. our Javascript, Google analytics, JQuery, FB, Twitter APIs). Have a look!


This will return HTML of the nav bar. No body or html tags. Just the div. Checkout the source to see what I mean, both as an authenticated and un-authenticated user.

Once we got Django to serve the above URLs properly, we can modify header.php by adding this block of code to before </head>. This pretty much adds all our Javascript and CSS code to our blog. This also allows us to reuse CSS definitions in our blog.

<!-- Django integration: read from /blog_head -->
$contents = file_get_contents('http://www.spotivate.com/blog_head');
echo $contents;

Finally, modify footer.php by adding this block of code to before </body>.

<!-- Django integration: read from /blog_navbar -->
<div id="spotivate-blog-navbar" style="z-index:1000; position: fixed; height: 45px;">
$(function() {

The first bit of code defines an empty navbar div with id spotivate-blog-navbar, with fixed positioning and pre-defined height. We wanted the nav bar to float over any blog content just like in our main website. Then there’s a bit of Javascript that loads /blog_navbar (which calls our Django view mentioned above), and stuffs the content into the spotivate-blog-navbar div.

To be honest, it’s not the most pleasing user experience, as the user will see the blog post first, and a split second later, the nav bar shows up.. But it works!

Here’s how our website looks:

Spotivate Website

And here’s how our blog looks:

Spotivate Blog

We spent quite a bit of time making sure the experience feels integrated, and we feel like we have achieved that.

Do you have any other tips and gotchas while integrating Django and WordPress?