89/100
Nginx übernimmt die Dateiübertragung: Mit X-Accel-Redirect die Download-Leistung in Django steigern
Die meisten Django-Anwendungen liefern geschützte Dateien (z. B. nur für eingeloggte Nutzer oder nach dem Kauf verfügbar) über FileResponse oder ähnliche Mechanismen aus. Dabei liest der Python-Prozess die Datei und streamt sie an den Client. Bei geringem Traffic oder in internen Umgebungen ist das meist völlig ausreichend.
Wenn die Zahl der Download-Anfragen jedoch stark ansteigt, wird der Anwendungsserver (Python) durch Datei-I/O gebunden: Worker hängen an Übertragungen, und es bleibt weniger Kapazität für Berechtigungsprüfungen, Geschäftslogik oder API-Antworten. Die Lösung: Django entscheidet, wer herunterladen darf – und Nginx übernimmt die eigentliche Dateiübertragung per X-Accel-Redirect.
Warum direktes File-Streaming in Python zum Engpass wird
Der typische Ablauf, wenn Django Dateien selbst ausliefert:
- Anfrage empfangen
- Berechtigungen prüfen
- Datei von Datenträger/Storage lesen
- Datei über den Applikationsprozess an den Client streamen
Gerade Schritt 3 und 4 sind teuer:
- Große Dateien bedeuten lange Übertragungszeiten
- Viele parallele Downloads binden Worker/Threads/Prozesse
- Das führt zu langsamen API-Antworten, Timeouts und Skalierungsdruck
Nginx ist dagegen für die Auslieferung statischer Dateien optimiert: Kernel-Optimierungen wie sendfile, effiziente Event-Loops, Buffering und Range-Request-Handling sind genau auf Dateiübertragungen ausgelegt.
Kernidee von X-Accel-Redirect
Django prüft, Nginx liefert aus.
So funktioniert es
-
Der Client ruft z. B.
/download/123auf. -
Django macht DB-Lookup und Berechtigungsprüfung.
-
Django antwortet mit leerem Body, aber mit Header:
X-Accel-Redirect: /_protected/real/path/to/file.webp
- Nginx erkennt den Header, findet die Datei intern und streamt sie direkt an den Client.
Damit bestimmt Django nur die Erlaubnis, während Nginx die Übertragung übernimmt.
Wann diese Methode besonders sinnvoll ist
1) Viele Download-/Bildanfragen mit hoher Parallelität
- Foren, Messenger, Anhänge, PDF-Downloads
- Viele Requests bei vergleichsweise einfacher Logik
2) Große Dateien oder starke Nutzung von Range-Requests
- Video, Audio, große Archive
- Browser/Player fordern Byte-Ranges an; Nginx verarbeitet das zuverlässig
3) App-Server entlasten und Kosten senken
- Python-Worker sind teuer (RAM/CPU)
- Offloading hält den App-Server frei für Business-Logik
Wann man darauf verzichten kann
- Interne Kommunikation mit geringem Traffic
- Wenige Datei-Requests, bei denen eher API/DB-Logik limitiert
- Dateien liegen in S3/Objektspeichern und werden bereits via CDN oder Pre-Signed URLs ausgeliefert
Dann ist FileResponse oft völlig ausreichend – und man kann X-Accel-Redirect später bei Bedarf nachziehen.
Beispiel: Django + Nginx

Nginx-Konfiguration
Der zentrale Punkt ist internal: Ein internal-Location ist nicht direkt vom Client erreichbar, sondern nur über interne Redirects wie X-Accel-Redirect.
# Geschützte Dateien intern ausliefern
location /_protected/ {
internal;
alias /var/app/protected_media/;
sendfile on;
tcp_nopush on;
# Optional: Cache-/Header-Kontrolle
# add_header Cache-Control "private, max-age=0";
}
- Reale Dateien liegen unter
/var/app/protected_media/ - Öffentliche URLs laufen über Django (z. B.
/download/...) - Interne Pfade werden unter
/_protected/...vereinheitlicht
Django-View-Beispiel
Django prüft nur die Berechtigung, ohne Datei-I/O.
from django.http import HttpResponse, Http404
from django.contrib.auth.decorators import login_required
from django.utils.encoding import iri_to_uri
@login_required
def download(request, file_id):
# 1) DB-Lookup + Berechtigungsprüfung
obj = get_file_object_or_404(file_id) # Beispiel
if not obj.can_download(request.user):
raise Http404
# 2) Internen Pfad für Nginx bauen
internal_path = f"/_protected/{obj.storage_relpath}"
# 3) Nur X-Accel-Redirect setzen
response = HttpResponse()
response["X-Accel-Redirect"] = iri_to_uri(internal_path)
# Optional: Dateiname und MIME-Type
response["Content-Type"] = obj.content_type or "application/octet-stream"
response["Content-Disposition"] = f'attachment; filename="{obj.download_name}"'
return response
- Keine
FileResponse(open(...))-I/O im View - Worker bleiben frei für andere Requests
Sicherheits-Checkliste
-
Interne Pfade serverseitig bestimmen Nutzerinput nie direkt in
X-Accel-Redirectübernehmen. Sichere relative Pfade aus der DB verwenden oder whitelisten. -
internalzwingend setzen Sonst könnte/_protected/...direkt aufgerufen und der Check umgangen werden. -
Berechtigung ausschließlich in Django Nginx liefert nur aus – Zugriffskontrolle muss in Django bleiben.
Alternativen mit Drittanbietern
Wenn es passt, kann man Dateien auch direkt über externe Services ausliefern:
- CDN-Caching für öffentliche Dateien
- Pre-Signed URLs (z. B. S3) für Objektspeicher
Fazit
X-Accel-Redirect verschiebt die teure Dateiübertragung vom App-Server zu Nginx. Django bleibt für Berechtigungen und Business-Logik zuständig, während Nginx die Dateien effizient streamt. Bei geringem Traffic ist FileResponse eine saubere Lösung – wenn aber die Download-Last steigt und Worker durch Datei-I/O blockieren, ist X-Accel-Redirect eine sehr schnelle und wirksame Optimierung.
Merksatz: „Berechtigungen in Django, Auslieferung in Nginx.“