Installing Django on Ubuntu Intrepid: Django, Nginx, Apache, mod_wsgi, cmemcache

A complete start to finish guide.

This guide will cover the complete setup of an Ubuntu Intrepid server as well as the software below:

Please note, this guide was written for Ubuntu Intrepid, but will likely work on other versions of Ubuntu barring any software version differences.

Install Summary


Log in (for Windows users)

  • Download and install PuTTY
  • Configure and connect
  • Click 'yes' when prompted with security warning

Log in (for Linux users)

$ ssh root@<slice ip>

Setup SSH and add new user

Replace sylink with better shell

$ ln -sf /bin/bash /bin/sh

Change root password

$ passwd

Add a new admin user

$ adduser <username>

Grant new user sudo privileges

$ visudo

Add this to end of file and save

$ <username>   ALL=(ALL) ALL

Linux users and SSH key

Create folder to hold keys (on local workstation)

(local)$ mkdir ~/.ssh

Create SSH keys (on local workstation)

(local)$ ssh-keygen -t rsa

Copy public key onto slice (on local workstation)

(local)$ scp ~/.ssh/id_rsa.pub <username>@<slice ip>:/home/<username>/

Create directory in <username>/home folder to hold public key (on slice)

$ mkdir /home/<username>/.ssh
$ mv /home/<username>/id_rsa.pub /home/<username>/.ssh/authorized_keys

Set permissions on key (on slice)

$ chown -R <username>:<username> /home/<username>/.ssh
$ chmod 700 /home/<username>/.ssh
$ chmod 600 /home/<username>/.ssh/authorized_keys

Disable root login

Switch to new user

$ su <username>

Verify use has sudo before disabling. Should print 'root'

$ sudo whoami

Change default SSH config to be more secure

$ sudo nano /etc/ssh/sshd_config
Port 30000                  <--- change to a port of your 
choosing
Protocol 2
PermitRootLogin no
PasswordAuthentication no   <--- yes if windows
X11Forwarding no
UsePAM no
UseDNS no
AllowUsers <username>

Reload SSH config

$ sudo /etc/init.d/sshd reload

Configure firewall

Install firewall

$ sudo aptitude install ufw

Turn on firewall

$ sudo ufw enable

Enable/disable logging

$ sudo ufw logging on

Enable port 80 for TCP only

$ sudo ufw allow 80/tcp

Enable SSH port you chose before

$ sudo ufw allow <SSH port>

Lock down system

$ sudo ufw default deny

Update system and set locale

Update

$ sudo aptitude update

Set locale. This setting is for the US. If you live in another country you will need to use another setting.

$ sudo locale-gen en_US.UTF-8 
$ sudo /usr/sbin/update-locale LANG=en_US.UTF-8

Safe upgrade

$ sudo aptitude safe-upgrade

Full upgrade

$ sudo aptitude full-upgrade

Install Build Essentials

$ sudo aptitude install build-essential

Configure DNS

Creating DNS records on SliceHost

If you aren't hosted on SliceHost the process for creating your DNS records will be different.

Install Nginx

Install Nginx

$ sudo aptitude install nginx

Start Nginx server

$ sudo /etc/init.d/nginx start

Test Nginx is running by opening your favorite browser and navigating to http://<slice ip>. Should display "Welcome to nginx!"

Configure Nginx

Disable default site

$ sudo rm /etc/nginx/sites-enabled/default

Modify config file

$ sudo nano /etc/nginx/nginx.conf
worker_processes  4;     <--- set equal to the number of cores on your server
tcp_nopush     on;
keepalive_timeout  2;
gzip  on;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

Shutdown Nginx

$ sudo /etc/init.d/nginx stop 
Create proxy.conf file
$ sudo nano /etc/nginx/proxy.conf
proxy_redirect              off;
proxy_set_header            Host $host;
proxy_set_header            X-Real-IP $remote_addr;
proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size        10m;
client_body_buffer_size     128k;
proxy_connect_timeout       90;
proxy_send_timeout          90;
proxy_read_timeout          90;
proxy_buffer_size           4k;
proxy_buffers               4 32k;
proxy_busy_buffers_size     64k;
proxy_temp_file_write_size  64k;

Install Apache

Ignore the error after install

$ sudo aptitude install apache2 apache2.2-common apache2-mpm-worker apache2-threaded-dev libapache2-mod-wsgi python-dev

Configure Apache

Modify config file

$ sudo nano /etc/apache2/apache2.conf
Timeout 90
KeepAlive Off
ServerName <server name>

Restart Apache

$ sudo apache2ctl graceful

Test Apache is running by opening your favorite browser and navigating to http://<slice ip>. Should display "It works!"

Disable default site

$ sudo a2dissite 000-default

Change listening port and virtual host to 8080

$ sudo nano /etc/apache2/ports.conf

Change security settings

$ sudo nano /etc/apache2/conf.d/security

Restart Apache, ignore the error

$ sudo apache2ctl graceful

Start Nginx

$ sudo /etc/init.d/nginx start

Install Subversion

$ sudo aptitude install subversion

Install Django

Change directory

$ cd /usr/lib/python2.5/site-packages

Checkout code from Django SVN

