Files
2026-05-21 10:36:16 +02:00

4.6 KiB

Serienbrief

Django-Webanwendung zur Erzeugung von Serienbriefen aus DOCX-Vorlagen und CSV-Empfängerlisten. Läuft als Compose-Stack, HTTP-only — TLS terminiert ein vorgelagerter Nginx-Reverse-Proxy außerhalb dieses Stacks.

Architektur

LAN-Client ──HTTPS──▶ Externer Nginx-Proxy ──HTTP──▶ App-Stack (dieses Repo)
                       (TLS-Terminierung)            │
                                                     ├─ nginx (intern, :8080)
                                                     ├─ web (Gunicorn / Django)
                                                     ├─ worker (Celery)
                                                     ├─ beat (Celery Scheduler)
                                                     ├─ db (PostgreSQL 16)
                                                     ├─ redis (Celery Broker)
                                                     └─ backup (nightly pg_dump)

Der externe Proxy muss diese Header setzen:

  • X-Forwarded-Proto: https
  • X-Forwarded-For: <client>
  • Host: <serienbrief.lan>

Verzeichnisstruktur

serienbrief/
├── docker-compose.yml             # Prod-Stack
├── docker-compose.override.yml    # Dev-Overrides (Auto-Merge)
├── .env.example                   # Konfig-Template
├── .devcontainer/                 # VS Code Dev-Container
├── .vscode/                       # Launch, Tasks, Settings
├── nginx/                         # App-interner Nginx (HTTP)
├── app/                           # Django-Projekt
│   ├── Dockerfile                 # Multi-Stage: builder/dev/runtime
│   ├── requirements.txt
│   ├── requirements-dev.txt
│   ├── pyproject.toml             # Ruff & Pytest
│   ├── manage.py
│   ├── config/                    # Settings, URLs, WSGI
│   └── mailmerge/                 # Django-App: Models, Views, Tasks
├── postgres/init/                 # SQL-Init-Scripts (optional)
├── secrets/                       # Passwort-Files (chmod 600)
└── backups/                       # DB- & Media-Dumps

Erstinbetriebnahme (Prod)

cp .env.example .env
nano .env                          # Werte setzen

mkdir -p secrets
openssl rand -base64 32 > secrets/postgres_password.txt
chmod 600 secrets/postgres_password.txt

docker compose -f docker-compose.yml build
docker compose -f docker-compose.yml up -d
docker compose exec web python manage.py createsuperuser

Der externe Proxy zeigt dann z.B. so auf den Stack:

location / {
    proxy_pass http://app-host:8080;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
}

Entwicklung in VS Code

Variante A — Dev-Container (empfohlen)

  1. VS Code öffnet das Projekt
  2. Extension Dev Containers installiert
  3. Command Palette → Dev Containers: Reopen in Container
  4. VS Code startet Compose mit Override (Build-Target dev, Code-Mount, Hot-Reload)
  5. Terminal im Container: python manage.py migrate
  6. Browser: http://localhost:8000

Variante B — Lokal mit Compose im Hintergrund

docker compose up -d              # Override wird automatisch geladen
docker compose logs -f web

Code-Änderungen sind sofort wirksam (Bind-Mount + runserver mit Auto-Reload).

Debugging

Im Container läuft debugpy auf Port 5678. In VS Code:

  • Run & Debug → Django: attach (debugpy in Container)
  • Breakpoints überall im Code setzen

Alternativ Task django: start debugpy ausführen und attachen.

Häufige VS-Code-Tasks

Strg+Shift+PTasks: Run Task:

Task Wirkung
compose: up Stack starten
compose: logs web Live-Logs
django: makemigrations Migrations erzeugen
django: migrate Migrations anwenden
django: shell Django-Shell
django: createsuperuser Admin-User anlegen
tests: pytest Tests laufen lassen
lint: ruff Linting

Härtungs-Hinweise

  • Externe Proxy-Konfiguration (TLS, HSTS, CSP, Rate-Limit) muss vorhanden sein
  • APP_BIND_IP=127.0.0.1 in .env außer der externe Proxy läuft auf anderem Host
  • DJANGO_ALLOWED_HOSTS und CSRF_TRUSTED_ORIGINS strikt setzen
  • SECURE_PROXY_SSL_HEADER ist gesetzt — damit erkennt Django korrekt, dass der Client über HTTPS kam
  • Postgres und Redis sind nicht nach außen exponiert (nur im backend-Netz)
  • Container laufen non-root, read_only, mit no-new-privileges
  • Backups regelmäßig auf zweites System spiegeln (Borg/Restic)