oscarmlage oscarmlage

Django deploy: problems with limited hosting

Written by oscarmlage on

Some months ago I had to deal with a Symfony2 project in a shared hosting (Spanish article) and now the big next deal is a similar task with Django.

The project is almost done and I have the hosting credentials, once I'm in I noticed that there is no chance to configure anything (Apache, WSGI or whatever) so I was a bit lost. Thanks to my Ailalelo's mates (they had lot of experience with this kind of situations) I found the proper configuration.

Hosting is django-ready, but the version they're running (1.4.2) is not the best choice, I want to install 1.6.x, the one I have used to develop the project. The other big requirement is virtualenv+pip to retrieve the packages I'm using.

Mainly I've solved it with two files, project.cgi and .htaccess.

project.cgi

The hosting structure is like many others, I have access to a homedir with the following directories:

myhome/
  logs/
  tmp/
  www/
    cgi-bin/
    index.html

Before to say Apache what to do with our project, let's install virtualenv and all the requirements, my choice is to put the environment out of the www/ directory:

myhome/
  env/
  logs/
  tmp/
  www/
    cgi-bin/
    project/
    index.html
$ virtualenv env
$ . env/bin/activate
$ pip install -r www/project/requirements/production.txt

Seems to be that apache's mod_cgi will process all the files you put in the cgi-bin directory, so we already know where to save our project.cgi. I have to tell apache to use my own virtualenv python, where the environment and the project are. And finally set some environment variables:

#!/home/myhome/env/bin/python

import os
from os.path import abspath, dirname
from sys import path

actual = os.path.dirname(__file__)
path.insert(0, os.path.join(actual, "..", "project/project"))
path.insert(0, os.path.join(actual, "..", "env"))

# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['PATH'] = os.environ['PATH'] + ':/home/myhome/www/project/node_modules/less/bin'
os.environ['SECRET_KEY'] = 'SECRETKEY'
os.environ['DJANGO_SETTINGS_MODULE'] = "project.settings.production"

from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")

Note that I modified the PATH because I have to be able to use less binary, required for django-compressor package. In this particular case my user was not allowed to install node/less in the system, so I had to install it locally, referencing the particular node_modules folder.

.htaccess

Now that Apache knows what to do, we should redirect almost all the incoming traffic to the cgi, so let's write some.htaccess rules:

AddHandler fcgid-script .fcgi
RewriteEngine On

RewriteRule ^static/(.*)$ project/project/static/$1 [L]
RewriteRule ^media/(.*)$ project/project/media/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ cgi-bin/project.cgi/$1 [QSA,L]

AddDefaultCharset UTF-8

The media/ and static/ dirs are redirected to the proper location, because they didn't work as is. Not much more to say with this file, it's easy to understand I think.

Remember