This guide is a walk-through on how to setup Ubuntu Server for hosting Django websites. The Django stack that will be used in this guide is Ubuntu, Nginx, Gunicorn and Postgres. I needed an example site for this guide you can use Django Base Site which is available on Github. For more useful information on Ubuntu server installs, please see the documentation here: https://help.ubuntu.com/12.10/serverguide/
This walk-through goes over configuring a VM in VirtualBox using a bridged network connection so that we can access the Internet. This walk-through doesn't fully go over hardening your server, but please read this fine tutorial to get a fairly good understanding of what you need to do to secure your web servers: http://www.thefanclub.co.za/how-to/how-secure-ubuntu-1204-lts-server-part-1-basics.
Note: Before you begin, in Virtual Box just set up a bridged adapter on the first interface, eth0. There are security concerns in this configuration but we aren't going to run the webserver for long periods of time.
The version of Ubuntu I'm using for this guide is Ubuntu 12.10 64 bit Server. I've installed Ubuntu Server in a VirtualBox VM. During the installation of Ubuntu Server I answered the prompts with the following:
Language: English Install Menu: Install Ubuntu Server Select a language: English Select your location: United States Configure the Keyboard: No Configure the keyboard: English (US) Configure the keyboard: English (US) Configure the network (if you have multiple virtual NICs): eth1 Hostname: webapps1 Set up users and passwords: William Sams Set up users and passwords: (Enter a username) Set up users and passwords: ******** Set up users and passwords: ******* Set up users and passwords: No Configure the clock: Yes Partition disks: Guided - use entire disk and set up LVM Partition disks: SCSI1 (0,0,0) (sda) - 22.5 GB ATA VBOX HARDDISK Partition disks: Yes Partition disks: Continue Partition disks: Yes Configure the package manager: <blank> Configure taskse1: No automatic updates Software selection: OpenSSH server, PostgreSQL database Install the GRUB boot loader on a hard disk: Yes Installation complete: <Continue>
First, let's setup a static IP for our server. We will need to open up the interfaces configuration in a text editor. The text editor I will be using throughout this walk-through is VIM, but any command line based editor (i.e., Nano) would be fine:
$ sudo vi /etc/network/interfaces
Modify your entries to match your network configuration:
iface eth1 inet static address 192.168.1.145 netmask 255.255.255.0 gateway 192.168.1.254
And then to make all of your changes stick:
$ sudo apt-get remove isc-dhcp-client && sudo stop networking && sudo start networking
Next, we want to enable Ubuntu's Uncomplicated Firewall (UFW) and allow HTTP on port 8080 and SSH on port 2222. We will be using alternate ports instead of the well-known 80 for HTTP and 22 for SSH:
$ sudo ufw enable $ sudo ufw allow 8080/tcp && sudo ufw deny 80 $ sudo ufw allow 2222/tcp && sudo ufw deny 22
Double-check your changes:
$ sudo ufw status
To ensure SSH works on a different port other than the standard port 22 we will need to modify ssh configuration:
$ sudo vi /etc/ssh/sshd_config
Once Vim opens, modify these settings necessary modifications:
Port 2222 Protocol 2
Now restart ssh (alternatively, you can do sudo stop ssh && sudo start ssh):
$ sudo stop ssh && sudo start ssh
Edit your hosts file to add the web server:::
$ sudo vi /etc/hosts
Once Vim opens, add this to the contentss:
192.168.1.145 webapps1
Now that we have an alternate port set up for SSH, you should now be able to open up your Terminal on the host machine and connect to your Ubuntu Server using the following:
$ ssh webapps1 -p 2222
We will finish the rest of our steps in the Terminal from your host machine and not on the server.
The Python header files are needed in order to compile binding libraries like psycopg2
.
$ sudo aptitude install python2.7-dev
$ sudo aptitude install nginx
$ sudo aptitude install git
Install Postgres:
$ sudo aptitude install postgresql-server-dev-9.1
We installed PostgreSQL during our initial setup of the server. Make your Ubuntu user a PostgreSQL superuser:
$ sudo su postgres $ createuser --superuser <your username> $ exit
Restart PostgreSQL:
$ sudo /etc/init.d/postgresql restart
The reason we are setting up a generic deploy user is so that if you have multiple developers who are allowed to do deployments you can easily add the developer's SSH public key to the deploy user's /home/deploy/.ssh/authorized_keys
file in order to allow them to do deployments.
$ sudo useradd -d /home/deploy -m -s /bin/bash deploy
Setup a virtualenv:
$ sudo apt-get install python-setuptools $ sudo easy_install pip $ sudo pip install virtualenv $ cd /usr/local/ $ sudo mkdir virtualenvs $ sudo chown deploy:deploy virtualenvs $ sudo su deploy $ cd virtualenvs $ virtualenv --no-site-packages example-site $ exit
Note
I personally use and setup virtualenvwrapper on all my servers and local development machines so that I can use workon <virtualenv>
to easily activate a virtualenv. This is why I put all my virtualenvs in /usr/local/virtualenvs
.
Make a location for the example site:
$ cd /srv/ $ sudo mkdir sites $ sudo chown deploy:deploy sites $ sudo su deploy $ cd sites $ sudo mkdir example-site/ $ cd example-site/ $ echo `pwd` > /usr/local/virtualenvs/example-site/lib/python2.7/site-packages/django_project_root.pth $ mkdir -p static/cache $ exit $ sudo chown www-data:www-data /srv/sites/example-site/static/cache $ sudo su deploy
Install the sites required python packages:
$ source /usr/local/virtualenvs/example-site/bin/activate $ cd /srv/sites/example-site/
Install Django:
$ pip install django
Install Gunicorn:
$ pip install gunicorn
Install psycopg2:
$ pip install psycopg2
Create a PostgreSQL user and database for your example-site:
# exit out of the deploy user account $ exit $ createuser webuser -P $ Enter password for new role: [enter the same password you used in the local.py file from above] $ Enter it again: [enter the password again] $ Shall the new role be a superuser? (y/n) n $ Shall the new role be allowed to create databases? (y/n) y $ Shall the new role be allowed to create more new roles? (y/n) n $ createdb northwind -O webuser
Create the file /srv/sites/example-site/config/settings/local.py
and add the following.:
from base import * LOCAL_SETTINGS_LOADED = True DEBUG = True INTERNAL_IPS = ('127.0.0.1', ) ADMINS = ( ('Your Name', '[email protected]'), ) DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'example_site', 'USER': 'example_site', 'PASSWORD': '<enter a new secure password>', 'HOST': 'localhost', } }
Create the site:
$ django-admin.py startproject example-site
Create your Upstart configuration file:
$ sudo vi /etc/init/gunicorn_example-site.conf
Add the following and save the file:
description "upstart configuration for gunicorn example-site" start on net-device-up stop on shutdown respawn exec /usr/local/virtualenvs/example-site/bin/gunicorn_django -u www-data -c /srv/sites/example-site/config/gunicorn/example-site.py /srv/sites/example-site/config/settings/__init__.py
Start the gunicorn site:
$ sudo start gunicorn_example-site
Create a new file sudo vi /etc/nginx/sites-available/example-site.conf
and add the following to the contents of the file:
server { listen 80; server_name localhost; access_log /var/log/nginx/example-site.access.log; error_log /var/log/nginx/example-site.error.log; location = /biconcave { return 404; } location /static/ { root /srv/sites/example-site/; } location /media/ { root /srv/sites/example-site/; } location / { proxy_pass http://127.0.0.1:8001/; 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; } }
Enable the new site:
$ cd /etc/nginx/sites-enabled $ sudo rm default $ sudo ln -s ../sites-available/example-site.conf
Start nginx:
$ sudo /etc/init.d/nginx start
While still connected to your Ubuntu server via SSH run the following, which should spit out the HTML for your site:
wget -qO- 127.0.0.1:80
Since you setup port forwarding in step 2 for web, you should also be able to open up your browser on your local host machine and pull up the website using the URL, http://127.0.0.1:8080.