89/100 # Laat Nginx de bestandslevering verzorgen in plaats van Django: X-Accel-Redirect voor betere downloadprestaties De meeste Django-applicaties leveren beschermde bestanden (alleen voor ingelogde gebruikers, na betaling, enz.) via `FileResponse` of iets vergelijkbaars: het Python-proces leest het bestand en streamt het naar de client. Bij weinig verkeer of interne communicatie werkt dat prima. Maar zodra het aantal downloadverzoeken sterk toeneemt, raakt de applicatieserver (Python) bezig met bestands-I/O en blijft er minder capaciteit over voor de echte taken (autorisatie, businesslogica, API-responses). De oplossing is om **Django de permissiecheck te laten doen en Nginx de daadwerkelijke bestandsoverdracht** te laten afhandelen via **X-Accel-Redirect**. --- ## Waarom wordt direct streamen vanuit Python een bottleneck? {#sec-df5683b425c0} De gebruikelijke flow is: 1. Verzoek ontvangen 2. Permissies controleren 3. Bestand van schijf/opslag lezen 4. Bestand via het applicatieproces naar de client streamen Met name **stap 3 en 4** zijn zwaar: * Hoe groter het bestand, hoe langer de overdracht duurt * Meer gelijktijdige downloads binden workers/threads/processen * Gevolg: trage API-responses, time-outs en schaaldruk Nginx is juist geoptimaliseerd voor statische bestandsoverdracht met kernel-optimalisaties (`sendfile`), een efficiënte event-loop, buffering en ondersteuning voor range-requests. --- ## Kernidee van X-Accel-Redirect {#sec-8f39639ab234} **Django controleert, Nginx levert.** ### Werking {#sec-acfe1fded112} 1. De client vraagt bijvoorbeeld `/download/123` op. 2. Django doet de DB-lookup en permissiecheck. 3. Django stuurt een lege response terug met header: ``` X-Accel-Redirect: /_protected/real/path/to/file.webp ``` 4. Nginx ziet de header, vindt het bestand intern en levert het direct aan de client. Django leest het bestand dus niet; het beslist alleen of de download is toegestaan. --- ## Wanneer is dit bijzonder nuttig? {#sec-fc58c3d25d4f} ### 1) Veel downloads/afbeeldingen met hoge gelijktijdigheid {#sec-00164dd4ae34} * Community’s, messenger-media, bijlagen, PDF-rapporten * Veel requests met simpele logica ### 2) Grote bestanden of veel range-requests {#sec-e39fd6155745} * Video, audio, grote archieven * Browsers/players gebruiken `Range`; Nginx verwerkt dat doorgaans stabieler ### 3) Kosten van de app-server verlagen {#sec-c09b34610e6f} * Python-workers zijn duur (CPU/RAM) * Offloading laat de app-server focussen op logica --- ## Wanneer kun je het overslaan? {#sec-1357fdc58f72} * Interne communicatie met laag verkeer * Weinig bestandsverzoeken; API/DB-logica is de bottleneck * Bestanden staan in S3/objektopslag en gaan al via CDN of pre-signed URLs Dan is `FileResponse` vaak prima, en kun je later alsnog overstappen. --- ## Implementatievoorbeeld: Django + Nginx {#sec-7b7a69572111} ![Web request flow diagram](/media/editor_temp/6/a1ad0374-979a-447e-b586-81ac02f2b447.png) ### Nginx-configuratie {#sec-f9441826ea70} Cruciaal is `internal`: zo’n location is niet direct door clients te benaderen, alleen via interne redirects zoals X-Accel-Redirect. ```nginx location /_protected/ { internal; alias /var/app/protected_media/; sendfile on; tcp_nopush on; # add_header Cache-Control "private, max-age=0"; } ``` --- ### Django-view {#sec-0bf0a74802d0} ```python 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): obj = get_file_object_or_404(file_id) # voorbeeld if not obj.can_download(request.user): raise Http404 internal_path = f"/_protected/{obj.storage_relpath}" response = HttpResponse() response["X-Accel-Redirect"] = iri_to_uri(internal_path) response["Content-Type"] = obj.content_type or "application/octet-stream" response["Content-Disposition"] = f'attachment; filename="{obj.download_name}"' return response ``` --- ## Beveiligingschecklist {#sec-2fdde1f8ddfe} 1. **Interne paden server-side bepalen** (geen user input in `X-Accel-Redirect`). 2. **`internal` verplicht** om directe toegang tot `/_protected/...` te blokkeren. 3. **Autorisatie in Django**; Nginx doet alleen levering. --- ## Alternatieven {#sec-735de93cc272} * CDN voor publieke bestanden * Pre-signed URLs (S3 e.d.) voor objectopslag --- ## Conclusie {#sec-d2260ecd846a} Door bestandsoverdracht via X-Accel-Redirect naar Nginx te verplaatsen, ontlast je Django en verbeter je prestaties bij veel gelijktijdige downloads of grote bestanden. Bij lage traffic is `FileResponse` nog steeds een prima keuze. Onthoud: **“Permissies in Django, levering in Nginx.”**