Skip to content

Deployment using Docker

Simon Felix Seeger edited this page May 26, 2026 · 1 revision

Deploying with Docker

The Abitur Song Uploader is designed to be deployed using Docker Compose, since multiple services are required for the application to work correctly. While it is technically possible to manage each service separately, using Docker Compose is strongly recommended.

Docker Compose Configuration

The following example uses:

  • a Gmail account for sending emails
  • a MariaDB database running in a separate container
  • a Q Cluster worker running in a separate container for asynchronous tasks

Important

Values wrapped in angle brackets (<...>) must be replaced with your own configuration values.

services:
  app:
    image: ghcr.io/sfseeger/abitur-song-uploader
    env_file:
      - .env
    volumes:
      - "./media:/app/media"
      - "./static:/app/static"
    depends_on:
      db:
        condition: service_healthy

  q-cluster:
    image: ghcr.io/sfseeger/abitur-song-uploader
    entrypoint: "./entrypoint-djangoq.sh"
    env_file:
      - .env
    volumes:
      - "./backup:/app/backup"
      - "./media:/app/media"
      - "./static:/app/static"
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mariadb:latest
    environment:
      MARIADB_DATABASE: songuploader
      MARIADB_USER: songuploader
    healthcheck:
      test: [ "CMD", "healthcheck.sh", "--connect", "--innodb_initialized" ]
      start_period: 10s
      interval: 10s
      timeout: 5s
      retries: 3
    env_file:
      - .mariadb.env
    volumes:
      - db_data:/var/lib/mysql

volumes:
  db_data:

Example .env file:

# .env
SECRET_KEY="<A long and random key>"

EMAIL_HOST_USER="<application-email>@gmail.com"
EMAIL_HOST_PASSWORD="<Password used to authenticate to the email host>"

WEBSITE_URL="<Your domain or host>"
ADMIN_EMAIL="<Your admin email>"

MYSQL_HOST=db
MYSQL_PASSWORD="<A long and random password>"

TZ="Europe/Berlin"
# .mariadb.env
MARIADB_PASSWORD="<Same as MYSQL_PASSWORD>"

Step-by-Step Deployment Guide

1. Install Docker and Docker Compose

Make sure the following tools are installed on your server:

  • Docker
  • Docker Compose

You can verify the installation with:

docker --version
docker compose version

2. Create a Deployment Directory

Create a new directory for the application and move into it:

mkdir abitur-song-uploader
cd abitur-song-uploader

3. Create the Docker Compose File

Create a file named docker-compose.yaml and paste in the configuration shown above.


4. Create the Environment File

Create a .env file in the same directory:

touch .env

Add your configuration values to the file.

At minimum, you should configure:

  • SECRET_KEY
  • MYSQL_PASSWORD
  • EMAIL_HOST_USER
  • EMAIL_HOST_PASSWORD
  • WEBSITE_URL
  • ADMIN_EMAIL

5. Create Required Directories

Create the directories that will be mounted into the containers:

mkdir -p media static backup

6. Start the Application

Start all services in the background:

docker compose up -d

Docker will automatically:

  • download the required images
  • create the containers
  • start the database
  • start the web application
  • start the Q Cluster worker

7. Verify That Everything Is Running

Check the container status:

docker compose ps

8. Configure a Reverse Proxy (Recommended)

For production deployments, it is recommended to place the application behind a reverse proxy such as:

  • NGINX
  • Apache
  • Traefik
  • Caddy

The reverse proxy should:

  • handle HTTPS
  • serve static files
  • forward requests to port 8000

9. Register Recurring Tasks

To register recurring tasks such as scheduled backups and reminder emails, run the following command:

docker compose exec app python3 manage.py register_tasks register -a

10. Creating users

10.1 Create a superuser

To create a superuser with access to the Django admin interface, run the following command:

docker compose exec -it app python3 manage.py createsuperuser

The superuser account should be removed / disabled after all users are created and permissions have been set up correctly.

10.2 Create regular users

To create regular users, a .csv file with the following format can be used:

Important

