Jonatan
Posted on October 2, 2021
In this short tutorial, I will demonstrate how to deploy a Django project on Heroku while serving static files from your own domain.
Prerequisites:
- python (https://www.python.org/downloads/)
- Django (https://docs.djangoproject.com/en/3.2/topics/install/)
- virtualenv (https://virtualenv.pypa.io/en/latest/installation.html)
- pip (https://pip.pypa.io/en/stable/installation/)
- heroku-cli (https://devcenter.heroku.com/articles/heroku-cli)
You do not need to use virtualenv, but it is highly recommended to use an isolated environment for different projects. Another option to virtualenv, for deploying to Heroku, is pipenv.
Installing Django, virtualenv, pip and the heroku-cli on Ubuntu
sudo apt install python3
sudo apt install python3-django
sudo apt install python3-virtualenv
sudo apt install python3-pip
sudo snap install --classic heroku
Creating a Django project
We can now create our Django project named myproject
django-admin startproject myproject
Setting up your virtual environment
You now want to go to the root of your project and set up your virtual environment.
Navigate to your project
cd myproject
Make a virtual environment
virtualenv venv
Activate your virtual environment
source venv/bin/activate
Install Django in your virtual environment
pip install django
Creating a new Heroku project
We now want to create a new Heroku project.
heroku create
This will create a domain at https://example.herokuapp.com so select the project name to be the domain you want your project to be hosted at. (You can later add a custom domain).
Changing the secret key
First, we want to change the SECRET_KEY
to an environment variable, because we want to have a unique SECRET_KEY
in production that we don't push to version control.
SECRET_KEY = os.getenv('SECRET_KEY', 'change-in-production')
Now we can set our production environment variable with
heroku config:set SECRET_KEY=very-long-secret-key
We now need to set up static files and turn off DEBUG mode in production.
Setting up static files
We are going to use whitenoise to serve static files. First, we need to install it
pip install whitenoise
Next, we add the whitenoise middleware to the top of the middleware section
MIDDLEWARE = [
'whitenoise.middleware.WhiteNoiseMiddleware', # First in list
...
]
Next, we set up the path of our static files
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
We then install django_heroku to configure default values.
pip install django_heroku
We enable the django_heroku settings, but set staticfiles and allowed_hosts to False, because we want to specify our own static file options and change allowed_hosts from the django_heroku default value ['*'] to prevent Host Header attacks.
django_heroku.settings(locals(), staticfiles=False, allowed_hosts=False)
At the bottom of the settings.py file, we will now add settings specific to Heroku.
if "DYNO" in os.environ:
STATIC_ROOT = 'static'
Initializing git
We will now add git to our project.
git init
Adding Heroku to your git remotes
heroku git:remote -a example
Disabling DEBUG and settings allowed hosts
We now want to disable DEBUG in production and add our domain to our allowed hosts. We add these options in the if "DYNO" in os.environ
block because we only want these settings to be in effect in production.
if "DYNO" in os.environ:
STATIC_ROOT = 'static'
ALLOWED_HOSTS = ['example.herokuapp.com']
DEBUG = False
Adding the Procfile
First, we will add the Procfile. To do this just add a file called Procfile (without any extension) to the root of your project. On ubuntu and mac simply write
touch Procfile
We then install gunicorn which is the HTTP server we use in production on Heroku.
pip install gunicorn
while in the terminal while in the root directory. Next, add the following to the file
web: gunicorn myproject.wsgi --log-file -
Adding the requirements.txt file
Our last step is to create the requirements.txt file, which will specify all the packages that we have used. Since we used a virtual environment, this step is very easy. All we have to do is type
pip freeze > requirements.txt
in the terminal while being in our projects root directory. This will add all our packages installed through pip to the requirements.txt file automatically.
If you weren't using a virtual environment, you can also manually create a requirements.txt file in the root directory and manually add all the requirements. If you did everything correctly your requirements.txt file should look like
asgiref==3.4.1
dj-database-url==0.5.0
Django==3.2.7
django-heroku==0.3.1
gunicorn==20.1.0
psycopg2==2.9.1
pytz==2021.1
sqlparse==0.4.2
whitenoise==5.3.0
Deploying to Heroku
We are now ready to deploy our project.
git add .
git commit -m "My first project is ready to be deplayed"
git push heroku main
And we are done! Your project is now deployed to Heroku.
Optional settings for production
If you want to make sure your project only works over https you want to add the following options to your production settings.
if "DYNO" in os.environ:
STATIC_ROOT = 'static'
ALLOWED_HOSTS = ['example.herokuapp.com']
DEBUG = False
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
-
CSRF_COOKIE_SECURE
- Ensures your CSRF cookies will be served over https. -
SESSION_COOKIE_SECURE
- Ensures your session cookies will be served over https. -
SECURE_PROXY_SSL_HEADER
&SECURE_SSL_REDIRECT
- Will redirect all HTTP traffic to https
Additional reading
Posted on October 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.