How to deploy Django project to Dokku with Docker

Table of Contents

Django Heroku Tutorial Series:

  1. Heroku vs AWS Which is Best for Your Django project
  2. How to deploy Django project to Heroku using Docker
  3. How to deploy Python project to Heroku in Gitlab CI
  4. How to use Heroku Pipeline
  5. Heroku Logs Tutorial
  6. How to monitor Heroku Postgres using heroku-pg-extras

Django Dokku Tutorial Series:

  1. How to deploy Django project to Dokku
  2. How to deploy Django project to Dokku with Docker


In this post, I will talk about how to deploy Django project to Dokku with Docker, it would use Postgres db and Amazon S3 to store data and media files.

After reading this tutorial, you will get:

  1. How to install Dokku, config Dokku server
  2. How to create, manage Dokku app.
  3. How to test Docker image for Django project in local env.

The source code of this post can be found on Github, please give it star if it helps you.

Heroku Buildpacks and Dockerfile

By default, Dokku would use Heroku's buildpacks to deploy project.

But Dockerfile 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.

Generate SSH Key on Local

If you already have SSH key, you can skip this section.

# change to your email address
(local)$ ssh-keygen -t ed25519 -C "[email protected]"
  1. When you're prompted to "Enter a file in which to save the key," press Enter. This accepts the default file location.
  2. At the prompt, type a secure passphrase

If you meet problem, please check Generating a new SSH key to learn more.


├── id_ed25519                        # new
├──                    # new
  1. id_ed25519 is private key, you should not share it to other people.
  2. is the public key.

Create New User

After we SSH to our server as root, let's create normal user first.

(root)-# adduser michaelyin

enter some long and complex passwd

Add user to sudo group

(root)-# usermod -a -G sudo michaelyin
(root)-# groups michaelyin

michaelyin : michaelyin sudo

Make sudo without passwd, note that this setting is not recommended if the vps requires more safety

(root)-# visudo

# only edit this line

Now we can change to new user

(root)-# su michaelyin

'$' denote a normal user prompt

Improve SSH Experience

# make sure we login as normal user instad of root
(server)$ whoami