Make sure to use a semicolon (;) as the delimiter. The columns first_name, last_name and email are required.

first_name;last_name;email
John;Doe;john.doe@example.com

Then copy the file into the container and run the following command:

docker compose cp users.csv app:/app/web/users.csv
docker compose exec app python3 manage.py createusers /app/web/users.csv

This will create user accounts for all entries in the .csv file and send out the initial password email.

Note

To send out the emails a running Q Cluster worker is required.

Environment Variables

The application is configured using the following environment variables.

If the default value is empty, the variable must be configured manually.

Variables marked with πŸ”’ should be treated as confidential and only be stored in a .env file.

Variable Name Description Default
SECRET_KEY πŸ”’ Secret key for the application. Use a long, random value.
ALLOWED_HOSTS Comma-separated list of allowed hosts. WEBSITE_URL is appended automatically when set. localhost,127.0.0.1
WEBSITE_URL Main URL where the application is reachable. Used in emails and generated links. Don't include the protocol!
URL_SECURE Whether to use https in generated links. If set to True, the application will assume it is running behind a reverse proxy that handles HTTPS. True
CSRF_ALLOWED_ORIGINS Comma-separated list of allowed origins for CSRF requests. WEBSITE_URL is appended automatically when set. Required if the application is accessed via a different domain or subdomain. Same as ALLOWED_HOSTS
MYSQL_DB Database name used by the application. songuploader
MYSQL_USER Database user used by the application. songuploader
MYSQL_PASSWORD πŸ”’ Password for the database user.
MYSQL_HOST Database host or container name. localhost[^1]
TZ Application timezone. Europe/Berlin
MEDIA_BACKUP_DIR Directory used for media backups. /app/backup/media
DB_BACKUP_DIR Directory used for database backups. /app/backup/db
ADMIN_EMAIL Administrator email used for error reporting and user requests. Also displayed in emails and the help page.
STATIC_ROOT Static files directory inside the container. Primarily used during development. /app/static
STATIC_URL URL path for static files. /static/
MEDIA_ROOT Directory where uploaded media files are stored. /app/media
MEDIA_URL URL path for uploaded media files. /media/
EMAIL_HOST SMTP host used for sending emails. smtp.gmail.com
EMAIL_PORT SMTP port used by the email provider. 587
EMAIL_USE_TLS Set to True if the SMTP server uses TLS. True
EMAIL_USE_SSL Set to True if the SMTP server uses SSL. False
EMAIL_SENDER Sender name shown in outgoing emails. Abitur Song Uploader
EMAIL_HOST_USER SMTP username or email address used for sending emails.
EMAIL_HOST_PASSWORD πŸ”’ Password or app password used for SMTP authentication.
DJANGO_LOG_FILE Path to the Django log file. /app/log/django/django.log
DJANGO_LOG_LEVEL Minimum log level written to the log file. INFO

[^1]: Although localhost is the default value, using a dedicated database container or external database server is strongly recommended.


Folder Structure

All application-related files are located inside the /app directory within the container.

Persist any directories you want to keep across container restarts by mounting them as volumes.

β”œβ”€β”€ backup/
β”‚   β”œβ”€β”€ db/                 # Daily database backups
β”‚   └── media/              # Daily media backups
β”œβ”€β”€ log/
β”‚   β”œβ”€β”€ django/
β”‚   β”‚   └── django.log      # Django application logs
β”‚   └── gunicorn/
β”‚       β”œβ”€β”€ access.log      # HTTP access logs
β”‚       └── error.log       # Gunicorn error logs
β”œβ”€β”€ media/                  # Uploaded media files
β”œβ”€β”€ static/                 # Static assets (CSS, JavaScript, etc.)
└── web/                    # Application source code and manage.py

Q Cluster

A Q Cluster worker is required for asynchronous tasks such as:

  • sending emails
  • scheduled backups
  • reminder emails
  • cleaning expired sessions

The worker is started using the following entrypoint:

./entrypoint-djangoq.sh

To register recurring tasks run:

python3 manage.py register_tasks register -a