blog: Creating My Django Server.
(Note: This article is essentially a walk through of what I did to setup Django on a basic Ubuntu Intrepid server. Any comments or suggestions on improving my setup are more then welcome as I do not claim to be an expert at setting up web servers, just a tinkerer)
Whether you’re writing your application in Python, Ruby, or even PHP (Yes, even PHP) it feels good to know what’s exactly powering your software. Earlier this week I put together the setup for one of my Django sites and this guide will go through the process. The services are running off a 256mb slice from Slicehost, which I highly recommend.
What we’re running here: The end result is an Ubuntu Intrepid server using Apache2 with mod_python to serve Django, and lighttpd to serve media/static files. Memcache is used as a caching backend and mySQL 5.0 is our primary database. This is a very common Django setup and you will find similar guides all over the net. This is just my take :)
Getting the packages we need.
SSH to your server, authenticate and run the following commands to install our necessary packages:
$ sudo aptitude install apache2 apache2.2-common apache2-utils
$ sudo aptitude install libapache2-mod-python
$ sudo aptitude install python-setuptools # You need this for a few python modules we need to install
$ sudo aptitude install mysql-server mysql-client libmysqlclient15-dev
$ sudo aptitude install memcached
$ sudo aptitude install python-mysqldb
$ sudo aptitude install lighttpd</code>
Setting up MySQL.
Setting up mySQL is rather simple. You already supplied a root password when you were initially installing the packages so all we really need to do now is create a database and grant access to a non-root user. This is very simple:
$ mysql -uroot -p
mysql> CREATE DATABASE mysite;
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP ON mysite.* TO 'foo'@'localhost' IDENTIFIED BY 'password';
As I said, very simple. We create an initial database and then use GRANT to give us a user/password combo we can connect with. If you have an existing set of mysql data, you can now dump it into your database.
I don’t fancy myself an expert in mySQL user permissions so I recommend viewing the mySQL 5 Grant Documentation for more information. You may also want to take a look at your /etc/mysql/my.cnf configuration file to modify mySQL settings depending on your sites load.
Configure & run memcached as a daemon
Installing memcached is optional as you may not need or want caching, but it’s generally good practice to have it with your Django sites. To run it, we are going to execute this command:
$ memcached -u www-data -p 11211 -m 32 -d
What this does is tells memcached to run under the user www-data which is the user Apache runs under on Ubuntu. We run it on port 11211 (default), and give it 32mb of memory. You can adjust this memory to be larger or smaller depending on your machine and traffic of websites. As I only have 256mb of RAM and a single (small) site, this is sufficient. Finally, the -d flag runs it as a daemon.
Now we have to install some memcached python bindings. cmemcache is a popular choice but I can’t get it to work when installing memcached from a package (only from source, which we didn’t do), so we opt for the second best: python-memcached. Simply grab it and install it:
$ wget ftp://ftp.tummy.com/pub/python-memcached/python-memcached-latest.tar.gz
$ tar -zxvf python-memcached-latest.tar.gz
$ cd python-memcached-1.43
$ sudo python setup.py install
That’s pretty much it for memcached! The rest of the work is involved within your Django application which you can read all about from the official Django documentation.
Setup Django.
Of course, we actually need to get Django! You can fetch it in a variety of ways from the download page. Personally, I enjoy using the SVN trunk as it’s pretty stable while having the benefit of new features and bug fixes as soon as they are done. I like setting up Django in /home and then linking it to site-packages. This allows me to not worry much about permissions and everything just seems easier. Plus I love the ~ accessibility :)
First, let’s give our www-data user (see above, it’s our Apache user) access to our files.
$ sudo gpasswd -a www-data yourusername # In my case, it's admin
$ chmod g+w ~
Now, let’s get Django from trunk and setup some directories for our projects.
$ cd ~
$ mkdir projects
$ mkdir apps # This is not used in the tutorial, but this is where I place my portable django apps
$ svn co http://code.djangoproject.com/svn/django/trunk/ django
$ sudo ln -s `pwd`/django/django /usr/lib/python2.5/site-packages</code>
That’s it for that. Django is now recognized as a package in Python’s sys.path
Setting up your project with Apache.
We’re almost there! Now, we finally need to tell Apache and mod_python that we have a Django project we want them to serve. If you have an existing project, simply fetch it from your favourite version control service. If not, you can start your own project quite simply:
$ cd ~/projects
$ ~/django/django/bin/django-admin.py startproject myproject
If you are starting from scratch, you will need to modify your settings.py file to match our setup of a mySQL database and the usage of memcached. There’s no point in me iterating over this, as the Django docs explain it quite well. So let’s get right down to it and setup our domain in Apache.
$ sudo vim /etc/apache2/sites-available/myproject.tld
And then paste the following, modifying as needed:
<VirtualHost *>
ServerName www.myproject.com
ServerAlias myproject.com
DocumentRoot /var/www/myproject.com
CustomLog /var/log/apache2/myproject.com.access.log combined
ErrorLog /var/log/apache2/myproject.com.error.log
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE myproject.settings
PythonDebug On
PythonPath "['/path/to/my/projects/parent_dir'] + sys.path"
<Location "/media">
SetHandler None
</Location>
</VirtualHost>
Some quick notes:
- Replace /path/to/my/projects/parent_dir and myproject.settings to the relative values. The path is to your projects PARENT directory. So in my case, it would be /home/bartek/projects
- /media is the directory where our django’s admin media will be linked to.
- Depending on your DNS settings, you may need to adjust the wildcard on the VirtualHost declaration.
Finally, let’s enable the site and setup the admin media link:
$ sudo ln -s /etc/apache2/sites-available/myproject.com /etc/apache2/sites-enabled/myproject.com
$ sudo ln -s ~/django/django/contrib/admin/media /var/www/myproject.com/
$ sudo apache2ctl restart # Restart Apache
…….And if you did everything right you should see either your Django project running or the default “It works!” Django page. Congrats!
Setting up lighttpd
Lighttpd setup is optional, but is highly recommended. It’ll keep your site running smoothly and doesn’t bog down Apache/mod_python trying to serve both Django and media.
First, you’ll have to edit Lighttpd’s settings to run on a different port. The default is 80, which is what our Apache setup is running on:
$ sudo vim /etc/lighttpd/lighttpd.conf
Uncomment the server.port line (around line 70)
server.port = 81
Next, enable the mod_evhost module. Simply uncomment it in the server.modules variable near the top of the config file. mod_evhost allows you to use a different directory for the static media depending on the domain name. Now, add the following line which basically says requests for myproject.com should look in this directory. I did this on the 124th line, right after the evhost patterns.
$HTTP["host"] =~ "myproject\\.com" {
evhost.path-pattern = "/home/admin/projects/myproject/static/"
}
Just so you’re not confused, I generally place my media in my project directory like I did above but you can have it anywhere you want. A commonplace is under /var/www/myproject.com
Note: If you are under Debian/Ubuntu and your site has a “images” directory, the default lighttpd config may not serve this. Some Debian/Ubuntu configurations reference “images” as a dir for the Debian policy and all your images will be broken unless you remove this reference. I found it at around line 160.
Start lighttpd:
$ sudo /etc/init.d/lighttpd start
And verify it is working by visiting http://myproject.com:81. You should see either your Apache or Lighttpd placeholder page.
Configure Apache to use Lighttpd
To serve files using Lighttpd from Apache we need to enable proxy on Apache. There are other methods of doing this, but I’ve found this the best documented, and hey — it works great!
$ ln -s /etc/apache2/mods-available/proxy.load /etc/apache2/mods-enabled/
$ ln -s /etc/apache2/mods-available/proxy_connect.load /etc/apache2/mods-enabled/
$ ln -s /etc/apache2/mods-available/proxy_http.load /etc/apache2/mods-enabled/
Or just as easily type sudo a2enmod proxy proxy_connect proxy_httpd if you are under Ubuntu. Finally, unsecured proxies are used by spammers so we want to configure ours to only accept local connections. Simply do this:
$ sudo vim /etc/apache2/mods-available/proxy.conf
And modify the wildcard in <VirtualHost> to state the local host like so:
AddDefaultCharset off
Order deny,allow
Deny from all
Allow from 127.0.0.1
Finally, configure the VirtualHost to use the Proxy
$ sudo vim /etc/apache2/sites-available/myproject.com
Add this somewhere in your <VirtualHost> declaration
ProxyRequests Off
ProxyPreserveHost On
ProxyPass /static http://127.0.0.1:81/
ProxyPassReverse / http://127.0.0.1:81/
And with that setup, reload and restart Apache and Lighttpd should now be serving your static media!
$ sudo /etc/init.d/apache2 reload
$ sudo /etc/init.d/apache2 restart
To double check if it is, you can use the lovely Firebug plugin and just look under the “Net” tab or just use curl:
$ curl -I http://myproject.com
$ curl -I http://myproject.com:81
Curl will send back a response on what is serving it. You’ll see the first one shows Apache/mod_python, and the second line should return a lighttpd reference.
It works!
And that about wraps it up! There are many things you can do to customize the services running your software but this is a basic setup that works great for small and medium-scale sites. From here, you can extend this by setting up PHP for other apps, and securing your server. I recommend the articles on Slicehost for some great walk throughs on securing your server.
References & Credits:
Of course, there are many people who have done this long before me and I got a lot of information from. These posts outline what I did, but in their own manner and some have other useful information. I recommend checking them all out as they are great at what they do:
- http://ventanazul.com/webzine/trackback/124
- http://lethain.com/entry/2007/jul/13/creating-my-dream-server-django/
- http://www.inerciasensorial.com.br/2007/06/10/perils-of-software-development/lighttpd-with-apache/
- http://articles.slicehost.com/