####A clean project of a Django web-framework running on Heroku with static files served from Amazon S3, attempting to follow the 12-factor design pattern.
Django is a web framework that simplifies the work required to make a web app in python.
Heroku is touted as one of the best 'platform as a service' providers. You can host apps >without having to get too involved with installing your own serving software etc.
Amazon S3 is a quick, cheap way to host static files (images, js, css etc. that doesn't >change) because heroku doesn't do that.>
This collection is touted as one fo the best ways to serve up django apps, that's free initially and can scale up easily. This repo gets it up and running quickly and securely.
This setup using the excellent virtualenvwrapper to isolate the installed dependencies and environmental variables.
- heroku account and toolbelt installed on your computer
- git installed
- virtualenv and virtualenvwrapper
- an Amazon Web Services account
-
Make a new virtualenv and clone this repo
mkvirtualenv [name-of-your-project] git clone https://github.com/jordn/heroku-django-s3 [name-of-your-project] cd [name-of-your-project]
-
Install all the dependencies (django, psycopg2, gunicorn, dj-database-url, boto and django-storages) with pip. These are specified in requirements.txt (if you edit this file to remove the version numbers it will install the latest versions available)
pip install -r requirements.txt
-
All the private or environment-dependant settings in
settings.py
are kept as environmental variables. We need to set these variables everytime we enter this virtual environment. virtualenvwrapper does this with apostactivate
script. Edit this file:vim $VIRTUAL_ENV/bin/postactivate
Add the following variables:
#!/bin/zsh # This hook is run after this virtualenv is activated. # Django database export DATABASE_URL=sqlite:////[path to where you would like to store the sqlite (easiest) database for local dev]/sqlite.db # Django static file storage export AWS_STORAGE_BUCKET_NAME=[YOUR AWS S3 BUCKET NAME] export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX # Django debug setting export DJ_DEBUG=True export DJ_SECRET_KEY=[Any random sequence of 40ish characters - django uses it for added security]
-
Reopen the virtualenv to run this script
workon [name-of-your-project]
-
Everything should now work for local development to check we can see the admin pages at
http://127.0.0.1:8000/admin/
python manage.py syncdb ... python manage.py runserver
-
Create the app on heroku and push everything there. Heroku will detect it's a python app and install everything in requirements.txt (update this file with
pip freeze > requirements.txt
)heroku create [name-of-your-project] ... git push heroku master ...
-
The heroku django needs the environmental variables too (
DATABASE_URL
is already set on heroku) so we'll send over the values set locally:heroku config:add AWS_STORAGE_BUCKET_NAME=$AWS_STORAGE_BUCKET_NAME heroku config:add AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID heroku config:add AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY heroku config:add DJ_SECRET_KEY=$DJ_SECRET_KEY
You can turn debug on/off by changing the DJ_DEBUG setting (only do this if something has gone wrong. Note: static files aren't served from S3 in debug mode):
heroku config:add DJ_DEBUG=True
-
Should now be ready. Go and build that web app!
heroku run python manage.py syncdb heroku run python manage.py collectstatic ... heroku open
Go to http://[your-project-name].herokuapp.com/admin and you should see a CSS-styled admin login if it's all worked correctly.
Lastly, go into settings.py and change the trusted hosts to be specifically your domains (for added security)
ALLOWED_HOSTS = ['[your-project-name].herokuapp.com']
####Programs installed
- django
- psycopg2 (to be able to talk to postgreSQL databases)
- gunicorn (python HTTP server to use from heroku)
- dj-database-url (to use a URL environmental variable to reference the location of the database)
- django-storages (custom storage backends for django, best S3 support makes use of 'boto'...)
- Boto (Python interface to Amazon Web Services, simplifies the AWS connection to just the access keys)
####Changes Made
####settings.py
Removed
# 'django.contrib.sites'
add-on that can enable multiple sites to use the same back->end but confuses matters here.As part of the plan to make the settings.py file to be transferable and secure did the >following:
Make
DEBUG
an environmental variable by putting the following at the top of settings.py:import os # Added to help use env variables def env_var(key, default=None): """Retrieves env vars and makes Python boolean replacements""" val = os.environ.get(key, default) if val == 'True': val = True elif val == 'False': val = False return val DEBUG = env_var('DJ_DEBUG', False) #Unless env var is set to True, debug is off
SECRET_KEY
stored as asos.environ['DJ_SECRET_KEY']
environmental variable.`ALLOWED_HOSTS` accepting any `['.herokuapp.com']` subdomain. Only these domains can host the >site when `DEBUG = False`. User should **remember to change this to be most specific** Database settings are set by env var: ```python # Parse database configuration from $DATABASE_URL import dj_database_url DATABASES['default'] = dj_database_url.config(default=os.environ.get('DATABASE_URL')) # Honor the 'X-Forwarded-Proto' header for request.is_secure() SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
'admin'
and'admindocs'
enabled and'storages'
toINSTALLED_APPS
Added settings to store statics on S3
#Storage on S3 settings are stored as os.environs to keep settings.py clean if not DEBUG: AWS_STORAGE_BUCKET_NAME = os.environ['AWS_STORAGE_BUCKET_NAME'] AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID'] AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY'] STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage' S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME STATIC_URL = S3_URL
####urls.py
Uncommented lines 4, 5, 13 and 16 from urls to enable admin urls
####Procfile
Runs gunicorn process for heroku
####.gitignore
Ignores common ignorables for python and django development