orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1---
2title: Running a simple Django website in Docker
3slug: running-a-simple-django-website-in-docker
4date: 2022-05-14
5publish_date: 2022-05-14
6tags: webdev
7description: Using Docker to run a simple production and development environments with a few extras thrown in. Easily customized to your preferred language or framework.
8cover_image: django-dockerfile-edited.webp
9---
10
11Docker is a near perfect solution for having project portability across a wide variety of host platforms. I use docker to run my websites on both development computers and servers. For Django my go to Dockerfile looks a little something like this.
12
13```shell
14# django
15#
16# I use this to run most of my django projects in a single container in
17# production. If you wish to seriously reduce the size of this image and you
18# don't need it you can remove the chromium line. I use it for screenshots and
19# pdf creation.
20#
21# Make sure to change the below ENV variables to fit your needs and the gunicorn
22# path to your applications asgi file.
23#
24# You can run this with:
25# docker build --tag overshard/django:latest .
26# docker run -d -p 80:8000 -e DJANGO_SETTINGS_MODULE=project.settings.production \
27# -v /srv/data:/data django:latest
28
29
30FROM alpine:3.16
31
32RUN apk add --update --no-cache \
33 sqlite \
34 python3 py3-pip \
35 nodejs yarn \
36 chromium libstdc++ nss harfbuzz freetype font-noto font-noto-extra font-noto-emoji && \
37 pip install pipenv
38
39COPY Pipfile Pipfile.lock package.json yarn.lock /app/
40
41RUN yarn install && pipenv install --system
42
43COPY . .
44
45RUN yarn webpack:production && \
46 rm -rf node_modules && \
47 python3 manage.py collectstatic --noinput
48
49RUN addgroup -S -g 1000 app && \
50 adduser -S -h /app -s /sbin/nologin -u 1000 -G app app && \
51 chown -R app:app /app
52
53USER app:app
54
55WORKDIR /app
56
57VOLUME /data
58
59EXPOSE 8000
60
61ENV DJANGO_SETTINGS_MODULE=project.settings.production
62
63CMD ["gunicorn", "project.asgi:application", "-k", "uvicorn.workers.UvicornWorker", "-w", "4", "-b", ":8000", "--access-logfile", "-", "--error-logfile", "-"]
64```
65
66A few notes on my choices:
67
68* This assumes you are just using an sqlite database but this can easily scale into using PostgreSQL in coordination with docker-compose
69* I use webpack to build all of my static files on all of my sites hence why nodejs and yarn are included
70* Chromium is used in most of my projects for generating PDFs and screenshots, I've found it the most reliable and consistent way of handling that functionality
71* You'll need both gunicorn and uvicorn installed
72
73You could remove Chromium and save ~400MB of space on a roughly ~450MB image if you have no use for it. It is by far the largest dependency here. I also often use docker-compose in conjunction with this Dockerfile.
74
75```shell
76# django
77#
78# I create a `.env` file in the same folder as my `Dockerfile` and
79# `docker-compose.yml` file with the environmental variables below. Generally my
80# server file struction is `/srv/git/app` for the git bare repository,
81# `/srv/docker/app` for the git repo cloned from the bare repo, and
82# `/srv/data/app` for the data directory mounted to the container.
83#
84# The ports are `8000:8000` because I often use Caddy or Nginx to reverse proxy
85# to the container. You could probably just serve the app directly though with
86# `8000:80` instead if you have no media files.
87
88version: "3"
89
90services:
91 web:
92 build: .
93 volumes:
94 - /srv/data/app/:/data/
95 ports:
96 - "8000:8000"
97 command: gunicorn analytics.asgi:application -k uvicorn.workers.UvicornWorker -w 4 -b :8000 --access-logfile - --error-logfile -
98 restart: unless-stopped
99 environment:
100 DJANGO_SETTINGS_MODULE: ${DJANGO_SETTINGS_MODULE}
101```
102
103This can be used directly in production pretty well however I do put most of my websites behind Caddy using a reverse proxy. If you'd like to see my most up-to-date alpine-docker files you can check them out on my [overshard/dockerfiles GitHub project](https://github.com/overshard/dockerfiles).