A guide to django on dreamhost (and django deployment in general) and my experience so far
Dreamhost is one of the few large non-VPS shared hosting companies that is currently Django compatible. I’ve found that It hasn’t been too hard to set up either. This little guide assumes you’ve read this guide and is mainly just caveats and tips followed by a bit of personal experience on reliability.
MySQL
This is easy. First go to your dreamhost panel. Next, select goodies, then manage MySQL. Now create a database, I’d recommend Django as a name. Then, a hostname and user for the database, the hostname could be something like mysql.yourdomain.com, the user, whatever you want. Now in your settings.py change the DATABASE_* options to something like these:
DATABASE_ENGINE = 'mysql'
DATABASE_NAME = 'django'
DATABASE_USER = 'user'
DATABASE_PASSWORD = 'pass'
DATABASE_HOST = 'mysql.yourdomain.com'
DATABASE_PORT = '3306'
Under Mail > Manage Email in the dreamhost panel you need to set up an email with a mailbox. At first I was making the fatal error of only having one email that just redirects email. Then enter the info in settings.py
EMAIL_HOST = 'mail.yourdomain.com'
EMAIL_HOST_USER = 'addy@yourdomain.com'
EMAIL_HOST_PASSWORD = 'password'
Statistics
Dreamhost normally gives some rather nice statistics on all of your domains at /stats/. You lose this when you get Django to handle the whole domain. Lets take a wee look at the .htaccess’ file:
AddHandler fastcgi-script .fcgi RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ django.fcgi/$1 [QSA,L]
Currently everything everything except for files it being handled by Django. If you have Django serve for the whole of your domain you lose /stats/ as this isn’t a file. We want to make another exception, especially for /stats/. We want to do the same thing for failed authentication. We can put an extra rule before the Django one like so.
RewriteCond %{REQUEST_URI} ^/stats/(.*)$ [OR]
RewriteCond %{REQUEST_URI} ^/failed_auth.html$
RewriteRule ^.*$ - [L]
This rule tells Apache to just keep these two URLs as they are and not do anything with Django.
Keeping in sync with the development version
Often a website will have more than one revision. Maybe you’ll find there are some bugs in your website. Maybe you’ll want to add some new features. My recommendation here is to start a subversion repository for your project. Actually doing this is out of the scope of this guide (but there’s an excellent book) but here are some tips.
- Have a trunk and then periodically copy it to a tag and do a checkout of that tag at the dreamhost end.
- Keep the media in a directory within the source control and make a symbolic link to it from the actual website directory. Have uploads as a real directory under the domain directory and shove all the uploads there, otherwise you’ll get loads of clutter in your working copy.
- Tell subversion to ignore settings.py (as well as *.pyc) so that you can set up individual settings for your development and production environments.
Making backups
Dreamhost backup all of your stuff if bad stuff were to go down over there. However, personally, I feel safer having backed up stuff myself as well.
SSH into dreamhost and make a file called db_dump in ~/ and have it contain
mysqldump --opt -u user -ppass -h mysql.yourdomain.com django > ~/db_backups/django.sql
as well as a variation on that line non-django databases you might have. Run chmod 755 db_dump; mkdir db_backups then crontab -e, now enter something like:
MAILTO="your@email.com"
00 09 * * * /home/you/backup_dbs
Note that I’ve chosen 9:00 daily. Dreamhost is at -700. I am at either 000 or +100 depending on day light savings. This means that I am either 7 or 8 hours ahead. This means that while this script is dumping the database it is 4 or 5 in sunny York. Do the same calculations for yourself if you’re in a non-dreamhost timezone.
Do this next bit on a local machine. If you’re using windows start by downloading wget and putting it in your path. Make a file called backup_dh (or backup_dh.bat in windows) in somewhere and have it contain something like
cd dh_backup
wget ftp://user:pass@yourdomain.com/db_backups/*
cd yoursite1_uploads
wget ftp://user:pass@yourdomain.com/yoursite1.com/uploads/*
cd ..
cd yoursite2_uploads
wget ftp://user:pass@yourdomain.com/yoursite2.com/uploads/*
cd ..
Run chmod 755 backup_dh (*nix only), mkdir dh_backup; cd dh_backup; mkdir yoursite1_uploads; mkdir yoursite2_uploads.
Then on *nix crontab -e, enter (or append) something like:
30 17 * * * /home/you/backup_dh
On windows Start > Control Panel > Scheduled Tasks > Add Scheduled Task > Next > Browse… > look for backup_dh.bat > Select daily > Choose a time - for me it’s 17:30 > Enter your username and password > Finish.
Notice that this downloading is scheduled to happen at 5:30 in sunny York, 1/2 to 1 1/2 hours since dreamhost did its database dump,, calculate a similar thing yourself.
Optimising so dreamhost don’t kill you
Officially you’re safe with dreamhost if you use under 60 cpu minutes (that’s 3600 seconds). Anything over that will be evaluated on a case by case situation. You should take a look at http://yourdomain.com/stats/resources/yourunixname.sa.analysed.0 and see if you are getting too near that. If you are, don’t despair, luckily Django comes with a built cache framework. A few pointers:
- Make sure whatever you do, to turn on CACHE_MIDDLEWARE_ANONYMOUS_ONLY, otherwise the admin will start playing silly buggers.
- I would choose local memory caching for any smallish sites. Otherwise use db caching (which, from what I understand should always be just as fast as file-system caching on dreamhost as both files and database is stored on machines other than that running the Apache instance).
Also have a dive into python has an amazing chapter on performance tuning.
Thoughts
So far I’ve been fine, but I really haven’t got that much traffic yet (not even on my mum’s fantastic writing site). However, I’m sure that will all change when I launch my new web application idea thing. So I’ll report back on this later.
Finally…
I’m sure I’ve made some mistakes here so please comment and correct me. Also please comment if you’re having trouble setting up Django on dreamhost.
I also made a crontab to pkill dispath.fcgi every two hours.
It works well.
[…] My mum’s site is set up using Django on Apache running in a shared hosting environment with Dreamhost as laid out in the official documentation and my own write-up. I was having a few problems with it. The problem was an intermittent, unpredictable error about a third of the time which lead to /internal_error.html being displayed. This means that Django wasn’t even starting or was starting and failing very early on because if it was starting it would display the 500.html template instead of /internal_error.html. I took a look at the error.log and sure enough there were errors in the following format for each failed request: [time and date] [error] [client xxx.xxx.xxx.xxx] (104)Connection reset by peer: FastCGI: comm with server “/home/grimboy/example.com/django.fcgi” aborted: read failed [time and date] [error] [client xxx.xxx.xxx.xxx] FastCGI: incomplete headers (0 bytes) received from server “/home/grimboy/example.com/django.fcgi” […]
Is there a way to run some piece of django code repeatedly, like every one hour?
Cheers,
Altu
Yeah, cron.
If you are on dreamhost you can go to https://panel.dreamhost.com/index.cgi?tree=goodies.cron& otherwise login via shell and do crontab -e
The alternative is to write a middleware that if the difference between the current time and the last running time is more than an hour then run the desired code. But cron is a much easier, established solution.