Django/Heroku quickstart for existing applications
Getting a brand new Django application running on Heroku is fairly simple. There is a great tutorial for it on devcenter.heroku.com. I would recommend going through that, and getting it working. Here is my short version of their getting started notes, without the virtualenv and Django command stuff you probably already know.
wget -qO- https://toolbelt.heroku.com/install.sh | sh heroku login heroku create --stack cedar echo 'web: python manage.py runserver 0:$PORT' > Procfile heroku addons:add shared-database git push heroku master # if you're in a branch locally, you can git push -f heroku localbranch:refs/heads/master heroku run python manage.py syncdb heroku ps:scale web=1 heroku ps heroku logs
That should be enough to get a brand new Django app running. If you have an existing Django application, however, their documentation doesn't provide much guidance on common pitfalls.
First of all, you may need a mechanism to over-ride settings.py on the production Heroku instance. First, you can add an environment variable:
heroku config:add ENVIRONMENT=production
With that variable, you can easily create an over-ride for settings.py called settings_production.py:
# at the END of settings.py: import os ENVIRONMENT = os.environ.get('ENVIRONMENT', 'dev') # dev, production, qa, etc exec('from settings_%s import *' % ENVIRONMENT)
Heroku gives you a shared database for free. You can see the connect string on it with the heroku config command:
... DATABASE_URL => postgres://foobar:password@ec2-ip-address.amazonaws.com/instance ...
This would translate into the following in settings_production.py
DATABASES = { 'default': { 'ENGINE': 'postgresql_psycopg2', 'NAME': 'instance', 'USER': 'foobar', 'PASSWORD': 'password', 'HOST': 'ec2-ip-address.amazonaws.com', 'PORT': '', # leave blank } }
The Heroku directions for switching from Django's development web server to gunicorn don't work for Django 1.3, where there is no WSGI file. After adding gunicorn to requirements.txt, and 'gunicorn' to INSTALLED_APPS, I changed Procfile to the following:
web: python manage.py run_gunicorn -b 0.0.0.0:$PORT
Getting Django's staticfiles feature working was a little trickier. Heroku gives you a "ephemeral" file system, meaning that any changes you write to disk will not survive the next deploy, and may not even survive between heroku command-line sessions. This means that collectstatic must be run as part of the deploy, which you can also do in Profile:
web: python manage.py collectstatic --noinput; python manage.py run_gunicorn -b 0.0.0.0:$PORT
Lastly, I wanted gunicorn to (at least temporarily) serve up the static resources itself. To do that, you will need to add the following to your urls.py:
urlpatterns += patterns('', (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}), )
Heroku gives you SSL for free, at least when you're on *.herokuapp.com. The only tricky bit is that you need to tell Django which header to look at to determine if the original request was in SSL (Heroku will only speak plain HTTP to Django). Without this, any redirect from an HTTPS URL will direct the user back to HTTP. Just put the following in settings.py:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
Finally, I had to migrate my old data. If you're going from Postgres -> Postres, or MySQL -> MySQL, just use the herokup database restore tools. If you need to migrate from one to the other, things get a lot trickier. In my case, I ended up exporting to a JSON file, and re-importing. This was very buggy; I would not recommend it.