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: httpsX-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)
- VS Code öffnet das Projekt
- Extension Dev Containers installiert
- Command Palette →
Dev Containers: Reopen in Container - VS Code startet Compose mit Override (Build-Target
dev, Code-Mount, Hot-Reload) - Terminal im Container:
python manage.py migrate - 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+P → Tasks: 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.1in.envaußer der externe Proxy läuft auf anderem HostDJANGO_ALLOWED_HOSTSundCSRF_TRUSTED_ORIGINSstrikt setzenSECURE_PROXY_SSL_HEADERist 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, mitno-new-privileges - Backups regelmäßig auf zweites System spiegeln (Borg/Restic)