Content
Create myenv.env
An .env file is a good way to store secrets locally on your computer.
Never commit your .env files to github. This is why they are in the
.gitignorelist
Generate Local Secret
cd homepage
python manage.py shell
paste in the following text to generate your my_env.env file
from django.core.management.utils import get_random_secret_key
key_string = get_random_secret_key()
template = '''DJANGO_SECRET_KEY='{key_string}'
DJANGO_DEBUG=True
MYSQL_ROOT_PASSWORD='<create-a-robust-pw-and-paste-here>'
MYSQL_DATABASE='<pick-a-database-name>'
MYSQL_USER='<create-a-random-username-and-paste-here>'
MYSQL_PASSWORD='<create-a-second-robust-pw-and-paste-here>'
'''
with open('../my_env.env','w') as f:
s=template.format(key_string=key_string)
f.write(s)
Only run this code once. Re-running it will overwrite your file and potentially lock you out of your own database.
Edit the remaining fields, using your favorite key generator or password manager to generate the required info.
What is Docker
make a new subidrectory named docker/
Install
see lecture 2
Docker images
Docker images run on your machine, often with administrative permissions. If you want to make your own image in order to control what software is built, do the following:
make a new file, docker/image_django/Dockerfile. Paste in the following text:
FROM python:3.14.2-slim-bookworm
ARG DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y \
libmariadb-dev \
build-essential \
default-libmysqlclient-dev \
python3-dev \
pkg-config \
nano \
iputils-ping \
net-tools \
iproute2
WORKDIR /build
COPY requirements.txt .
RUN pip install -r requirements.txt
Docker Images
Django Image
Next create a build script at docker/image_django/build. Paste in the following:
#!/usr/bin/bash
cp ../../requirements.txt ./ && \
docker build -t django_markdown . --progress plain && \
rm ./requirements.txt
then from docker/image_django/build run
chmod +x build
./build
Mariadb image
in docker/image_mariadb/ create Dockerfile
FROM mariadb:latest
ARG DEBIAN_FRONTEND=noninteractive
RUN apt update && apt install -y \
mariadb-client
and create docker/image_mariadb/build
#!/usr/bin/bash
docker build -t my_maria_db .
then from docker/image_mariadb/build run
chmod +x build
./build
caddy image
create docker/image_caddy/Dockerfile
FROM caddy:2-alpine
RUN apk add --no-cache \
bash
create docker/image_caddy/build
#!/usr/bin/bash
docker build -t django_caddy .
then from docker/image_caddy run
chmod +x build
./build
Docker Compose
Create your docker compose file
Create docker/docker-compose.yaml and paste in the following:
Note: you have to modify
/path/to/your/markdown/source/fileswith your own path
services:
django:
hostname: django
container_name: django
# image: danb0b/django_markdown:latest
image: django_markdown:latest
env_file: "../my_env.env"
volumes:
- ../homepage:/homepage
- /home/danaukes/repos/websites/danb0b.github.io:/source
- ../collected_files:/files
- ./log:/log
working_dir: /homepage
command: bash -c "./run"
restart: unless-stopped
depends_on:
db:
condition: service_healthy
restart: true
required: true
networks:
- local
caddy:
hostname: caddy
container_name: caddy
# image: danb0b/django_caddy:latest
image: django_caddy:latest
cap_add:
- NET_ADMIN
ports:
- 8000:8000
- 8001:8001
volumes:
- ./caddyconf:/etc/caddy
- ./caddysite:/srv
- ./caddydata:/data
- ./caddyconfig:/config
- ../collected_files:/files
restart: unless-stopped
networks:
- local
db:
hostname: db
container_name: db
# image: danb0b/my_maria_db:latest
image: my_maria_db:latest
restart: unless-stopped
volumes:
- ./mysql:/var/lib/mysql
env_file: "../my_env.env"
networks:
- local
healthcheck:
test: mariadb-admin ping -h 127.0.0.1 -u $$MYSQL_USER --password=$$MYSQL_PASSWORD
start_period: 5s
interval: 5s
timeout: 5s
retries: 5
networks:
local:
driver: bridge
Caddy
Caddy is a web server that is easily configured, and can be easily set up to serve secure https pages with the LetsEncrypt service.
create a new file at docker/caddyconf/Caddyfile. Paste in the following:
:8000 {
reverse_proxy {
to django:8000
}
}
:8001 {
root * /files
file_server
log {
output file /var/log/danaukes_files.log
format json
}
}
Update homepage/homepage/settings.py
below imports add:
import os
replace
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-m7hog_clla!4b0gx^-0i*aa^^9ub+9+#xz_pz=$f%orx)=cmj^'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
with
SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY')
DEBUG = os.environ.get('DJANGO_DEBUG', '') != 'False'
ALLOWED_HOSTS = [
'127.0.0.1',
'localhost',
]
Replace
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
with
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ.get('MYSQL_DATABASE'),
'USER': os.environ.get('MYSQL_USER'),
'PASSWORD': os.environ.get('MYSQL_PASSWORD'),
'HOST': 'db',
'PORT': '3306',
}
}
replace
STATIC_URL = 'static/'
STATIC_ROOT = '/home/danaukes/repos/django/django_homepage_public/collected_files'
STATICFILES_DIRS = [
'/home/danaukes/repos/websites/danb0b.github.io/static',
'/home/danaukes/repos/websites/danb0b.github.io/content',
]
# custom addition for defining the search path for markdown file imports
MARKDOWN_SOURCE_PATH = '/home/danaukes/repos/websites/danb0b.github.io/content'
with:
STATIC_URL = 'http://127.0.0.1:8001/'
STATIC_ROOT = '/files'
STATICFILES_DIRS = [
'/source/static',
'/source/content',
]
# custom addition for defining the search path for markdown file imports
MARKDOWN_SOURCE_PATH = '/source/content'
# Added to permit only logins when the site is found at the following domains
CSRF_TRUSTED_ORIGINS = ['http://127.0.0.1',]
Update .gitignore
make sure your gitignore file has a few new files. Replace it with the following:
**/__pycache__/*
**/migrations/*
.venv/*
*.env
homepage/db.sqlite3
docker/mysql/*
collected_files/*
docker/caddyconfig/*
docker/caddydata/*
docker/log/*
.vscode/settings.json
Update run
We will be using a server called gunicorn to host caddy. Replace the contents of homepage/run with:
#!/usr/bin/bash
# python3 manage.py runserver 0.0.0.0:8000
python -m gunicorn -w 4 --proxy-protocol auto -b 0.0.0.0:8000 --access-logfile '/log/gunicorn.log' homepage.wsgi:application
Create an import command
inside homepage/ create import:
#!/usr/bin/bash
python3 manage.py import_markdown
make it executible:
chmod +x import
add three new files
Add these files to your top-level project directory:
collect
#!/usr/bin/bash
docker exec -it django ./collect
import
#!/usr/bin/bash
docker exec -it django ./import
migrate
#!/usr/bin/bash
docker exec -it django ./migrate
make executible
chmod +x collect
chmod +x import
chmod +x migrate
Run
from your docker/ subfolder, run
docker compose up
In a separate window in the main project folder type:
docker exec -it django ./startup
follow the prompts to create a new superuser and import your markdown.
You have to do this again because you are using a new database for the first time
once complete, you can run:
./collect
to collect all static files
Git Repository
The branch reflecting these changes can be found here:
https://github.com/danb0b/django_homepage_public/tree/Lecture10-production-local