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?

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

Django controleert, Nginx levert.

Werking

  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

  1. 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?

1) Veel downloads/afbeeldingen met hoge gelijktijdigheid

  • Community’s, messenger-media, bijlagen, PDF-rapporten
  • Veel requests met simpele logica

2) Grote bestanden of veel range-requests

  • Video, audio, grote archieven
  • Browsers/players gebruiken Range; Nginx verwerkt dat doorgaans stabieler

3) Kosten van de app-server verlagen

  • Python-workers zijn duur (CPU/RAM)
  • Offloading laat de app-server focussen op logica

Wanneer kun je het overslaan?

  • 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

Web request flow diagram

Nginx-configuratie

Cruciaal is internal: zo’n location is niet direct door clients te benaderen, alleen via interne redirects zoals X-Accel-Redirect.

location /_protected/ {
    internal;
    alias /var/app/protected_media/;
    sendfile on;
    tcp_nopush on;
    # add_header Cache-Control "private, max-age=0";
}

Django-view

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

  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

  • CDN voor publieke bestanden
  • Pre-signed URLs (S3 e.d.) voor objectopslag

Conclusie

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.”