Deploy a Django web application on Heroku
When I initially began my web development journey, I started with Django. I had some previous experience with Python and some quick googling revealed that many major companies such as Instagram and Spotify were using Django to some extent.
This seemed like a great framework to begin with. Django is a "batteries-included" full-stack application that has been around for quite a while. The primary goal of Django is to speed up development by handling many of the commonly encountered issues in web development.
A couple of issues that Django has built-in handling for are:
- CSRF protection
- User management
- Secure authentication and authorization
- Database integration
- And much more...
If you have minimal experience, need to rapidly develop a complete web application, or have need of Python then Django could be a great choice for you.
However, Django does have a few disadvantages:
- Statically-generated pages
- Django-specific syntax and flow that must be learned
- Strongly-opinionated
Over the past decade Javascript has come to dominate the front-end of web development. Every company wants fast and dynamic pages that provide interactivity for their user. This is the primary issue with Django's statically-generated pages. The solution to this is the Django REST framework.
With the Django REST framework, you get many of the advantages of Django while still being able to use a JS front-end framework such as React.
Overview
In this guide I will discuss how to upload a Django web application to Heroku so that you can begin serving your creation to potential customers.
For the backend you will use a postgreSQL database hosted on the Heroku Postgres add-on.
All images will be hosted on AWS S3.
Heroku is one of the most popular platforms for hosting web applications in the cloud. Many novice programmers underestimate how complex deploying a website can be. Even once you have a web application built in your local development environment, there are still many steps before it is ready for production.
The application must undergo the build process, it must be optimized, servers need to be configured, etc. Heroku automates all of this so that you can focus on developing a great web application. Some other platforms similar to Heroku that are worth checking out are:
- AWS
- Netlify
- Dokku
- Vercel
Table of Contents
Prepare Django for production
First you need to create an account with Heroku and then click Create new app
. This will set up a Heroku project with a
Heroku provided URL.
Before you can upload Django to Heroku, you must prepare it for the production environment. Django includes a very handy command shown below:
manage.py check --deploy
Depending on your setup you may need to add python
or python3
in front of the above command.
This command will automatically evaluate your Django application and discover many of the common issues.
Some of the most common settings and issues are listed:
- SECRET_KEY setting
- Set DEBUG to False
- Add Heroku's provided URL to ALLOWED_HOSTS
- Define a STATIC_ROOT setting
- Set CSRF_COOKIE_SECURE and SESSION_COOKIE_SECURE to true
All of these settings should be adjusted in your settings.py
folder. If the setting is not already in settings.py
you should
add it.
One setting that Django will most likely recommend turning on is the SECURE_SSL_REDIRECT
setting. This setting redirects all
non-HTTPS requests to HTTPS to increase security. However, this causes issues with Heroku as all traffic within the Heroku
network is HTTP.
As a result, you need to tell Django to check the X-FORWARDED_PROTO header to determine if the connection that originally hit the Heroku proxy was HTTPS:
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
The formal Django production checklist can be found here.
If you encounter any other issues or settings, Django's documentation is the best place to start.
Set up Procfile
A Procfile
is Heroku's method for defining instructions on how to run the deployed application. Heroku "should" automatically
run the necessary commands to start up your web application after the build process.
However, in actuality this does not always work. It is best practice to create a Procfile
to avoid any potential issues.
Before creating your Procfile
, you want to install and set up Gunicorn. Gunicorn allows your Django application to process
incoming HTTP requests concurrently instead of using Django's default blocking servers.
pip install gunicorn
In the root directory of your application (same location as .gitignore and README) create a file called Procfile
with the
following code:
web: gunicorn application_name.wsgi
Note that application_name
should be whatever you have named your Django application. This will be the name of the directory
that holds the wsgi.py
file.
Ensure that this file is not included in .gitignore
.
Create requirements.txt
In order to build your web application, Heroku needs to know what Python packages to install. This is where the requirements.txt file is used.
Every Python package and version used by your application needs to be listed in this file. It should look similar to the below:
appdirs==1.4.4
asgiref==3.4.1
backports.zoneinfo==0.2.1
Bottleneck==1.3.5
certifi==2020.6.20
distlib==0.3.2
Django==3.2.5
...
Hopefully you have been using a virtual environment with Pip. If you have a .venv
folder in the root folder of your Django
application then you have been.
Creating a requirments.txt file is as simple as entering the below command into your terminal:
pip freeze > requirements.txt
Or if that does not work try the below:
pip3 freeze > requirements.txt
This command will automatically create the requirements.txt file with whatever packages are in your virtual environment.
Ensure this file is not included in .gitignore
.
If you have been using Anaconda to install packages you can try running the below command:
pip list --format=freeze > requirements.txt
More information can be found here. I use Pip and cannot speak to how effective these techniques are.
runtime.txt
This file should be added to your root folder. It specifies exactly which version of Python Heroku should use for your web application.
Run the below code to discover which version you are using:
python --version
or this command if the previous does not work:
python3 --version
Simply type the outputted version into runtime.txt
using the following format:
python-3.9.7
Ensure this file is not included in .gitignore
.
Set up AWS S3 (Optional)
Amazon's Simple Storage Service (S3) is ideal for hosting static files such as images. This service is invaluable with Heroku for two reasons:
- Heroku has a hard limit on your final build size (500 MB)
- Heroku uses an ephemeral filesystem
If your application has no images feel free to continue to the next section. In addition, if you believe your build size will be below 500 MB even with the images included skip to the next section. If your build size ends up being too large you can always come back and move your images to S3.
If you do not want to create an AWS account, Heroku's documentation recommends the Bucketeer add-on. I have not used this add-on and cannot speak to its effectiveness.
In order to use S3 you will need to create an AWS account. The process is straight-forward and well-documented. Check out this guide to get started.
After creating your primary AWS account, you will want to create an IAM user. IAM user's have restricted access and unique credentials which decreases potential security concerns.
The IAM user creation process is detailed below:
- From the search bar at the top of the AWS console search for "IAM"
- Select "Users" on the left-hand side
- Click "Add users"
- Enter a username (name of your site is a decent option)
- Select "Access key - Programmatic access" and then click "Next"
- Click "Attach existing policies directly" and enter "S3" into the search bar
- Select "AmazonS3FullAccess" and then click "Next"
- Skip the "Tags" section and then click "Create user"
- Copy the
Access key ID
and theSecret access key
to yourConfig Vars
under Heroku's settings as shown below
AWS_ACCESS_KEY_ID => Access key ID
AWS_SECRET_ACCESS_KEY => Secret access key
If you need additional help creating a user this guide provides more information.
Now you will need to create your S3 bucket. This bucket will host your images and any other static files you would like to store in it.
The S3 bucket creation process is detailed below:
- From the search bar at the top of the AWS console search for
S3
- Click
Create bucket
at the top - Give it a name that follows the rules for bucket naming
- Select the AWS region that closest matches your Heroku region
- Leave the remaining settings on their defaults and click
Create bucket
- Add the bucket name to Heroku's
Config Vars
S3_BUCKET_NAME => your-bucket-name
Now you can upload your image files to S3 and remove them from your web application's files. If you click on your image in
S3 a detailed view will pop up. One of the values will be Object URL
which is what you should use for your images' src
values in your code.
If you need additional help setting up a S3 bucket and integrating it with Heroku this guide provides more information.
Set up Postgres add-on
The final step before deploying is setting up your Postgres database. This will be done through the Heroku Postgres add-on. From the Heroku dashboard install the Heroku Postgres add-on.
After installation, check your Config Vars
for a new DATABASE_URL
variable. This is the variable that will be used to
connect to your database in Django settings. You should not hard code the database credentials into Config Var
as these
can sometimes change.
DATABASE_URL
will automatically stay up-to-date and keep you connected even if the database credentials change.
Before your Django web application can connect to your Heroku Postgres database there are some settings you need to adjust.
First you will need to install the following packages:
pip install dj-database-url
pip install whitenoise
Here is the Whitenoise documentation to ensure you properly set it up.
Then you should ensure that your settings.py
file reflects this example from Heroku.
Connect Heroku to Github
From your app's homepage on Heroku click Deploy
at the top. This will open all deployment settings for your
application. We recommend that you use Heroku Git
or GitHub
.
If your code is already stored on Github, then the Github integration option will be easiest. This guide details the process.
If you would like to use the Heroku CLI, this guide can walk you through the setup process.
Regardless of which option you select, once you push your code to Heroku the build process should begin. You can follow the
progress by navigating to the the Overview
tab and clicking View build progress
on the right under Latest activity
.
Allow this process to continue until you see an error or a Done: Launching...
message. Then navigate back to the Overview
tab. Underneath Latest activity
there should now be a message Deployed
.
Continue to wait until the Build in progress
message changes to Build succeeded
. This may take a few minutes. You should now
be able to click Open app
and see your web application.
If you receive an Application error
when attempting to view your web application check your logs. Heroku's logs are typically
very informative and there are many resources online to sort through the various issues.
In addition, check out my Common issues section.
While Heroku is a very advanced tool, there are still a multitude of issues that can be encountered while trying to deploy your application. Be patient and do your research. The answer is out there somewhere and if not try posting a question on StackOverflow.
Common issues
This section investigates a couple of issues that frequently occur during the build process. If you encounter any issues the best place to start is the logs. These can be found in two places:
- Click
More
andView logs
on the Heroku dashboard - Type
heroku logs --tail
in Heroku CLI
requirements.txt or runtime.txt not accurate
If your requirements.txt or runtime.txt are not accurate, Heroku will not be able to build your web application. Review these files to ensure that all of the necessary packages are included and that the versions are correct.
Sometimes specific versions of packages are not supported by Heroku which can be difficult to discover. StackOverflow is a great resource to check for potential solutions.
Slug size too large
Heroku includes a 500 MB hard limit on their "slug size". The slug is a compressed and optimized version of your web application that is sent to Heroku's dyno servers. If your final slug size is larger than 500 MB you will not be able to deploy to Heroku.
There are a couple of techniques you can use to decrease your slug size:
- Move static files such as images and PDFs to a separate asset storage system such as S3
- Review requirements.txt and remove any unused packages
- Files that do not need to be included in your slug should be added to
.slugignore
(ex. test files) - Purge the build cache
The below commands can be used to purge the build cache:
heroku plugins:install heroku-builds
heroku builds:cache:purge
To check the size of all of you files in your slug you can run the following commands:
heroku run bash -a appname
du -ha --max-depth 1 /app | sort -hr
If after all of this your slug size is still too large then you may need to look into other platforms such as AWS.
at=error code=H14 desc=”No web process running”
Heroku "should" automatically run the necessary commands to start up your web application after the build process. However, in actuality this does not always work. It is best practice to create a Procfile that explicitly tells Heroku how to start up your web application.
Ensure that your Procfile
is in the root folder and includes the following code:
web: gunicorn application_name.wsgi
Note that application_name
should be whatever you have named your Django application. This will be the name of the directory
that holds the wsgi.py
file.
Double check that your Procfile
is not included in .gitignore
or .slugignore
. If you already have the Procfile
included you will need to run the following command using the Heroku CLI:
heroku ps:scale web=1 --app YOUR_APP_NAME
This command ensures that a dyno is started up to serve your web application. After running this command, you should see
the contents of your Procfile
underneath Dyno formation
on your Heroku app dashboard. In addition, there should be a green
ON symbol next to it.
at=error code=H10 desc="App crashed"
This is a generic app crash message that by itself is not that useful. However, if you encounter this issue the next best step is to type the below code into the Heroku CLI:
heroku restart --app YOUR_APP_NAME
Ensure that you are watching the logs while the app restarts. It will display some messages such as State change from crashed to starting
.
Then it will most likely display a more informative error message indicating why the app has crashed.
Next steps
Now that your application is built and hosted on Heroku you probably want to focus on improving the performance of your website. One of the best methods you can use to improve the performance is a content delivery network (CDN).
A CDN allows fast delivery of assets required for loading your website. Images, JS files, stylesheets, etc can all take advantage of a CDN. Nearly all professional-quality websites and web applications use CDNs.
If you are interested in taking this next step, check out AWS CloudFront.