Debian 7 (Wheezy) Deployment Guide

This section covers deploying the website on Debian 7(Wheezy). It assumes you have a working apache configuration and are logged in as thefec.

Install & Configure PostgreSQL

Start by installing the postgreSQL server & client. Development libraries are required for the python postgreSQL library:

$ sudo apt-get install postgresql postgresql-server postgresql-server-dev-9.1

Next, become the postgres user and create a new database and user:

$ sudo su - postgres
$ createuser -DERPS thefec      # No DB/user creation privleges, not a superuser, encrypt the password
$ createdb fec_website -O thefec
$ logout

Install Memcached

Memcached is used for caching. All you need to do is install it to get it working, it will automatically start a server at 127.0.0.1:11211:

$ sudo apt-get install memcached

Enable Wheezy Backports & Install the LESS Compiler

lessc takes LESS source files and converts them to CSS. To get the package in Debian 7, we need to enable the wheezy-backports repository. To do this, add the following line to the end of /etc/apt/sources.list:

deb http://http.debian.net/debian wheezy-backports main

Then you can update your package list & install lessc:

$ sudo apt-get update
$ sudo apt-get -t wheezy-backports install node-less

Install & Create Python Virtual Environment

A virtual environment will let us separate our dependencies from the system’s python libraries:

$ sudo apt-get install python-virtualenv
$ virtualenv ~/WebsiteEnv

We’ll create a bash script at ~/load_website_env.sh to set environmental variables that configure the website(database name, password, secret key, etc.):

# ~/load_website_env.sh
source ~/WebsiteEnv/bin/activate

export DB_NAME='fec_website'
export DB_USER='thefec'
export DB_PASS=YOUR_PASSWORD

export ALLOWED_HOST='www.thefec.org'
export DJANGO_SECRET_KEY=YOUR_SECRET_KEY
export DJANGO_SETTINGS_MODULE='fec.settings.production'
export CACHE_PREFIX='FECprod'

Since this contains our database user’s password, we’ll make sure only we can run/read/write it:

$ chmod 700 ~/load_website_env.sh

Download & Setup Application

First we’ll need git to pull the source code and some image libraries:

$ sudo apt-get install git libjpeg-dev libfreetype6-dev

Activate our virtual environment, grab the source & install the python dependencies:

$ source ~/load_website_env.sh
$ cd ~
$ git clone http://bugs.sleepanarchy.com/fec.git ~/website
$ cd ~/website
$ pip install -r requirements/base.txt

Create the database schema and load the initial data if you have any:

$ cd ~/website/fec
$ ./manage.py migrate
$ ./manage.py loaddata ~/full_dump.json

Collect the static files & link it to our public HTML directory:

$ ./manage.py collectstatic
$ ln -s ~/website/fec/static ~/htdocs/static

Install & Configure Python Server

Dynamic requests will be served by the uWSGI server and proxied by apache. Static files like images, CSS and JavaScript will be served by apache.

Start by installing uWSGI:

$ sudo apt-get install uwsgi uwsgi-plugin-python

Note

You may want a newer version of uWSGI for page caching & gzipping support. There is no uWSGI package in wheezy-backports so you’ll have to build the packages yourself. That’s out of the scope of this guide, you should refer to the SimpleBackportCreation Page on the Debian Wiki. Once you’ve built the packages and have them on your server, install them using dpkg along with some dependencies for gzipping & uWSGI:

$ sudo apt-get install libpcre3-dev libz-dev
$ sudo apt-get -t wheezy-backports install libzmq3-dev
$ sudo dpkg -i libapache2-mod-uwsgi_2*.deb
$ sudo dpkg -i uwsgi-core_2*.deb
$ sudo dpkg -i uwsgi-plugin-python_2*.deb
$ sudo apt-get -f install

Add the following configuration to /etc/uwsgi/apps-available/fec-website.ini:

[uwsgi]
uid = thefec
gid = www-data
chdir = /home/thefec/website/fec

plugin = python2,transformation_gzip
pythonpath = /home/thefec/WebsiteEnv/lib/python2.7/site-packages/
pythonpath = /usr/lib/python2.7
virtualenv = /home/thefec/WebsiteEnv
no-site=True

socket = 127.0.0.1:3032
master = true
workers = 4
max-requests = 5000
vacuum = True

pidfile = /tmp/fec-website.pid
touch-reload = /tmp/fec-website.touch

env = DJANGO_SETTINGS_MODULE=fec.settings.production
env = DJANGO_SECRET_KEY=YOUR_SECRET_KEY
env = DB_NAME=fec_website
env = DB_USER=thefec
env = DB_PASS=YOUR_PASSWORD
env = ALLOWED_HOST=www.thefec.org
env = CACHE_PREFIX=FECprod
wsgi-file = /home/thefec/website/fec/fec/wsgi.py

