Django in Production with mod_wsgi and Docker
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 :)
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,
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
--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
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
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
chown www-data /code/.logs/debug.log from within the container
which makes www-data the owner of the file solved it for me.