Based on:
- Will Larson’s Django and Ubuntu Intrepid Almanac excellent post. Probably worth looking at that first!
- Ubuntu Server Guide
- Ubuntu Hardy + Nginx
- Rich Leland’s ‘pip and virtualenv’ post
Assumptions
- Logged in as root locally.
- Network interface has been configured.
Steps
- Update your apt-get sources
apt-get upgrade
- Add some accounts (using
bobas my own account):
useradd django
mkdir /home/django
chown django:django /home/django
useradd bob
mdkir /home/bob
chown bob:bob /home/bob
passwd bob - Change the default shell:
chsh root -s /bin/bash
chsh bob -s /bin/bash
chsh django -s /bin/bash -
passwd bob
passwd django - Add root permission to
bobby adding the account to the admin group.
usermod -a -Gadmin bob
- Try logging in as
bob:
su bob
- If OpenSSH is not installed then visit this page about setting it up.
sudo apt-get install openssh-server
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.original
sudo chmod a-w /etc/ssh/sshd_config.originalCheck if ssh is running:
ps -ef | grep sshd
If not try:
/etc/init.d/ssh start
If you’re getting a ‘Connection refused’ message, check that the
/etc/hostsfile is set correctly particularly if you changed to a static address by changing/etc/network/interfaces. If there is nothing wrong there double check any firewall settings. - We’ll be restricting ssh to
bobonly, so create a specialsshersgroup:
sudo groupadd sshers
sudo usermod -a -Gsshers bob - Time to configure
ssh:
Make these changes to/etc/ssh/sshd_config#Port 22
PortXXXX(pick a port number)#PermitRootLogin yes
PermitRootLogin no#X11 Forwarding yes
X11 Forwarding noAdd these if not found
MaxAuthTries 6
UseDNS no
AllowGroups sshersAnd restart the
sshservice:sudo /etc/init.d/ssh restart
Check that you can login:
ssh bob@xxx.xxx.xxx.xxx -p XXXX
If it works you can disable the root password:
sudo passwd -l root
- Next install Postgres (might need to install gcc and make as well):
sudo apt-get install postgresql-8.3 postgresql-server-dev-8.3
Change the password for the
postgresuser:sudo -u postgres psql template1
You’ll get the
psqlprompt and then just type:- ALTER USER postgres WITH PASSWORD ‘
somePassword‘; - \q
- ALTER USER postgres WITH PASSWORD ‘
- The config file for Postgres also needs to be modified:
sudo vi /etc/postgresql/8.3/main/pg_hba.conf
The end of the file should changed to look like:
# Database administrative login by UNIX sockets
local all postgres ident sameuser
# TYPE DATABASE USER CIDR-ADDRESS METHOD
# “local” is for Unix domain socket connections only
local all all password
# IPv4 local connections:
#host all all 127.0.0.1/32 md5
# IPv6 local connections:
#host all all ::1/128 md5Next, just restart Postgres:
sudo /etc/init.d/postgresql-8.3 restart
- Nginx will serve static content and proxy requests to Apache2. We’ll need to install the latest stable version.
sudo aptitude -y install libpcre3 libpcre3-dev libpcrecpp0 libssl-dev zlib1g-dev
mkdir ~/sources
cd ~/sources/
wget http://sysoev.ru/nginx/nginx-0.7.61.tar.gz
tar -zxvf nginx-0.7.61.tar.gz
cd nginx-0.7.61
./configure --sbin-path=/usr/local/sbin --with-http_ssl_module
make
sudo make installStart Nginx
sudo /usr/local/sbin/nginx
Try viewing it on a browser.
Stop it and create an init scriptsudo kill `cat /usr/local/nginx/logs/nginx.pid`
sudo vi /etc/init.d/nginx#! /bin/sh### BEGIN INIT INFO
# Provides: nginx
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: starts the nginx web server
# Description: starts nginx using start-stop-daemon
### END INIT INFOPATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/local/sbin/nginx
NAME=nginx
DESC=nginxtest -x $DAEMON || exit 0
# Include nginx defaults if available
if [ -f /etc/default/nginx ] ; then
. /etc/default/nginx
fiset -e
case "$1" in
start)
echo -n "Starting $DESC: "
start-stop-daemon --start --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \
--exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
start-stop-daemon --stop --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \
--exec $DAEMON
echo "$NAME."
;;restart|force-reload)
echo -n "Restarting $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/usr/local/nginx/logs/$NAME.pid --exec $DAEMON
sleep 1
start-stop-daemon --start --quiet --pidfile \
/usr/local/nginx/logs/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
reload)
echo -n "Reloading $DESC configuration: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /usr/local/nginx/logs/$NAME.pid \
--exec $DAEMON
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
exit 1
;;
esacexit 0
sudo chmod +x /etc/init.d/nginx
Add it to the default run levels:
sudo /usr/sbin/update-rc.d -f nginx defaults
Create folder layout:
sudo mkdir /usr/local/nginx/sites-available
sudo mkdir /usr/local/nginx/sites-enabledChange the nginx.conf file:
sudo vi /usr/local/nginx/conf/nginx.conf
to:
user www-data www-data;
worker_processes 4;events {
worker_connections 1024;
}http {
include mime.types;
default_type application/octet-stream;sendfile on;
tcp_nopush on;
tcp_nodelay off;
keepalive_timeout 5;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;include /usr/local/nginx/sites-enabled/*;
}
Next add a
proxy.conffile:sudo vi /usr/local/nginx/conf/proxy.conf
# 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_buffers 32 4k;
And start Ngninx:
sudo /etc/init.d/nginx start
- Get files for Apache2:
sudo apt-get install apache2 libapache2-mod-wsgi
Modify
ports.confsudo vi /etc/apache2/ports.conf
with
NameVirtualHost 127.0.0.1:80
Listen 127.0.0.1:80Need to modify
apache2.confsudo vi /etc/apache2/apache2.conf
Change
KeepAliveto:# KeepAlive On
KeepAlive OffThen restart:
sudo apache2ctl restart
- Create a virtual host file for your site with nginx:
sudo vi /usr/local/nginx/sites-available/example.com
and add the following where 255.255.255.255:80 should be replaced with the correct IP:
server {
listen 255.255.255.255:80;
server_name www.example.com;
rewrite ^/(.*) http://example.com/$1 permanent;
}
server {
listen 255.255.255.255:80;
server_name www.example.com example.com;access_log /home/django/domains/example.com/log/access.log;
error_log /home/django/domains/example.com/log/error.log;location / {
proxy_pass http://127.0.0.1:80/;
include /usr/local/nginx/conf/proxy.conf;
}location /media/ {
root /home/django/domains/example.com/public/;
expires 1d;
}
}
sudo ln -s /usr/local/nginx/sites-available/example.com /usr/local/nginx/sites-enabled/example.com
- Add some
djangofolders:
sudo usermod -a -G www-data django
sudo usermod -a -G www-data bob
su django
mkdir domains
chgrp -R www-data /home/django/domains
chmod -R 2750 /home/django/domains
mkdir .python-eggs
chown django:www-data .python-eggs
chmod g+w .python-eggs/
cd /home/django/domains
mkdir example.com
mkdir -p example.com/{public,log}
mkdir example.com/public/media
chown -R django:www-data example.com
exit
sudo rm /etc/apache2/sites-enabled/000-default
sudo rm /usr/local/nginx/sites-enabled/default
sudo /etc/init.d/nginx stop
sudo /etc/init.d/nginx start
sudo apache2ctl graceful - Install some general libraries
sudo apt-get install mercurial git-core curl
sudo apt-get install build-essential python-dev python-setuptools python-psycopg2sudo easy_install pip
sudo pip install virtualenv
sudo pip install virtualenvwrapper
su django
cd
mkdir virtualenv
chgrp -R www-data virtualenv
vi .bashrc
“export WORKON_HOME=$HOME/virtualenv
source /usr/bin/virtualenvwrapper_bashrc”
source .bashrc
cd
virtualenv –no-site-packages –unzip-setuptools envName - Create a Django project (virtualenvwrapper might be useful here):
/home/django/virtualenv/envName/bin/python /home/django/virtualenv/envName/bin/django-admin.py startproject myProject
- Link admin/media with public/media/admin and change settings.py
ln -s /home/django/virtualenv/envName/lib/python2.5/site-packages/django/contrib/admin/media /home/django/domains/example.com/public/media/admin
Then update the ADMIN_MEDIA_PREFIX setting in your myProject/settings.py file :
vi /home/django/domains/example.com/myProject/settings.py
It should look like:
#ADMIN_MEDIA_PREFIX = ‘/media/’
ADMIN_MEDIA_PREFIX = ‘/media/admin/’ - Create a database:
sudo su postgres
createuser -P pg_substanceis
# should not be a superuser
# should not be able to create databases
# should not be able to create more new roles
createdb –encoding=UNICODE db_example -O pg_example
exitvi /home/django/domains/example.com/myProject/settings.py
and add in the details:
DATABASE_ENGINE = ‘postgresql_psycopg2′
DATABASE_NAME = ‘db_example’
DATABASE_USER = ‘pg_example’
DATABASE_PASSWORD = ‘123456789′
DATABASE_HOST = ”
DATABASE_PORT = ”Then just sync the database to check these settings:
~/domains/virtualenv/envName/bin/python myProject/manage.py syncdb
- Create a wsgi file for the project:
sudo vi /home/django/domains/example.com/myProject/myProject.wsgi
And add the following:
ALLDIRS = ['/home/django/virtualenv/envName/lib/python2.5/site-packages']
# note that the above directory depends on the locale of your virtualenv,
# and will thus be *different for each project!*
import os
import sys
import siteprev_sys_path = list(sys.path)
for directory in ALLDIRS:
site.addsitedir(directory)new_sys_path = []
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path# this will also be different for each project!
sys.path.append('/home/django/domains/example.com/myProject/')os.environ['PYTHON_EGG_CACHE'] = '/home/django/.python-eggs'
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
- Create a VirtualHost file for Apache:
sudo vi /etc/apache2/sites-available/example.com
Add the VirtualHost definition:
ServerName www.example.com
ServerAlias example.com
Order deny,allow
Allow from all
LogLevel warn
ErrorLog /home/django/domains/example.com/log/apache_error.log
CustomLog /home/django/domains/example.com/log/apache_access.log combinedWSGIDaemonProcess example.com user=www-data group=www-data threads=25
WSGIProcessGroup example.com
WSGIScriptAlias / /home/django/domains/example.com/myProject/myProject.wsgi
Then just enable it and restart Apache2 – you should see the Django debug screen:
sudo ln -s /etc/apache2/sites-available/example.com /etc/apache2/sites-enabled/example.com
sudo apache2ctl graceful - Some security: take a look at some StricterDefaults. By default /dev/shm is mouted read/write but on servers it should be read only as some exploits may use it. Edit the /etc/fstab file to include the following:
sudo vi /etc/fstab
tmpfs /dev/shm tmpfs defaults,ro 0 0
Create a pip installation file e.g. ‘envName_env.txt‘:
#Django
Django>=1.1#PIL
http://effbot.org/downloads/Imaging-1.1.6.tar.gz# egenix-mx-base
# Caused an error with pip: "--single-version-externally-managed"
#http://downloads.egenix.com/python/egenix-mx-base-3.1.2.tar.gz# psycopg2
http://initd.org/pub/software/psycopg/psycopg2-2.0.12.tar.gz
pip -E envName install -r envName_env.txt
./envName/bin/easy_install egenix-mx-base