# uWSGI v1.9+ only
# route to gzip if supported
route-if = contains:${HTTP_ACCEPT_ENCODING};gzip goto:mygzipper
route-run = last:

route-label = mygzipper
route = ^/$ gzip:

Link the file to apps-enabled to enable it, restart uwsgi, then touch the touch-file to restart the python server:

$ sudo ln -s /etc/uwsgi/apps-available/fec-website.ini /etc/uwsgi/apps-enabled/
$ sudo service uwsgi restart
$ touch /tmp/fec-website.touch

Configure Virtual Host

First we need to install the apache module for uWSGI:

$ sudo apt-get install libapache2-mod-uwsgi

Then add the following configuration to /etc/apache2/sites-available/thefec.org.conf:

<VirtualHost 72.249.12.147:80>
    ServerName www.thefec.org

    DocumentRoot /home/thefec/website/fec

    ErrorLog /home/thefec/logs/error_log
    CustomLog /home/thefec/logs/access_log common

    Alias /static /home/thefec/htdocs/static
    <Directory /home/thefec/htdocs/static>
        Options Indexes FollowSymLinks MultiViews
        allow from all
        AllowOverride All
    </Directory>

    # Redirect requests to the python server
    <Location "/">
        Options FollowSymLinks Indexes
        SetHandler uwsgi-handler
        uWSGISocket 127.0.0.1:3032
    </Location>
    # Except for requests to /static/
    <Location /static>
        SetHandler none
        allow from all
    </Location>

    # Cache all the things
    ExpiresActive On
    ExpiresByType text/html "access plus 5 minutes"
    ExpiresByType text/css "access plus 10 years"
    ExpiresByType text/javascript "access plus 10 years"
    ExpiresByType application/x-javascript "access plus 10 years"
    ExpiresByType text/javascript "access plus 10 years"
    ExpiresByType application/javascript "access plus 10 years"
    ExpiresByType image/jpg "access plus 10 years"
    ExpiresByType image/gif "access plus 10 years"
    ExpiresByType image/jpeg "access plus 10 years"
    ExpiresByType image/png "access plus 10 years"
    ExpiresByType image/x-icon "access plus 10 years"
    ExpiresByType image/icon "access plus 10 years"
    ExpiresByType application/x-ico "access plus 10 years"
    ExpiresByType application/ico "access plus 10 years"

    # Gzip all the things
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css
        AddOutputFilterByType DEFLATE application/x-javascript application/javascript image/x-icon
    </IfModule>

    # Seperate browser caching for gzip-encoded things
    <FilesMatch ".(js|css|xml|gz|html)$">
        Header append Vary: Accept-Encoding
    </FilesMatch>
</VirtualHost>


# Redirect other domains to www.thefec.org, preserving the URL path
<VirtualHost 72.249.12.147:80>
    ServerName thefec.org
    ServerAlias *.thefec.org
    ServerAlias thefec.skyhouseconsulting.com
    Redirect permanent / http://www.thefec.org/
</VirtualHost>

Then enable the site and restart apache:

$ sudo a2ensite thefec.org
$ sudo apache2ctl -k restart

The site should now be visible at http://www.thefec.org

Setup Cronjobs

We’ll setup cron to run two scripts on a regular basis. One script will backup the database and uploads while the other will compress & optimize uploaded images.

First install the optimizing tools:

$ sudo apt-get install optipng jpegoptim

Now make directories for the scripts & backups to live in:

$ mkdir ~/bin ~/backups

Create a script called backup_website.sh in ~/bin containing the following:

#!/usr/bin/env bash
# ~/bin/backup_website.sh
mv ~/backups/database.gz ~/backups/database.gz.2
pg_dump fec_website | gzip > ~/backups/database.gz

mv ~/backups/uploads.tar.gz ~/backups/uploads.tar.gz.2
tar -cpzf ~/backups/uploads.tar.gz ~/website/fec/static/media/

This will keep 2 days worth of backups in ~/backups.

Now create optimize_website_images.sh in ~/bin containing the following:

#!/usr/bin/env bash
# ~/bin/optimize_website_images.sh
find ~/htdocs/static/media -type f -iname "*.png" -exec optipng -o7 {} \;
find ~/htdocs/static/media -type f -iname "*.jpeg" -o -iname "*.jpg" -exec jpegoptim -t --all-progressive -s {} \;

Make sure to mark them as executable:

chmod +x ~/bin/backup_website.sh ~/bin/optimize_website_images.sh

We’ll set the backup script to run daily & the image optimizing to run weekly. Edit the enabled cronjobs by running crontab -e (or something like EDITOR=vim crontab -e) and add the following lines:

# Backup Website Database & Uploads
@daily ~/bin/backup_website.sh > /dev/null 2>&1

# Optimize Images Uploaded to the Website
@weekly ~/bin/optimize_website_images.sh > /dev/null 2>&1