$ sudo svn co http://code.djangoproject.com/svn/django/tags/releases/1.0.2/django django

Create symlink

$ sudo ln -s /usr/lib/python2.5/site-packages/django/django/bin/django-admin.py /usr/local/bin/django-admin.py

Install Memcached

Install Memcached and dependencies

$ sudo aptitude install memcached
$ sudo aptitude install libmemcache-dev

Download cmemcached

$ cd /usr/local/src/
$ sudo wget http://gijsbert.org/downloads/cmemcache/cmemcache-0.95.tar.bz2

Install cmemcache

$ sudo tar xjvf cmemcache-0.95.tar.bz2
$ cd cmemcache-0.95
$ sudo python setup.py install

Edit test.py

$ sudo nano test.py
# get stats
#stats = mc.get_stats()
#self.failUnlessEqual(len(stats), 1)
#self.assert_(self.servers[0] in stats[0][0])
#self.assert_('total_items' in stats[0][1])
#self.assert_('bytes_read' in stats[0][1])
#self.assert_('bytes_written' in stats[0][1])

Start Memcached. Be sure to set memory size

$ memcached -d -m <memory size> -l 127.0.0.1 -p 11211

Run test.py

$ python test.py

Create layout for domains

Create parent directory layout

$ mkdir /home/<username>/public_html

Create sub-folders for domain

$ mkdir -p /home/<username>/public_html/<domain name>
$ mkdir -p /home/<username>/public_html/<domain name>/private
$ mkdir -p /home/<username>/public_html/<domain name>/logs

Grant Apache write permissions

Add main user to Apache group

$ sudo usermod -a -G www-data <username>

Make sure public_html folder is owned by <username> and is in the www-data group

$ sudo chgrp -R www-data /home/<username>/public_html

Make sure any new files put into public_html will inherit permissions

$ sudo chmod -R 2750 /home/<username>/public_html

Grant Apache write permissions to private folder (if needed)

$ sudo chmod -R 2770 /home/<username>/public_html/<domain name>/private

Install source code

Change directory and install your source code in this directory

$ cd /home/<username>/public_html/<domain name>

Create .wsgi file

$ mkdir /home/<username>/public_html/<domain name>/<django project name>/apache
$ cd /home/<username>/public_html/<domain name>/<django project name>/apache
$ nano <django project name>.wsgi
import os, sys

apache_configuration= os.path.dirname(__file__)
project = os.path.dirname(apache_configuration)
workspace = os.path.dirname(project)
sys.path.append(workspace) 

sys.path.append('/usr/lib/python2.5/site-packages/django/')
sys.path.append('/home/<username>/public_html/<domain name>/<django project name>')

os.environ['DJANGO_SETTINGS_MODULE'] = '<django project name>.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Create symlink for admin media

$ sudo ln -s /usr/lib/python2.5/site-packages/django/contrib/admin/media /home/<username>/public_html/<domain name>/<django project name>/media/admin

Modify settings.py file of your project

$ sudo nano settings.py
ADMIN_MEDIA_PREFIX = '/media/admin/'
.
.
.
MIDDLEWARE_CLASSES = (
    'django.middleware.http.SetRemoteAddrFromForwardedFor',
)

Create Nginx virtual host

Create new virtual host file

$ sudo nano /etc/nginx/sites-available/<domain name>
upstream backend {
  server 127.0.0.1:8080;
}

server {
            listen   80;
            server_name www.<domain name> <domain name>;

            access_log /home/<username>/public_html/<domain name>/logs/nginx_access.log;
            error_log /home/<username>/public_html/<domain name>/logs/nginx_error.log;

            location / {
                        proxy_pass  http://backend;
                        include     /etc/nginx/proxy.conf;
            }

            location  /media/ {
                        root /home/<username>/public_html/<domain name>/<django project name>/;
            }
}

Create symlink to enable new domain

$ sudo ln -s /etc/nginx/sites-available/<domain name> /etc/nginx/sites-enabled/<domain name>

Restart Nginx

$ sudo /etc/init.d/nginx stop 
$ sudo /etc/init.d/nginx start

Create Apache virtual host

Create new virtual host file

$ sudo nano /etc/apache2/sites-available/<domain name>
<VirtualHost *:8080>
    #Basic setup
    ServerAdmin <admin email>
    ServerName www.<domain name>
    ServerAlias <domain name>

    <Directory /home/<username>/public_html/<domain name>/<django project name>/apache/>
        Order deny,allow
        Allow from all
    </Directory>

    LogLevel warn
    ErrorLog  /home/<username>/public_html/<domain name>/logs/apache_error.log
    CustomLog /home/<username>/public_html/<domain name>/logs/apache_access.log combined
    
    WSGIDaemonProcess <domain name> user=www-data group=www-data threads=25
    WSGIProcessGroup <domain name>
    
    WSGIScriptAlias / /home/<username>/public_html/<domain name>/<django project name>/apache/<django project name>.wsgi
</VirtualHost>

Enable new site

$ sudo a2ensite <domain name>
$ sudo /etc/init.d/apache2 reload

Your new server should now be up and running. If you'd like more information on the above directions please consult the sources below:


blog comments powered by Disqus