How to deploy a Django App on Heroku in less than 5 minutes
Tags: django, heroku, postgres
Published: 2021-10-02 19:05:42

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
- [Creating Apps from the CLI](https://devcenter.heroku.com/articles/creating-apps)
- [Configuring config variables in Heroku](https://devcenter.heroku.com/articles/config-vars)
- [Django and Static Assets](https://devcenter.heroku.com/articles/django-assets)
- [Deploying Python Applications with Gunicorn](https://devcenter.heroku.com/articles/python-gunicorn)
- [Configuring Django Apps for Heroku](https://devcenter.heroku.com/articles/django-app-configuration)
- [Django official deployment checklist](https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/)