In this Django Heroku guide, I will talk about how to deploy Django project to Heroku using Docker.
So after you read it, you will get:
The difference between Heroku Buildpacks and Heroku Container.
How to serve Django static assets and media files in Heroku.
How to test Docker image for Django project in local env.
How to build front-end stuff for Django project when deploying.
The source code of this tutorial is django-heroku. I would appreciate that if you could give it a star.
Heroku Buildpacks and Heroku Container
There are mainly two ways for you to deploy Django project to Heroku
One way is the
Buildpacks are responsible for transforming deployed code into a slug, which can then be executed on a dyno
You can see
Buildpacks as some
pre-defined scripts maintained by Heroku team which deploy your Django project. They usually depend on your programming languages.
Buildpacks is very easy to use so most Heroku tutorial would like talk about it.
Another way is using
Docker provides us a more flexible way so we can take more control, you can install any packages as you like to the OS, or also run any commands during the deployment process.
For example, if your Django project use NPM as front-end solution (this is popular now), you want to
npm install some dependency packages during the deployment process or wnat to run custom npm build command, Docker seems more clean solution even
buildpacks can do this. (buildpacks can also do this but still have some limitations)
What is more,
Docker let you deploy project in a way most platforms can support, it can save time if you want to migrate it to other platforms such as AWS, Azure in the future.
Build manifest and Container Registry
Some people are confused about
Build manifest and
Container Registry in Heroku Docker doc. So let me explain here.
Container Registry means you build docker in local, and then push the image to Heroku Container Registry. Heroku would use the image to create a container to host your Django project.
Build manifest means you push Dockerfile and Heorku would build it, run it in standard release flow.
What is more,
Build manifest support some useful Heorku built-in features such as
If you have no special reason, I strongly recommend using
Build Manifest way to deploy Django.
Docker Build vs Docker Run
So what is the difference between
Docker build and
Docker build builds Docker images from a Dockerfile.
Dockerfileis a text document that contains all the commands a user could call on the command line to build an image.
Docker run create a writeable container layer over the specified image,
So we should first use
docker build to build the docker image from
Dockerfile and then create container over the image.
Step1: Start to write Dockerfile
Now you already have basic understanding of the Heroku docker, so now let's learn more about
Here I would use
django_heroku as an example to show you how to write Dockerfile.
# Please remember to rename django_heroku to your project directory name FROM python:3.6-stretch # WORKDIR sets the working directory for docker instructions, please not use cd WORKDIR /app # sets the environment variable ENV PYTHONUNBUFFERED=1 \ PYTHONPATH=/app \ DJANGO_SETTINGS_MODULE=config.settings.production \ PORT=8000 \ WEB_CONCURRENCY=3 EXPOSE 8000 # Install operating system dependencies. RUN apt-get update -y && \ apt-get install -y apt-transport-https rsync gettext libgettextpo-dev && \ curl -sL https://deb.nodesource.com/setup_8.x | bash - && \ apt-get install -y nodejs &&\ rm -rf /var/lib/apt/lists/* # start to compile front-end stuff WORKDIR django_heroku/static_src # Install front-end dependencies. COPY ./django_heroku/static_src/package.json ./django_heroku/static_src/package-lock.json ./ RUN npm install # Run custom npm commadn to compile static assets such as js, SCSS COPY ./django_heroku/static_src/ ./ RUN npm run build:prod # Install Gunicorn. RUN pip install "gunicorn>=19.8,<19.9" # start to install backend-end stuff WORKDIR /app # Install Python requirements. COPY requirements.txt . RUN pip install -r requirements.txt # Copy application code. COPY . . # Install assets RUN python manage.py collectstatic --noinput --clear # Run application CMD gunicorn config.wsgi:application
Please note that
WORKDIRdocker instruction, it would sets the working directory for docker instructions (RUN, COPY, etc.) It is very like the
cdcommand in shell, but you should not use
Since you already know what is
docker build, I want to say nearly all docker instructions above would be executed in
docker build. The only exception is the last
CMD, it would be excuted in
ENVto set the default env variable.
As you can see, I use
RUN npm run build:prodto help me build front-end assets.
If you use
pipenvin your project, you can change the
pip installcommand part.
Step2: Build Docker image
After you create
Dockerfile and put it at root of your Django project, it is recommended to test it in local, this can save you time if something is wrong.
PS: If you have not installed Docker, please check this Docker install Doc
$ docker build -t django_heroku:latest .
Step3: Docker run
If the docker image has been built without error, here we can keep checking in local env
$ docker run -d --name django-heroku-example -e "PORT=9000" -p 9000:9000 django_heroku:latest # Now visits http://127.0.0.1:9000/admin/
Dockerfile, we use
ENVto set default env variable in
docker run, but we can still use
-e "PORT=9000"to overwrite the env in run command.
-p 9000:9000let us can visits the 9000 port in container through 9000 in host machine.
Let's check the project files now
$ docker exec django-heroku-example ls /app Dockerfile config db.sqlite3 django_heroku manage.py requirements.txt static_root
As you can see, a local
db.sqlite3 is created because we did not set remote DB ENV. I will talk about it in a bit.
After you finish testing, remember to stop and remove the local docker container
$ docker stop django-heroku-example $ docker rm django-heroku-example
Step4: Serving static assets on Heroku
Django only serve media files and static assets in dev mode, so I will show you how to serve them on Heroku in production mode.
To serve static assets, we need to use a 3-party package.
$ pip install whitenoise
settings/base.py, put it above all other middleware apart from Django’s
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # ... ]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
That is all the config you need.
python manage.py collectstatic --noinput --clearin Dockerfile executed in
docker build, all static assets would be put to
docker runexcecuted on Heroku, Django can serve static assets with the help of
Step5: Serving media files on Heroku
Because all changes to docker container would be lost during redploy. So we need to store our media files to some other place instead of Heroku Docker container.
The popular solution is to use Amazon S3 storage, because the service is very stable and easy to use.
If you have no Amazon service account, please go to Amazon S3 and click the
Get started with Amazon S3to signup.
Login AWS Management Console
In the top right, click your company name and then click
My Security Credentials
Create New Access Key, please copy the
If you are new to Amazon and have no idea what is
IAM user, you can skip it and set permissions later.
Next, we start to create Amazon bucket on S3 Management Console, please copy
Bucket name to notebook.
Bucket in Amazon S3 is like top-level container, every site should have its own
bucket, and the bucket name are unique across all Amazon s3, and the url of the media files have domain like
Now let's config Django project to let it use Amazon s3 on Heroku.
$ pip install boto3 $ pip install django-storages
Add config below to
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME') AWS_S3_CUSTOM_DOMAIN = '%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID') AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') AWS_S3_FILE_OVERWRITE = False MEDIA_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
To secure your Django project, please set
AWS_SECRET_ACCESS_KEYin env instead of project source code (I will show you how to do it in Heroku in a bit)
AWS_S3_FILE_OVERWRITEplesae set it to False, so this can let the storage handle
duplicate filenamesproblem. (I do not understand why so many blog posts did not mention this)
Step6: Remote DB support
Heroku support many different dbs, you can choose what you like and add it to your Heroku instance. (I recommend
In Heroku, the DB connection string is attached as ENV variable. So we can config our settings in this way.
pip install dj-database-url
import dj_database_url if "DATABASE_URL" in env: DATABASES['default'] = dj_database_url.config(conn_max_age=600, ssl_require=True)
dj_database_url would convert
DATABASE_URL to Django db connection dict for us.
heroku.yml is a manifest you can use to define your Heroku app.
Please create a file at the root of the directory
build: docker: web: Dockerfile release: image: web command: - django-admin migrate --noinput
As you can see, in
buildstage, docker would build
webimage from the
In release stage,
migratecommand would run to help us sync our database.
Step8: Deploy the Django project to Heroku
Now, let's start deploy our Django project to Heorku.
First, we go to Heroku website to login and create a app.
After we create the app, we can get the shell command which can help us deploy the project to Heroku.
Then we start to config and deploy in terminal.
$ heroku login $ git init $ heroku git:remote -a django-heroku-docker $ heroku stack:set container -a django-heroku-docker # git add files and commit $ git push heroku master
heroku stack:set containeris important here because it would tell Heroku to use container instead of
buildpacksto deploy the project.
You can find the domain of your Heroku app in
settingstab. (Heroku has free plan so you can test and learn as you like)
Step9: Add DB add-on
Now you can add db add-on to your Heroku instance, so data of your Django project would be persistent.
Go to the
overviewtab of your Heroku project, click
Heroku Postgresand click
Now go to
settingstab of your Heroku project, click the
Reveal Config Vars
You will see
DATABASE_URL, it is ENV variable of your Heroku project and you can add AWS S3 config to make the Django project can serve media files.
NOTE: Heroku CLI is very powerful, and the
add-on operation can also be done in terminal, considering readers of this post have not much expereince on Heroku, screenshots might be better here.
You can add code below to your Dockerfile. (put it on top)
ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1
PYTHONDONTWRITEBYTECODEwould make Python not write .pyc file.
PYTHONUNBUFFEREDwould make terminal output more better and not buffered.
You Django project should also work fine even you did not set them in your Dockerfile.
In this Django Heorku tutorial, I talked about how to deploy Django project to Heroku using Docker.
You can find the source code django-heroku. I would appreciate that if you could give it a star.
So what should you go next?
Take a look at how to use NPM as front-end solution with Django
In the next Django Heroku tutorial, I will talk about how to deploy from Gitlab to Heroku and I will also give you some useful tips.
If you still have any question, please feel free to contact us.