Reverse-Proxy-Anforderung¶
Bifolk muss immer hinter einem Reverse-Proxy (z. B. Traefik, Nginx oder Caddy) betrieben werden. Der direkte Zugang zum Internet ohne Proxy ist keine unterstützte Konfiguration.
Zielgruppe: Systemadministratoren, DevOps-Ingenieure
Warum ein Reverse-Proxy erforderlich ist¶
Bifolk delegiert mehrere Sicherheitsaufgaben bewusst an die Reverse-Proxy-Schicht, anstatt diese in Django zu implementieren:
- TLS-Terminierung — HTTPS wird vom Proxy verwaltet, nicht von der Django-Anwendung.
- HTTP-Sicherheitsheader — Header wie HSTS, CSP und
X-Content-Type-Optionswerden vom Proxy gesetzt und können nicht garantiert werden, wenn die Anwendung direkt aufgerufen wird. - Endpunkt-Zugangskontrolle — Interne Endpunkte (z. B.
/health/) müssen auf Proxy-Ebene für den öffentlichen Zugang gesperrt werden.
Danger
Der direkte Zugriff auf Bifolk ohne Reverse-Proxy entfernt all diese Schutzmaßnahmen. Die Anwendung selbst setzt keine Sicherheitsheader durch.
Erforderliche Sicherheitsheader¶
Ihr Reverse-Proxy muss die folgenden Header bei allen Antworten setzen:
| Header | Empfohlener Wert |
|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Referrer-Policy |
strict-origin-when-cross-origin |
Content-Security-Policy |
Siehe Beispiel unten |
Permissions-Policy |
geolocation=(), microphone=(), camera=() |
Content-Security-Policy¶
Bifolk verwendet Chart.js (vom jsDelivr-CDN), Leaflet (von unpkg und jsDelivr-CDN), Bootstrap und liefert eigene statische Dateien aus. Eine Basis-CSP, die diese Quellen abdeckt:
Content-Security-Policy:
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net https://unpkg.com;
style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://unpkg.com;
img-src 'self' data: https://*.tile.openstreetmap.org;
font-src 'self';
connect-src 'self';
frame-ancestors 'none';
Note
Testen Sie die CSP zunächst im Report-Only-Modus (Content-Security-Policy-Report-Only), um Verstöße zu erkennen, bevor Sie diese durchsetzen.
Nur intern erreichbare Endpunkte¶
Der folgende Endpunkt darf nicht aus dem öffentlichen Internet erreichbar sein:
| Endpunkt | Zweck | Einschränkung |
|---|---|---|
/health/ |
Container-Gesundheitsprüfung (gibt Datenbankverbindungsstatus preis) | Nur intern / Container-Netzwerk |
Sperren Sie diesen Endpunkt auf Traefik-Router-Ebene oder entsprechend.
Traefik-Konfigurationsbeispiel¶
Sicherheitsheader-Middleware¶
# traefik/dynamic/middlewares.yml
http:
middlewares:
bifolk-security-headers:
headers:
stsSeconds: 31536000
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
contentTypeNosniff: true
frameDeny: true
referrerPolicy: "strict-origin-when-cross-origin"
permissionsPolicy: "geolocation=(), microphone=(), camera=()"
customResponseHeaders:
Content-Security-Policy: >-
default-src 'self';
script-src 'self' https://cdn.jsdelivr.net https://unpkg.com;
style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://unpkg.com;
img-src 'self' data: https://*.tile.openstreetmap.org;
font-src 'self';
connect-src 'self';
frame-ancestors 'none';
Sperrung des Health-Endpunkts¶
# traefik/dynamic/routers.yml
http:
routers:
bifolk:
rule: "Host(`ihredomain.de`) && !PathPrefix(`/health/`)"
middlewares:
- bifolk-security-headers
service: bifolk
tls:
certResolver: letsencrypt
Vertrauenswürdige Proxys¶
Konfigurieren Sie TRUSTED_PROXIES in Ihrer .env-Datei mit der IP des Traefik-Containers, damit X-Forwarded-For-Header für Zugriffsprotokollierung und Rate-Limiting vertrauenswürdig sind:
HTTPS-Schema und E-Mail-Links¶
Wenn Traefik (oder ein anderer Proxy) TLS terminiert, sieht die Django-Anwendung intern nur einfaches HTTP. Ohne zusätzliche Konfiguration verwenden Einladungslinks und andere generierte URLs http:// statt https://.
Setzen Sie TRUST_X_FORWARDED_PROTO=True, damit Django den X-Forwarded-Proto-Header liest, den der Proxy weiterleitet:
SITE_DOMAIN legt den öffentlichen Hostnamen fest, der in Einladungs-E-Mails, allauth-E-Mails (z. B. E-Mail-Verifizierung) und QR-Codes verwendet wird. Ohne diese Einstellung wird auf den ersten Eintrag in DJANGO_ALLOWED_HOSTS zurückgefallen, der in Docker-Setups oft localhost ist.
Warning
TRUST_X_FORWARDED_PROTO sollte nur aktiviert werden, wenn der Reverse-Proxy unter eigener Kontrolle steht und sichergestellt ist, dass er den X-Forwarded-Proto-Header aus nicht vertrauenswürdigen eingehenden Anfragen entfernt. Andernfalls könnten Clients das Schema fälschen.
Weitere Details zu diesen Einstellungen finden Sie unter Konfiguration.
Nginx-Konfigurationsbeispiel¶
Falls Sie Nginx als Reverse-Proxy verwenden:
server {
listen 443 ssl;
server_name ihredomain.de;
# TLS
ssl_certificate /etc/ssl/certs/ihredomain.pem;
ssl_certificate_key /etc/ssl/private/ihredomain.key;
# Sicherheitsheader
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
# Internen Health-Endpunkt sperren
location /health/ {
deny all;
return 404;
}
location / {
proxy_pass http://bifolk-app:8000;
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 $scheme;
}
}
Mediendateien ausliefern¶
Bifolk liefert vom Benutzer hochgeladene Mediendateien (Profilbilder, Bienenstock-Fotos und Exportdateien) über Django mit Authentifizierungsprüfungen aus. Der Reverse-Proxy muss /media/-Anfragen durch die Django-Anwendung weiterleiten — sie dürfen nicht direkt aus dem Docker-Volume ausgeliefert werden.
Danger
Wenn Ihr Reverse-Proxy /media/ direkt aus dem Speicher-Volume ausliefert (z. B. über einen Nginx-alias oder Traefik-serveFile-Middleware), werden alle Authentifizierungskontrollen umgangen. Jeder, der eine Datei-URL kennt, kann sie ohne Anmeldung herunterladen.
Was Django für Mediendateien erzwingt¶
| Dateityp | Schutz |
|---|---|
| Profilbilder, Bienenstock-Fotos | @login_required — nicht authentifizierte Anfragen werden zur Anmeldung weitergeleitet |
Exportdateien (/media/exports/) |
@login_required + Überprüfung der Organisationsmitgliedschaft. Nicht-Mitglieder erhalten 404. |
| Alle Mediendateien | Schutz vor Pfad-Traversal |
Korrekte Nginx-Konfiguration¶
Leiten Sie /media/ an die Anwendung weiter, nicht an das Volume:
location /media/ {
# Verwenden Sie hier KEIN alias oder root.
# Weiterleitung durch Django zur Authentifizierungsprüfung.
proxy_pass http://bifolk-app:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Korrekte Traefik-Konfiguration¶
Fügen Sie keine serveFile- oder fileServer-Regel für /media/ hinzu. Die Standard-proxy_pass an den App-Container ist ausreichend und korrekt.
Header überprüfen¶
Überprüfen Sie nach der Bereitstellung, ob die Sicherheitsheader vorhanden sind. Verwenden Sie dazu die Entwicklertools des Browsers oder eine Befehlszeilenprüfung:
In der Antwort sollten Strict-Transport-Security, X-Content-Type-Options, X-Frame-Options und Referrer-Policy enthalten sein.
Online-Tools wie securityheaders.com können Ihre Domain scannen und fehlende oder falsch konfigurierte Header melden.
Nächste Schritte¶
- Installation - Vollständige Installationsanleitung
- Konfiguration - Umgebungsvariablen-Referenz einschließlich
TRUSTED_PROXIES - Monitoring - Log-Dateispeicherorte und Zugriffslog-Format