Django in Production with mod_wsgi and Docker
created
This article will show you how to run Django in production with docker and apache2/mod_wsgi. While there are several guides on how to do it, I found no simple enough tutorial on how to do it since all of the existing solutions require a lot of configuration or a custom docker image. The solution I found is way quicker and requires close to no configuration.
Guides I found:
- Django with Apache and mod_wsgi assumes you have installed everything already and requires configuration possibly unnecessary for a dockerized version
- mod_wsgi explains how to install mod_wsgi, but not how to use Django with it
So, let's do this. If you just want to see the final Dockerfile, scroll to the end of the article :)
Prerequisites
I assume you have some Dockerfile with Django application setup and run Django via the command that spins up the development server:
FROM python:3.6
WORKDIR /code/
# copy and install requirements first to leverage caching
COPY requirements.txt /code/
RUN pip install -r requirements.txt
# copy the actual code
COPY . /code/
CMD ./manage.py runserver 0.0.0.0:8000
Step 1: Install Apache
We basically need a working Apache setup to run python code via mod_wsgi. So in our Dockerfile, we need to install apache2 and apache2-dev.
RUN apt-get install apache2 apache2-dev
Step 2: install mod_wsgi
We want to run our project within a container. The mod_wsgi documentation says the easiest and preferred using docker is to use mod_wsgi-express as it does not require any configuration. mod_wsgi-express can be used as a command after you have installed it via pip. So we need to add:
RUN pip install mod_wsgi
Step 3: run Django inside Apache with mod_wsgi
Lastly, we simply have to run mod_wsgi-express which will start an apache instance with our Django project. This can be achieved via:
mod_wsgi-express start-server /code/project_name/wsgi.py --user www-data --group www-data
The wsgi.py file is auto-generated by Django's startproject
command and inside you app's folder,
i.e. django-project/project_name
.
So, to run our project within Apache after we've set-up everything in the Dockerfile,
we have to add a CMD
command at the end of the Dockerfile:
CMD mod_wsgi-express start-server /code/connect_web/wsgi.py --user www-data --group www-data
The --user
and --group
parameters make sure Apache isn't run as root which results in errors.
If you want to find out, just run the command without them.
Final Dockerfile: Installing and running Apache and mod_wsgi within Docker
Your final Dockerfile should now look like this:
FROM python:3.6
# update packages
RUN apt-get -qq update
RUN apt-get install --yes apache2 apache2-dev
RUN pip install mod_wsgi
RUN mkdir /code
WORKDIR /code
COPY . /code/
CMD mod_wsgi-express start-server /code/project_name/wsgi.py --user www-data --group www-data
Troubleshooting
If you have any problems, check the logs. Their locations are outputted when starting the container:
web_1 | Server URL : http://localhost:8000/
web_1 | Server Root : /tmp/mod_wsgi-localhost:8000:0
web_1 | Server Conf : /tmp/mod_wsgi-localhost:8000:0/httpd.conf
web_1 | Error Log File : /tmp/mod_wsgi-localhost:8000:0/error_log (warn)
web_1 | Request Capacity : 5 (1 process * 5 threads)
web_1 | Request Timeout : 60 (seconds)
web_1 | Startup Timeout : 15 (seconds)
web_1 | Queue Backlog : 100 (connections)
web_1 | Queue Timeout : 45 (seconds)
web_1 | Server Capacity : 20 (event/worker), 20 (prefork)
web_1 | Server Backlog : 500 (connections)
web_1 | Locale Setting : en_US.UTF-8
If you want to monitor them, just tail -f
them:
tail -f /tmp/mod_wsgi-localhost:8000:0/error_log
Permission problems
At first, I got an Internal Server Error
when opening the page on my machine.
After checking the logs as described above, mod_wsgi seemed to have problems with file permissions on .logs/debug.log
.
A simple chown www-data /code/.logs/debug.log
from within the container
which makes www-data the owner of the file solved it for me.