This document covers basic steps to setup
- a
django
user who will serve Django applications, - Nginx as web server,
- Gunicorn as a WSGI and
- PostgreSQL with PostGIS as database server.
...on a default Ubuntu 10.04 server installation.
See the UFW Community docs and Ubuntu 10.04 server UFW docs for more details.
Allow SSH port (default: 22) and activate:
$ sudo ufw allow ssh
$ sudo ufw enable
Allow http service (port 80):
$ sudo ufw allow http
Check which rules are active:
$ sudo ufw status
Add a group wheel
that will contain users with sudo privileges:
$ sudo groupadd wheel
$ sudo visudo
## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL
Add new user, with home directory, bash and part of group wheel:
$ sudo useradd myusername -m -g wheel -s /bin/bash
$ sudo passwd myusername
The user django
will serve Django applications, without having sudo privileges.
$ sudo useradd django -m -g www-data -s /bin/bash
$ sudo passwd myusername
Configure remote login permissions:
$ sudo nano /etc/ssh/sshd_config
# Disable remote login for django user
Match User django
PasswordAuthentication no
$ sudo /etc/init.d/ssh reload
As django
user create a www
directory with the structure below:
$ su - django
$ sudo mkdir -p /home/django/www/domain.name/{public,log,backup,private}
Some basic tools that are of general use for developing and deploying Python based applications.
$ sudo apt-get install build-essential python-software-properties
$ sudo apt-get install python-dev python-setuptools
$ sudo easy_install pip
$ sudo pip install virtualenvwrapper
$ nano /home/django/.profile
export WORKON_HOME=~/virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
Git distributed version control
$ sudo apt-get install git-core
See GitHub's Linux docs for detailed information about how to configure git and a GitHub account.
Nginx web server
Add the stable repository and install Nginx 1.0 (default Ubuntu 10.04 repository has older version, might not be required for newer Ubuntu version):
$ sudo add-apt-repository ppa:nginx/stable
$ sudo apt-get update
$ sudo apt-get install nginx
Edit nginx.conf
to with a basic configuration:
$ sudo nano /etc/nginx/nginx.conf
user www-data;
worker_processes 2;
# check maximum file descriptors available at /proc/sys/fs/file-max
worker_rlimit_nofile 197587;
pid /var/run/nginx.pid;
events {
# 2GB available memory
worker_connections 1024;
# multi_accept on;
use epoll;
}
http {
index index.html;
client_max_body_size 20m;
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# Logging Settings
##
# uncomment if access logs are needed
# access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Some interesting posts about Nginx configuration optimizations:
- http://www.untwistedvortex.com/installing-configuring-nginx-ubuntu-1004-64bit-lts/
- http://www.lifelinux.com/how-to-optimize-nginx-for-maximum-performance/
Test and reload Nginx's updated configuration:
$ sudo nginx -t
$ sudo nginx -s reload
PostgreSQL database server
Add the PostgreSQL 9.0 repository (default version Ubuntu 10.04 is 8.4, might not be required on newer Ubuntu system) and install the PostgreSQL server and development libraries:
$ sudo add-apt-repository ppa:pitti/postgresql
$ sudo apt-get update
$ sudo apt-get install postgresql-9.0 postgresql-server-dev-9.0 postgresql-contrib-9.0 libpq-dev
Create the PostGIS template (note: PostGIS must be installed, see below for details):
$ sudo su - postgres
$ POSTGIS_SQL_PATH=`pg_config --sharedir`/contrib
# Creating the template spatial database.
$ createdb -E UTF8 --lc-collate en_US.UTF-8 --lc-ctype en_US.UTF-8 -T template0 template_postgis
$ createlang -d template_postgis plpgsql # Adding PLPGSQL language support.
# Allows non-superusers the ability to create from this template
$ psql -d postgres -c "UPDATE pg_database SET datistemplate='true' WHERE datname='template_postgis';"
# Loading the PostGIS SQL routines
$ psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis-1.5/postgis.sql
$ psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis-1.5/spatial_ref_sys.sql
$ psql -d template_postgis -f $POSTGIS_SQL_PATH/postgis_comments.sql
# Enabling users to alter spatial tables.
$ psql -d template_postgis -c "GRANT ALL ON geometry_columns TO PUBLIC;"
$ psql -d template_postgis -c "GRANT ALL ON geography_columns TO PUBLIC;"
$ psql -d template_postgis -c "GRANT ALL ON spatial_ref_sys TO PUBLIC;"
# Garbage-collect and freeze.
$ psql -d template_postgis -c "VACUUM FULL;"
$ psql -d template_postgis -c "VACUUM FREEZE;"
Create a new PostgreSQL user and set password:
$ createuser django
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
$ psql
# ALTER ROLE django WITH password 'mypassword';
ALTER ROLE
# \q
Create a new database from a template and assign an owner
$ createdb test -T template_postgis -O django
Delete database
$ dropdb test
Each sudoer is also a PostgreSQL superuser. If that's not sufficient, you can use the postgres user to perform database related tasks:
$ sudo su - postgres
Config directory: /etc/postgresql/9.0/main
Data directory: /var/lib/postgresql/9.0/main
Allow remote access, if required by editing the config files pg_hba.conf
, postgresql.conf
, adjusting the firewall rules and finally restarting the server to propagate all changes:
$ sudo nano /etc/postgresql/9.0/main/pg_hba.conf
...
# All of an intranet
host all all 10.10.10.0/24 md5
...
$ sudo nano /etc/postgresql/9.0/main/postgresql.conf
...
listen_addresses = '*'
...
# open PostgreSQL's port in firewall
$ sudo ufw allow from 10.10.10.0/24 to any port 5432
$ sudo /etc/init.d/postgresql restart
Performance tweaks for postgresql.conf:
shared_buffers: set to 10-20% of RAM
effective_cache_size: set to 75% of RAM
Memcached caching system
Memcached will help to reduce load on Django applications (and therefore database queries).
Install and start the memcached server:
$ sudo apt-get install memcached libmemcached-dev
$ sudo memcached -d -u www-data -p 11211 -m 64
Memcached startup configuration is located at /etc/memcached.conf
.
Add repository with last 1.5 version (might not be required on newer Ubuntu system):
$ sudo add-apt-repository ppa:ubuntugis/ubuntugis-unstable
$ sudo add-apt-repository ppa:pi-deb/gis
$ sudo apt-get update
$ sudo apt-get install postgresql-9.0-postgis \
proj libproj-dev libgeos-3.2.2 libgeos-c1 libgeos-dev \
libgdal1-1.8.0 libgdal1-dev libxml2 libxml2-dev \
checkinstall
Django applications are deployed by the Gunicorn WSGI server and cached with memcached. Nginx is proxying the WSGI server and also serving Django's static files.
Additional dependencies that need to be installed on the system or better, the individual virtual environment:
$ pip install gunicorn python-memcached
Test Gunicorn installation with Django:
$ cd /home/django/domains/MYPROJECT.ORG/private/MYPROJECT
$ gunicorn_django -b 0.0.0.0:8000
Create a gunicorn script /home/django/domains/MYPROJECT.ORG/private/gunicorn.sh
and make it executable:
#!/bin/bash
set -e
LOGFILE=/home/django/domains/MYPROJECT.ORG/log/gunicorn.log
NUM_WORKERS=1
# user/group to run as
USER=django
GROUP=www-data
cd /home/django/domains/MYPROJECT.ORG/private/MYPROJECT
source /home/django/virtualenvs/MYPROJECT/bin/activate
exec /home/django/virtualenvs/MYPROJECT/bin/gunicorn MYPROJECT.wsgi:application \
--workers=$NUM_WORKERS \
--bind=127.0.0.1:8001 \
--user=$USER --group=$GROUP --log-level=error \
--log-file=$LOGFILE 2>>$LOGFILE
$ chmod ug+x gunicorn.sh
Additional Django local_settings.py
configuration parameters:
# static files served by Nginx
STATIC_URL = '/static/'
STATIC_ROOT = '/home/django/domains/MYPROJECT.ORG/public/static'
# uncomment and/or change if GDAL can't be found
# GDAL_LIBRARY_PATH = '/usr/lib/libgdal1.8.0.so'
# memcached integration (https://docs.djangoproject.com/en/1.3/topics/cache/)
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
)
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 3600
CACHE_MIDDLEWARE_KEY_PREFIX = 'MYPROJECT'
Add Ubuntu Upstart service script in /etc/init/MYPROJECT.conf
to start app on system boot:
description "MYPROJECT Django instance"
start on runlevel [2345]
stop on runlevel [06]
respawn
respawn limit 10 5
exec /home/django/domains/MYPROJECT.ORG/private/gunicorn.sh
# start and stop app
$ sudo service MYPROJECT [start/stop]
Nginx serves static files and proxies Gunicorn WSGI applications.
A virtual host configuration with a proxy to a Django project looks like:
$ nano /etc/nginx/sites-available/MYPROJECT.ORG
server {
listen 80;
server_name MYPROJECT.ORG;
root /home/django/domains/MYPROJECT.ORG/public;
access_log /home/django/domains/MYPROJECT.ORG/log/access.log;
error_log /home/django/domains/MYPROJECT.ORG/log/error.log;
# serve staticfiles
location /static/ {
root /home/django/domains/MYPROJECT.ORG/public/;
expires 1d;
}
# proxy
location / {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 10;
proxy_read_timeout 10;
proxy_pass http://127.0.0.1:8001/;
}
# what to serve if upstream is not available or crashes
# error_page 500 502 503 504 /media/50x.html;
}
Enable the virtual host with a symbolic link from available to enabled:
$ sudo ln -s /etc/nginx/sites-available/MYPROJECT.ORG /etc/nginx/sites-enabled/MYPROJECT.ORG