Minimal Django and Docker configuration

1st: 30 March 2022 • Last Updated: 30 March 2022 • 3 min read

I see a lot of people asking how to deploy Django apps. Surely, Django has a “flaw” that is deploying in production. I also had my share of difficulty on this matter but, now, I use a simple approach that has been serving me well. I’ll try to describe it here. So, let’s get to it:

Dockerfile

My Dockerfile is extremely straight forward. I have a version of it using pip-tools instead of regular pip. It doesn’t really matter since, in the end, you have to install you dependencies through requirements.txt. Use whatever floats your boat.

FROM python:3.10

ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE 1

RUN mkdir /code
WORKDIR /code/
ADD . /code/

RUN pip install --upgrade pip \&\& \
    pip install --no-cache-dir -r /code/requirements.txt

EXPOSE 8001

docker-compose.yml

Some notes on this configuration: 1. <service name> can be any name you choose for your service. 2. Same with <your image name>. 3. Mapping ports here is important if you’re going to use this service proxied through Nginx, Apache or whatever you use to expose your app to the outside world. 4. As with ports, I do map a external volume to the service. It’s better to serve static content from Nginx (since I use it to expose my apps) than from Django. Even if you could use Whitenoise for that. Django is not the ideal tool for static content.

version: '3'

services:
  <service name>:
    image: <your image name>
    build: blog
    ports:
      - "8001:8001"
    volumes:
      - /var/www/<your static content folder inside Nginx>/media:/core/media
    entrypoint: sh docker-entrypoint.sh

Docker entrypoint

The docker-entrypoint.sh script that is referenced in the docker-compose.yml is as follows:

#!/bin/bash
python manage.py collectstatic --noinput
python manage.py migrate

gunicorn -b 0.0.0.0:8001 -w 4 config.wsgi:application

Nginx sites-available

Since I’m using Nginx, to configure the proxy to my container, I just need to point it to the IP address and exposed port (8001 - from above):

server {
    server_name <domain name> www.<domain name> # e.g. server_name domain.com www.domain.com;

    location / {
        proxy_pass http://<IP address>:8001;
    }
}

Note that I use http:// and not https:// since Nginx will handle TLS stuff and Django is not configured to handle this kind of connection (never tried to do that).

And that’s pretty much it. For more complex situations, you could use my other approach: Django (DRF) 12 Factor App with examples.

Again, hope it helps.