(server)$ cd ~
(server)$ mkdir .ssh && touch .ssh/authorized_keys
(server)$ chmod 700 .ssh && chmod 600 .ssh/*

Now on local, upload the ssh public key to the vps

(local)$ cat ~/.ssh/ | ssh [email protected]  "cat >> ~/.ssh/authorized_keys"

Now on local, we can login ssh [email protected] without typing the complex password, which is convenient.

Please add code below to your ~/.ssh/config on local.

Host dokku_server
    RequestTTY yes
    User michaelyin
    Port 22
    ServerAliveInterval 60
    ServerAliveCountMax 60

Now we can use ssh dokku_server instead of ssh [email protected] to login to your server

Install Dokku

We can get the install script on the Dokku release page

Let's SSH to our server and then use code below to install Dokku

# Please use ssh to login to your server
(server)$ whoami

(server)$ cd
(server)$ wget
(server)$ sudo DOKKU_TAG=v0.26.5 bash

The script would also install dependencies and Dokku on the server.

Setup Dokku

After we install Dokku, we will see something like this in the terminal

! Setup a user's ssh key for deployment by passing in the public ssh key as shown:

echo 'CONTENTS_OF_ID_RSA_PUB_FILE' | sudo dokku ssh-keys:add admin

Let's add our public SSH to the Dokku.

# run this command on local
# need root password
(local)$ cat ~/.ssh/ | ssh root@dokku_server dokku ssh-keys:add admin
# let's check on server
$ sudo dokku ssh-keys:list

SHA256:XXXXXX NAME="admin" SSHCOMMAND_ALLOWED_KEYS="no-agent-forwarding,no-user-rc,no-X11-forwarding,no-port-forwarding"

Config Dokku App

Next, let's create and config our Dokku app.

Please note that, the dokku project has name django-dokku-docker.

Create Dokku app

$ sudo dokku apps:create django-dokku-docker
-----> Creating django-dokku-docker...

Create Postgres DB

Here we put the Postgres db on our server, but you can also use 3-party DB server like Amazon RDS if you like.

Dokku has many plugins and here we use postgres plugin to help us.

# install the plugin
$ sudo dokku plugin:install

# let's create db, I add suffix '-db'
# we can even use --image-version to specify postgres version
$ sudo dokku postgres:create django-dokku-docker-db --image "postgres" --image-version "14.1"

       Waiting for container to be ready
       Creating container database
       Securing connection to database
=====> Postgres container created: django-dokku-docker-db
=====> django-dokku-docker-db postgres service information
       Config dir:          /var/lib/dokku/services/postgres/django-dokku-docker-db/data
       Config options:
       Data dir:            /var/lib/dokku/services/postgres/django-dokku-docker-db/data
       Dsn:                 postgres://postgres:a24e71a3f0ca3814ae6be809921b0313@dokku-postgres-django-dokku-docker-db:5432/django-dokku-docker-db
       Exposed ports:       -
       Id:                  4919a29ec4820fbf758482b7d91d53ae8fa0bcc27e9ea9bb1bbc6cc0895ca43b
       Internal ip:
       Links:               -
       Service root:        /var/lib/dokku/services/postgres/django-dokku-docker-db
       Status:              running
       Version:             postgres:14.1

Now link the db to your dokku app, and it would add a new env varialbe DATABASE_URL to the dokku app.

$ sudo dokku postgres:link django-dokku-docker-db django-dokku-docker
-----> Setting config vars
       DATABASE_URL:  postgres://postgres:a24e71a3f0ca3814ae6be809921b0313@dokku-postgres-django-dokku-docker-db:5432/django_dokku_docker_db
-----> Restarting app django-dokku-docker
 !     App image (dokku/django-dokku-docker:latest) not found

Let's print out the env of our Dokku app.

$ sudo dokku config:show django-dokku-docker

=====> django-dokku-docker env vars
DATABASE_URL:  postgres://postgres:a24e71a3f0ca3814ae6be809921b0313@dokku-postgres-django-dokku-docker-db:5432/django_dokku_docker_db

Config Amazon s3

Unlike Heroku, Dokku also support store media files on local disk, you can check Dokku Persistent Storage for more detail

  1. If you have no Amazon service account, please go to Amazon S3 and click the Get started with Amazon S3 to signup.
  2. Login AWS Management Console
  3. In the top right, click your company name and then click My Security Credentials
  4. Click the Access Keys section
  5. Create New Access Key, please copy the AMAZON_S3_KEY and AMAZON_S3_SECRET to notebook.

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 {bucket_name}


Please use the values from your notebook.

$ sudo dokku config:set --no-restart django-dokku-docker AWS_STORAGE_BUCKET_NAME='CHANGE ME'
$ sudo dokku config:set --no-restart django-dokku-docker AWS_ACCESS_KEY_ID='CHANGE ME'
$ sudo dokku config:set --no-restart django-dokku-docker AWS_SECRET_ACCESS_KEY='CHANGE ME'
$ sudo dokku config:set --no-restart django-dokku-docker AWS_S3_REGION_NAME='CHANGE ME'

By default, Dokku would restart the app if you changed env variable, here we use --no-restart to tell Dokku not restart it.

Config other env variable

There are still some env variables we need to config, please use dokku config:set --no-restart django-dokku-docker to add them to Dokku app.

DJANGO_SECRET_KEY:        xxxxxxxxx
DJANGO_SETTINGS_MODULE:   django_dokku_docker.settings
DJANGO_DEBUG:             False

Config domain

Next, we start to config domain.

$ sudo dokku domains:add django-dokku-docker
-----> Added to django-dokku-docker
 !     No web listeners specified for django-dokku-docker

Here we add to to our Dokku app django-dokku-docker, we can add more than one domain to Dokku app.

Config Django project

Now the Dokku app env is ready, before pushing code to Dokku server, let's prepare our Django project.

You would also see we need to add some config files, which are very similar with Heroku's config file, Dokku would scan and read them to decide some deployment workflow.


First, let's add django-environ to requirements.txt.


And then, let's update Django settings django_dokku_docker/ to use django-environ to read the env.

import environ                           # new
from pathlib import Path

env = environ.Env()                      # new

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env('DJANGO_SECRET_KEY', default='django-insecure-$lko+#jpt#ehi5=ms9(6s%&6fsg%r2ag2xu_2zj1ibsj$pckud')

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = env.bool("DJANGO_DEBUG", True)

ALLOWED_HOSTS = env.list("DJANGO_ALLOWED_HOSTS", default=[])


  1. Here we use django-environ to set SECRET_KEY, DEBUG and ALLOWED_HOSTS from the Environment variable.
  2. And we also set default value to make it work in development without extra Env.
$ ./ migrate
$ ./ runserver

Now, please check on to make sure everything is working.

Static files

To serve static assets, we need to use a 3-party package. whitenoise.

Add whitenoise to requirements.txt


Update django_dokku_docker/

import os                                                                            # new

   'whitenoise.middleware.WhiteNoiseMiddleware',                                     # new
   # ...

STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')                                       # new


That is all the config you need.

Store media in Amazon s3

update requirements.txt.


Add storages to INSTALLED_APPS in django_dokku_docker/

And then update django_dokku_docker/

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')                                      # new
MEDIA_URL = '/media/'                                                             # new

if 'AWS_STORAGE_BUCKET_NAME' in env:                                              # new
    AWS_DEFAULT_ACL = 'public-read'

    MEDIA_URL = "https://%s/" % AWS_S3_CUSTOM_DOMAIN
    DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
  1. AWS_S3_FILE_OVERWRITE please set it to False, so this can let the storage handle duplicate filenames problem. (I do not understand why so many blog posts did not mention this)

Please note the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY is for AWS admin, for better security, you should create AWS IAM user and then grant S3 permissions. You can check Bucket owner granting its users bucket permissions to learn more.

Postgres DB

Update django_dokku_docker/

if "DATABASE_URL" in env:
    DATABASES['default'] = env.db('DATABASE_URL')
    DATABASES["default"]["ATOMIC_REQUESTS"] = True

Here env.db would convert DATABASE_URL to Django db connection dict for us.

Do not forget to add psycopg2-binary to requirements.txt.



This file exists in root directory of our project. It contains entry command of our service.

web: gunicorn django_dokku_docker.wsgi:application

release: django-admin migrate --noinput

Here web means the web service, Dokku would use the command to run for our web service.

And release is the command which would be run in release stage, here we use the command to migrate our database in release stage.

If you used Celery worker in your project, you can add worker: ... to do that.


A Dockerfile is a text document that contains all the commands a user could call on the command line to build an image.

Create Dockerfile

# Please remember to rename django_dokku_docker to your project directory name
FROM python:3.10-slim-buster


    PYTHONPATH=/app \
    DJANGO_SETTINGS_MODULE=django_dokku_docker.settings \
    PORT=8000 \

# Install system packages required by Wagtail and Django.
RUN apt-get update --yes --quiet && apt-get install --yes --quiet --no-install-recommends \
    build-essential curl \
    libpq-dev \
    libmariadbclient-dev \
    libjpeg62-turbo-dev \
    zlib1g-dev \
    libwebp-dev \
 && rm -rf /var/lib/apt/lists/*

RUN addgroup --system django \
    && adduser --system --ingroup django django

# Requirements are installed here to ensure they will be cached.
COPY ./requirements.txt /requirements.txt
RUN pip install -r /requirements.txt

# Copy project code
COPY . .

RUN python collectstatic --noinput --clear

# Run as non-root user
RUN chown -R django:django /app
USER django

# Run application
CMD gunicorn django_dokku_docker.wsgi:application
  1. Please note that WORKDIR docker instruction, it sets the working directory for docker instructions (RUN, COPY, etc.) It is very like the cd command in shell, but you should not use cd in Dockerfile.
  2. We use ENV to set the default env variable.
  3. We added a django user and used it to run the command for security.

Add gunicorn to requirements.txt


PS: If you have not installed Docker, please check this Docker install Doc

# let's test the docker image on local
$ docker build -t django_dokku:latest .

If you have some problem in Dockerfile, you can troubleshoot in this step.

Note: If you need to build frontend assets in Dockerfile, please check How to deploy Django project to Heroku using Docker for more details.

Deploy project

Please commit code first and then keep reading.

First we add a remote branch dokku to our Git repo.

$ git remote add dokku dokku@dokku_server:django-dokku-docker


  1. dokku_server here can also be the ip address of the server (dokku_server is the hostname we config in ~/.ssh/config),
  2. django-dokku-docker is the dokku app we just created on our server.

Then we push our code to remote master branch

$ git push dokku master:master

Below is the output, Dokku would check language we use and download relevant Heroku buildpack to deploy the project. Which is very cool!

Counting objects: 177, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (162/162), done.
Writing objects: 100% (177/177), 49.38 KiB | 3.53 MiB/s, done.
Total 177 (delta 45), reused 0 (delta 0)

=====> Application deployed:

To dokku_server:django-dokku-docker
 * [new branch]      master -> master

If the push command did not raise error, you should see something like this and now our app is live on

Let's check to make sure Django app is running without issue.

Setup SSL

Let's make https work for our site.

(server)$ sudo dokku plugin:install
(server)$ sudo dokku config:set --no-restart --global [email protected]
(server)$ sudo dokku letsencrypt:enable django-dokku-docker
(server)# this would setup cron job to update letsencrypt certificate
(server)$ sudo dokku letsencrypt:cron-job --add

Please replace DOKKU_LETSENCRYPT_EMAIL with your email.

After https can work on your site, you can setup http->https to improve security, Django SECURE_SSL_REDIRECT can help.

Some Advanced issues

Run Dokku command without sudo

It is annoying to make everything dokku command have sudo

From the Dokku doc

(server)$ sudo visudo /etc/sudoers

# add following line
%dokku ALL=(ALL:ALL) NOPASSWD:SETENV: /usr/bin/dokku

This means any user in dokku group can run /usr/bin/dokku without password.

Next, let's add user michaelyin to the dokku group

$ sudo usermod -a -G dokku michaelyin

# exit and login again
$ groups
michaelyin sudo dokku

As you can see, now michaelyin is in dokku group, and we can run dokku command without sudo

$ dokku apps:list
=====> My Apps


It is common if your Django projects return 500 error page in some cases, so how to troubleshoot?

  1. I strongly recommend to use to help you solve this, the free plan is enough for personal projects.
  2. Or you can check the running logs using this command dokku logs django-dokku-docker

Customize Nginx

Sometimes, we need to customize our Nginx settings.

For example, the default Nginx settings has small client_max_body_size, so I need to change it to make upload feature work in my Django project.

Dokku generate nginx config from nginx.conf.sigil, you can first download it from Dokku repo (better download from specific Git tag you use).

And then you can modify your settings.

You can add that file to root directory of your project and Dokku would use it to generate new nginx config.

  1. You can check Doc: Customizing the nginx configuration
  2. In the new version, you can set client_max_body_size with dokku command,

Zero Downtime Deploy

When Dokku deploy, it would start container which has the latest code and then wait for 10 secs to make sure the service is ok to run.

To decrease the time, we can add CHECKS file and Dokku would use that file to check if our web server is ok to serve.

/admin                      Django

It tells Dokku to visit /admin url and check if the response contains Django

-----> Deploying web (count=1)
       Attempting pre-flight checks (web.1)
       CHECKS expected result: http://localhost/admin => "Django" (web.1)
       Attempt 1/5. Waiting for 5 seconds (web.1)
       All checks successful (web.1)

Run Django command

If you want to run some command on web server, for example, run Django shell, you can use command in this way

(server)$ dokku run django-dokku-docker python shell

Here Dokku would create a new container for you to use and this can avoid some risky operation.

The container is deleted when you exit.

Dokku Client

If you want to run dokku on local without SSH command, you can check Dokku official client

After setting it up, we can enter Django shell on the server:

(local)$ DOKKU_HOST=dokku_server dokku run django-dokku-docker python shell

Setup Cron job

If you want to setup cron jobs for your project, it is better to do it on host machine.

# we setup crontjob as dokku user
(server)$ sudo crontab -u dokku -e

@daily dokku run django-dokku-docker python clearsessions

As you can see, we setup clearsessions job to run each day and it helps us clean out expired sessions in db.


In this Dokku tutorial, I showed you how to deploy Django project to Dokku with Docker.

The source code of this post can be found on Github, please give it star if it helps you.

Django Heroku Tutorial Series:

  1. Heroku vs AWS Which is Best for Your Django project
  2. How to deploy Django project to Heroku using Docker
  3. How to deploy Python project to Heroku in Gitlab CI
  4. How to use Heroku Pipeline
  5. Heroku Logs Tutorial
  6. How to monitor Heroku Postgres using heroku-pg-extras

Django Dokku Tutorial Series:

  1. How to deploy Django project to Dokku
  2. How to deploy Django project to Dokku with Docker
Launch Products Faster with Django

SaaS Hammer helps you launch products in faster way. It contains all the foundations you need so you can focus on your product.

Michael Yin

Michael is a Full Stack Developer from China who loves writing code, tutorials about Django, and modern frontend tech.

He has published some ebooks on leanpub and tech course on

He is also the founder of the AccordBox which provides the web development services.

Django SaaS Template

It aims to save your time and money building your product

Learn More

Hotwire is the default frontend solution shipped in Rails, this book will teach you how to make it work with Django, you will learn building modern web applications without using much JavaScript.

Read More
© 2018 - 2024 AccordBox