Django
From DreamHost
Django is a framework for Python (in the same way rails is a framework for Ruby). See the official website and the official book for more details. Django can be deployed via FastCGI on dreamhost.
Contents |
Considerations
If Django is crucial to your site, you may wish to consider another host since Dreamhost does not officially support Django. In the past, some users have reported reliablity problems; however, others have had no problems.
Another important consideration is that if you are planning on developing a heavily used application, a shared environment will probably not suffice due to the heavy CPU load. Enable CPU reporting for your user and keep an eye on your usage. Extremely heavy usage (200+ minutes) is an indication that you should look into tuning your site. Any site that severely disrupts service for other users could be disabled without warning.
Prerequisites
- FastCGI must be enabled for the site on which you intend to run Django.
- Enable SSH access and request the default bash shell.
- You'll need to use Subversion to download the latest version of Django's source code. (It should be installed by default. Use the command 'which svn' to ensure that Subversion is already installed.)
- Make sure that your web site works without Django and you can navigate subdirectories and see files without any problems. If you are getting the "503 Service Temporarily Unavailable" error, please read Referer Gotcha before using Django.
Setup
These instructions are based in part on Jeff Croft's article. It is assumed that you have a hosted domain such as www.mydomain.com and can create a subdomain to host media files. These instructions should work just as well if you'd rather install Django on a subdomain.
We will use the following for username, domain, and project. These should be replaced with your own details.
username = myuser domain = mydomain.com media domain = media.mydomain.com project = myproject
- Enable 'FastCGI Support' on mydomain.com in the Dreamhost control panel (Domains -> Manage Domains -> Web Hosting Column, Edit -> Fast CGI Support?)
- Create a media subdomain in Dreamhost control panel, media.mydomain.com
- Create a directory in your home directory to contain your Django projects:
$ mkdir django_projects
- Download the latest Django source code
$ svn co http://code.djangoproject.com/svn/django/trunk/ django_src
Note: If you have previously followed the Python documentation you can run the following and not have to add anything to the PATH or follow the next 2 steps.
easy_install django_src
- Otherwise, without easy_install, edit .bash_profile to add Django to your path and python path
export PATH=$PATH:$HOME/django_src/django/bin export PYTHONPATH=$PYTHONPATH:$HOME/django_src:$HOME/django_projects
- Reload .bash_profile
$ source .bash_profile
- Link admin_media to your media domain from the Django source code
$ ln -s $HOME/django_src/django/contrib/admin/media $HOME/media.mydomain.com/admin_media
- Start a new project in django_projects
$ cd django_projects $ django-admin.py startproject myproject $ chmod 600 myproject/settings.py
- Edit ~/django_projects/myproject/settings.py. SQLite is perfectly usable for test sites. If you'd rather use MySQL then just edit the settings appropriately here.
DATABASE_ENGINE = 'sqlite3' DATABASE_NAME = '/home/myuser/django_projects/myproject/myproject.db' TIME_ZONE = 'US/Pacific' MEDIA_ROOT = '/home/myuser/media.mydomain.com/' MEDIA_URL = 'http://media.mydomain.com/' ADMIN_MEDIA_PREFIX = 'http://media.mydomain.com/admin_media/' Add django.contrib.admin to INSTALLED_APPS
- Change to webroot directory for mydomain.com and download fcgi.py
$ cd ~/mydomain.com $ wget http://svn.saddi.com/py-lib/trunk/fcgi.py
- Edit ~/mydomain.com/dispatch.fcgi
#!/usr/bin/python2.4 import sys sys.path += ['/home/myuser/django_src'] sys.path += ['/home/myuser/django_projects'] from fcgi import WSGIServer from django.core.handlers.wsgi import WSGIHandler import os os.environ['DJANGO_SETTINGS_MODULE'] = 'myproject.settings' WSGIServer(WSGIHandler()).run()
- Make ~/mydomain.com/dispatch.fcgi and ~/mydomain.com/fcgi.py executable. It is important to make sure that they are not group writable, otherwise some dreamhost servers will not be able to run the scripts.
$ chmod 755 ~/mydomain.com/dispatch.fcgi ~/mydomain.com/fcgi.py
- Edit ~/mydomain.com/.htaccess
RewriteEngine On RewriteBase / RewriteRule ^(dispatch\.fcgi/.*)$ - [L] RewriteRule ^(.*)$ dispatch.fcgi/$1 [L]
- Initialize the DB for your project and create an admin user
$ ~/django_projects/myproject/manage.py syncdb
- Load http://www.mydomain.com/ in a browser and you should see the "It worked!" page.
- Edit ~/django_projects/myproject/urls.py and uncomment the admin line.
- Touch the dispatch.fcgi to reload the code
$ touch ~/mydomain.com/dispatch.fcgi
- Load http://www.mydomain.com/admin/ in a browser and you should see the admin login page.
Troubleshooting
Run dispatch.fcgi from the commandline
It may help to find the cause of problems by manually running dispatch.fcgi from the commandline.
./dispatch.fcgi
Django should output it's HTML to your shell. You can safely ignore "WSGIServer: missing FastCGI param" errors.
500 errors and Incomplete Header in logs
Dreamhost apparently runs a background process to kill zombie processes. This can cause issues for FastCGI dispatchers (like the one needed to get Django working). Because of this, Dreamhost updated their zombie-killer to avoid dispatch.fcgi; in other words, if you don't rename the file mysite.fcgi to dispatch.fcgi your site will not work. The file name is different than the one mentioned on various other tutorials.
You must also use#!/usr/bin/python2.4as the first line of dispatch.fcgi. Using #!/usr/bin/env python2.4 confuses the procwatch background process.
You may also get this error if dispatch.fcgi is group-writable (use chmod 755 dispatch.fcgi).
AttributeError: type object 'unicode' has no attribute 'decode'
Calling manage.py using Python 2.4 resolves this problem:
$ python2.4 manage.py
A better way
Mod_fastcgi on apache is, frankly, appalling. There are two alternatives that have been suggested and you can vote on:
- Use mod_fcgid instead of mod_fastcgi.
- Add mod_python support.
- Add mod_wsgi support for Python web apps.
Misc.
- A lot of errors can be fixed by updating django and flup to the latest versions through svn.
- Make sure FastCGI is enabled for your site in the Dreamhost panel.
- Double-check your usernames, passwords, database names, and hostnames in the settings file.
- Verify that FastCGI is working. Create a file named hello.fcgi with the following text.
#!/usr/bin/python2.4
from flup.server.fcgi import WSGIServer
def test_app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
yield 'Hello, world!\n'
WSGIServer(test_app).run()
Make sure to set the correct permissions.
chmod 755 hello.fcgi
- NOTE: For this to work, you'll still need to load up your environment (I.E. that pythonpath you'll be setting in the tutorials below). Just to verify fastcgi works, just copy the "flup" directory from your django_src (or wherever you decide to store that) over to the directory you're testing from.
Then try to load http://django.mydomain.com/hello.fcgi.
- Once you've proven that FastCGI is working, check your sys.path settings in dispatch.fcgi. Make sure you added the directory that contains "django", and not the django directory itself! In other words, put /home/username/django_src in your sys.path, not /home/username/django_src/django.
- If you make changes to the code, such as working through the official tutorials, and they don't seem to work, make sure to kill any existing python processes and reload the page.
pkill python
- Also, in addition to killing the python processes, you also have to tell FastCGI that a file/code has been changed. This is pretty simple, just reupload dispatch.fcgi, or edit the file, so that the timestamp on the file will change. When Apache sees the file has been updated, it will restart your Django application for you. You can use the touch command to update the file's timestamp. Just go to the site directory, where you placed your dispatch.fcgi file and use the touch command:
touch dispatch.fcgi
mod_rewrite
To be able to login and actually use the django admin pages you will need to set up a mod_rewrite rule in your .htaccess file.
If you want everything to be run by dispatch.fcgi, you can use the following set of rewrite rules. Order is important!
RewriteEngine On RewriteBase / RewriteRule ^(media/.*)$ - [L] RewriteRule ^(appmedia/.*)$ - [L] RewriteRule ^(dispatch\.fcgi/.*)$ - [L] RewriteRule ^(.*)$ dispatch.fcgi/$1 [L]
All directories and files not managed by Django, should go before the last line. E.g., if you want to use Analog 6.0 web stats application (supplied by DreamHost), you should add following three lines before Django instruction (taken from Mod_rewrite):
RewriteCond %{REQUEST_URI} ^/stats/(.*)$ [OR]
RewriteCond %{REQUEST_URI} ^/failed_auth.html$
RewriteRule ^.*$ - [L]
For example, if you want to add favicon.ico, which can be actually located in appmedia/favicon.ico:
RewriteRule ^(favicon\.ico)$ appmedia/favicon.ico [L]
And so on.
1st part of rewrite rule is a regex pattern to be matched. 2nd part is a replacement ("-" means don't rewrite the url). 3rd part is a command ("L" means "last" => "this is the last rule, quit rewriting after successful application of this rule").
Media Files
For the admin pages to be able to access the correct CSS and JavaScript files, you'll need to set up a media directory.
ln -s $HOME/django_src/django/contrib/admin/media $HOME/django.mydomain.com/admin_media
Now surfing to http://django.myproject.com/media/ should give you a directory listing:
css img js
(It is possible to rename the effective name of the media directory for the admin app through a conf setting. This will be required if you decide that you want your own media in a subdirectory named 'media'.)
Sessions
If you're having trouble with sessions working as expected, try using file-based sessions. By default Django stores session data in the database, but in my experience this does not work with dreamhost. I don't know why, but would guess that it has something to do with the way they have the database cache setup.
Performance Improvements
Shared environment forces users to use some tricks to improve overall performance of web applications. Django provides many ways to do it:
- Use Django's excellent cache facilities --- make sure your web application uses Filesystem caching or Database caching. In memory caching doesn't work very well in shared environments. And we don't have memcached yet.
- Use appropriate Django's middleware --- specifically you should check out Cache middleware (described in Cache documentation), GZip middleware to improve bandwidth utilization (works well with cache to amortize expenses on data compression), and Conditional Get middleware to reduce bandwidth even more (works well with cache).
- Enable caching of all your static files.
- Enable compression of compressible static files (like .css, .js, .html, and so on).
The latter two can be achieved by placing a specially crafted .htaccess in top static file directories (like media/, appmedia/). The one I use is here:
ExpiresActive on
ExpiresDefault "access plus 15 minutes"
ExpiresByType image/gif "access plus 1 hours"
ExpiresByType image/png "access plus 1 hours"
ExpiresByType image/jpeg "access plus 1 hours"
ExpiresByType image/x-icon "access plus 1 hours"
ExpiresByType application/x-javascript "access plus 15 minutes"
ExpiresByType text/css "access plus 1 hours"
SetOutputFilter DEFLATE
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE\s6 no-gzip
BrowserMatch \bMSIE\s7 !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png|pdf|swf|ipk)$ no-gzip dont-vary
Header append Vary User-Agent env=!dont-vary
Warning! The above file works only for Apache 2.0! If you still use Apache 1.3, please talk to DreamHost support to switch you over to Apache 2.0.
Helpful Links
Gordon Tillman - Django and Dreamhost

