Django deploy: problems with limited hosting
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
- To properly install the environment.
- Set up this two files (cgi and .htaccess).
- Take care with node tools (bower, npm, less, node_modules...).
- Most of times django-compressor is a PITA in shared hostings.
- Take double care with static/media settings.
- Set the proper permissions in the .cgi file.
- Having a bit of patience and access to stackoverflow is to have it a half fixed ;).