Running a High Performance Website


Nathan Osman's Gravatar

Nathan Osman
published Oct. 25, 2013, 3:57 p.m.


Here at 2buntu, we are always looking for ways to make our website more efficient. We recently published a brief article on some new changes we made to our architecture. Today, I would like to go into a bit more detail on what exactly we've done.

Note: this is not a one-size-fits-all solution for making your own website faster. Your needs will likely be different from ours and you will need to adjust accordingly.

First Things First

We did a bit of planning before throwing everything together. (Which is always a good idea, by the way.) I was asked by James to put together a plan and here's what I came up with:

2buntu Infrastructure

From there, we decided that we would need two servers:

  • one for PostgreSQL (DB) and Redis (cache)
  • one for Apache (HTTP)

Provisioning

Once you have a completely clean installation of Ubuntu Server, there are still a few things that need to be done before setting up the web server. I always prefer to run the actual WSGI application as an unprivileged user (instead of root). This can be accomplished as follows:

useradd -d /home/wsgi -m wsgi

This will create a user named "wsgi" that will be used to run the application. I usually create the ~/www path for storing static and media files. That way, because the application is running as the "wsgi" user, it will always be able to write static files to a path accessible to the web server.

Setting Up the Web Server

I won't go into a lot of details regarding the database / cache server since it was relatively easy to set up. The web server, however, was a different story. Our website is written in Python and uses the Django framework (which I highly recommend). Django cannot act as a front-end web server itself - it's a WSGI application. I usually just point Apache (with mod_wsgi) at the application and that's the end of the story.

But we wanted performance. Killer performance.

So I went back to the drawing board and decided to use nginx+gunicorn. After installing nginx for the first time and firing up gunicorn, I opened the home page in my browser. nginx lived up to its reputation for speed and efficiency - pages loaded much faster than before and I was greatly impressed.

Monitoring gunicorn

But there's one small problem. Even though gunicorn runs as a daemon, it must be started at some point. Sure I could use screen to keep it running, but what happens when the server reboots?

Enter supervisor.

Once installed, I simply provided the gunicorn command to supervisor and that was it. Now the gunicorn server will be started whenever the server boots and will be restarted if it crashes or aborts unexpectedly. The configuration file for 2buntu looks something like this:

[program:gunicorn]
command   = gunicorn twobuntu.wsgi:application
directory = /home/wsgi/repositories/2buntu
user      = wsgi

Summary

Hopefully that gives you a bit of a bigger picture of what we've done. Please let us know in the comments if you have any other questions for us and we will be happy to answer them.