Skip to content
Complete setup with tutorial for deploying Django project on docker.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


This is a production-ready setup for running Django 1.11.* with mysql and nginx on Docker. It has sensible defaults for security, scaling, and workflow. It's a robust and simple way to run Django projects on production servers.

Up and running with docker

$ docker build -t <yourname>/django-docker-setup .
$ docker run -d -p 80:80 -v $(pwd):/code --env DJANGO_PRODUCTION=false <yourname>/django-docker-setup


First, install Docker. If you're new to Docker, you might also want to check out the Hello, world! tutorial.

Next, clone this repo:

$ git
$ cd django-docker-setup

(Mac users should clone it to a directory under /Users because of a Docker bug involving Mac shared directories.)

You can also fork this repo or pull it as image from Docker Hub as akkefa/django-docker-setup.

Update the origin to point to your own Git repo:

$ git remote set-url origin

Configure the project

Run docker ps to make sure your Docker host is running. If it's not, run:

$ docker-machine start <dockerhostname>
$ eval "$(docker-machine env <dockerhostname>)"

Build the Docker image (you should be in the django-docker-setup/ directory, which contains the Dockerfile):

$ docker build -t <yourname>/django-docker-setup .

Run the Docker image you just created (the command will be explained in the Development workflow section below):

$ docker run -d -p 80:80 -v $(pwd):/code --env DJANGO_PRODUCTION=false <yourname>/django-docker-setup

Run docker ps to verify that the Docker container is running:

CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                          NAMES
2830610e8c87        <yourname>/django-docker-setup  "/usr/bin/supervisord"   25 seconds ago      Up 25 seconds>80/tcp, 8000/tcp   focused_banach

You should now be able to access the running app through a web browser. Run docker-machine ls to get the local IP address for your Docker host:

NAME           ACTIVE   DRIVER       STATE     URL                         SWARM
mydockerhost   *        virtualbox   Running   tcp://

Open (or your host's address, if it's different) in a browser. You should see a "Hello, world!" message.

Grab the CONTAINER ID from the docker ps output above, and use docker kill to stop the container:

$ docker kill 2830610e8c87

The output of docker ps should now be empty:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Development workflow

You should be inside the django-docker-setup folder, which contains the Dockerfile and this README.

Here's the outline of the workflow:

1. Run the Docker container and mount the local directory containing the Django project code
2. Make changes and test them on the container
3. Commit the changes to the Git repo

Start the Docker container:

$ docker run -d -p 80:80 -v $(pwd):/code --env DJANGO_PRODUCTION=false <yourname>/django-docker-setup

Here's what the flags do:

  • -d: Run in detached mode (i.e., Docker will no longer listen to the console where you ran docker run).
  • -p 80:80: Map port 80 on the host to port 80 on the container. This lets you communicate with Nginx from your browser.
  • -v $(pwd):/code: Mount the current directory as a volume at /code on the Docker container. This lets you edit the code while the container is running so you can test it without having to rebuild the image.
  • --env DJANGO_PRODUCTION=false: Production settings are enabled by default in and defined in This flag prevents from being loaded, which lets you have separate settings for local development (e.g., DEBUG = True and a local development database).

Point your browser to your Docker host's IP address. You should see the "Django default page" message again.

Point your browser to http://<ip address>/admin/. You should be able to log in with username root and the root password you set in config.ini.

Run docker ps to get the CONTAINER ID and use docker kill to stop the container:

$ docker ps
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                          NAMES
39b60b7eb954        <yourname>/django-docker-setup  "/usr/bin/supervisord"   4 minutes ago       Up 3 minutes>80/tcp, 8000/tcp   elegant_banach
$ docker kill 39b60b7eb954

Editing files

Unlike the Django development server, this configuration won't automatically detect and load changes in Python files. You'll have to manually refresh the server when you make changes (except for templates, which will automatically update). First, open a shell on the dev server:

$ docker exec -ti <CONTAINER ID> /bin/bash

Then, each time you change a Python file, run:

$ supervisorctl restart gunicorn

Updating models

When you update your models, django-docker-setup will automatically run python makemigrations and python migrate the next time you run the Docker image. There are a few caveats:

  • Don't delete the migrations/ folders inside your apps (or else you'll have to do something like editing to add migrate --fake-initial—ugh)
  • When adding new model fields, remember to set a default (or else migrate will fail)

Still, there will be times when you need to create migrations by hand. Django currently doesn't support fully automated migration creation—for instance, you might get a prompt like this:

Did you rename job.cost to job.paid (a IntegerField)? [y/N]

As far as I know, this can't be automated. To handle this scenario, open a shell on your development Docker machine:

$ docker run -ti -p 80:80 -v $(pwd):/code --env DJANGO_PRODUCTION=false <yourname>/django-docker-setup /bin/bash

Then, start the database server and invoke

$ /etc/init.d/mysql start
$ ./

This will call python makemigrations and prompt you if necessary. It will create the necessary migration files. The migration will be automatically applied the next time you run the Docker image in production. (This can be scary. Make a clean backup of your code and database before applying the migration in production in case you need to roll back.)

You can’t perform that action at this time.