Introduction
Heroku is a cloud platform that provides hosting services. It supports several programming languages including PHP, Node.js, and Python. It is Platform-as-a-Service (PaaS) which allows you to manage website applications while it takes care of your servers, networks, storage and other cloud components.
In this article, we'll take a look at how to deploy a Django application to Heroku, using Git.
You can follow the same steps, and deploy the application from GitHub, if it's hosted there.
Prerequisites
Below is a list of things that need to be done before we getting started with the deployment:
- Git
- Heroku Account and CLI
- Django Application
The Heroku Command Line Interface (CLI) makes it easy to create and manage your Heroku applications directly from the terminal. It’s an essential part of using Heroku.
To install the Heroku CLI (aka Heroku Toolbelt), please follow the instructions on the official website.
Make sure your Django application is running on virtual environment which you need to keep active throughout the deployment process.
A Heroku Account
Once all these things have been installed, the next step is to create a free Heroku account here, if you don't have an account already.
After writing the following in a terminal:
$ heroku login
The terminal should display a message like:
heroku: Press any key to open up the browser to login or q to exit:
Press any key and log in using your browser. The terminal will then display a message along the lines of:
Logged in as [email protected]
Configure Django Application for Heroku
Now that we are done with the prerequisites, let's prepare our Django application for Heroku.
Procfile
A Procfile is a file named Procfile
without any file extension placed in the root of your application. It lists the process types in an application and each process type is a declaration of a command that is executed when a container/dyno of that process type is started.
Before creating a Procfile
, you'll want to install django gunicorn
in your project directory:
$ pip install django gunicorn
While Django ships with its own WSGI server, our Procfile
will tell Heroku to use gunicorn
to serve our application, which is also recommended by Heroku.
Now, create a Procfile
in the parent directory and add the following line:
web: gunicorn yourdjangoweb.wsgi --log-file -
Replace yourdjangoweb
with the actual name of your project.
Runtime.txt
Create a text file called runtime.txt
in the same directory as the Procfile
. It tells Heroku what version of Python your application is using. If you are not sure of the version, enter python --version
in the terminal with your Django virtual environment activated.
Then add the version in runtime.txt
:
python-x.x.x
See the supported versions of Python on Heroku here.
Allowed Hosts
This is an extra security measure in Django to prevent HTTP host header attacks by only allowing the site to be served at host/domains which are added in the ALLOWED_HOSTS
list. If Debug = True
and ALLOWED_HOSTS
is []
then only localhost
is allowed by default. To deploy and serve your web application on Heroku, add it to the list:
ALLOWED_HOSTS = ['herokuappname.herokuapp.com']
Alternatively, you can allow all apps from Heroku by omitting the app name like this:
ALLOWED_HOSTS = ['.herokuapp.com']
You can also use ['*']
to allow all hosts. You can find more details in the documentation.
Install Packages
Below are the extra packages which need to be installed in our virtual environment.
To connect our Django database with Heroku, install dj-database-url
by calling:
$ pip install dj-database-url
As Heroku uses Postgres databases, we need its adapter for Python as well:
$ pip install psycog2
And finally, we will use WhiteNoise to serve static files in the production server. Which we can install by calling:
$ pip install whitenoise
We have already configured gunicorn
, let's add a configuration for whitenoise
and dj-database-url
.
Configuring Static Files
First add basic settings to serve static files in any Django project. You can copy-paste the following settings in your settings.py
:
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
PROJECT_ROOT = os.path.join(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(PROJECT_ROOT, 'staticfiles')
STATIC_URL = '/static/'
# Extra lookup directories for collectstatic to find static files
STATICFILES_DIRS = (
os.path.join(PROJECT_ROOT, 'static'),
)
-
Add WhiteNoise to the
MIDDLEWARE
list immediately afterSecurityMiddleware
which should be on the top:MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', ]
-
Add
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
in yoursettings.py
.0
Configuring the Database
We are using dj-database-url
to configure our database. Add these lines at the bottom of your settings.py
:
Check out our hands-on, practical guide to learning Git, with best-practices, industry-accepted standards, and included cheat sheet. Stop Googling Git commands and actually learn it!
import dj_database_url
prod_db = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(prod_db)
Requirements.txt
Heroku will recognize a deployed application as a Python application only if it has a requirements.txt
file in the root directory. It tells Heroku what packages are required to run your application.
We can use pip freeze
and pipe the output into a requirements.txt
file for this:
$ pip freeze > requirements.txt
Your requirements.txt
should include these:
whitenoise==5.2.0
dj-database-url==0.5.0
Django==3.0.9
gunicorn==20.0.4
psycopg2==2.8.5
pytz==2020.1
Note: The above versions are used by our Django application and they can differ for yours.
Connect Heroku Application With Git
Now we need to create a Heroku application:
$ heroku create herokuappname
It will display a "done" message with two URLs along this lines:
Creating ⬢ herokuappname... done
https://herokuappname.herokuapp.com/ | https://git.heroku.com/herokuappname.git
This means a Git repository has been created on Heroku cloud for your application. The URL https://herokuappname.herokuapp.com/
will be used to access your application anywhere but we still need to do one more step before running our application i.e. we need to push our code to the repository.
Initialize an empty repository in your project directory:
$ git init
> Initialized empty Git repository in /herokuappname/.git/
Connect your Heroku app with the empty git
repository:
$ heroku git:remote -a herokuappname
> set git remote heroku to https://git.heroku.com/herokuappname.git
Add files to the staging area:
$ git add .
Commit the changes/files:
$ git commit -m "first commit for all files"
Finally, push the project to git
repo hosted on Heroku:
$ git push master heroku
If everything goes fine, you will see an output like this:
Counting objects: 26, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (20/20), done.
Writing objects: 100% (26/26), 32.13 KiB | 0 bytes/s, done.
Total 26 (delta 1), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
.....
.....
remote: -----> Launching...
remote: Released v1
remote: https://herokuappname.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/herokuappname.git
[new branch] master -> master
collectstatic Error
You might get an error related to collectstatic
when you run the git push heroku master
command. This is related the to static files directory and you can bypass it with the following command:
$ heroku config:set DISABLE_COLLECTSTATIC=1
Setting DISABLE_COLLECTSTATIC and restarting ⬢ herokuappname... done, v2
DISABLE_COLLECSTATIC: 1
It will tell Heroku not to run collectstatic
command during application deployment. You can run it later using bower
:
$ heroku run 'bower install --config.interactive=false;grunt prep;python manage.py collectstatic --noinput'
It can occur for many reasons including but not limited to:
- Your
STATICFILES_DIRS
list is empty insettings.py
or not configured properly. - Your
static
directory contains no files forgit
to track. You can add any temporary file into yourstatic
directory to make it work.
Migrate the Database
Final step is to reflect your models
to Heroku database by running migrations:
$ heroku run python manage.py migrate
That's it, your application is up and running on heroku! You can access it at [appname].herokuapp.com
. The URL in our case would be http://herokuappname.herokuapp.com/
.
Adding a Custom Domain Name
Every app on Heroku is hosted on .herokuapp.com
but you can change it to your domain name if you own one. The process is simple:
- Login to Heroku Dashboard
- Select your current app from the list:
- Select Settings from navbar and scroll down to find the Domain section:
- Click on Add domain where you will be able to add your domain name.
This option is for verified accounts only. You will be asked to enter credit card details on Heroku to verify your account. You can find more details about adding domains and sub-domains on this page.
Conclusion
In this article, we deployed a Django application on Heroku with a custom domain name, using Git.
Besides various cloud services, Heroku also offers one of the best server up times and 24/7 operation and security team support.