# Ne laissez pas Django servir les fichiers directement : boostez les performances de téléchargement avec X‑Accel‑Redirect La plupart des services Django livrent des fichiers protégés (téléchargement réservé aux utilisateurs connectés, accès après paiement, etc.) en lisant le fichier via un `FileResponse` et en le transmettant au client. Cela fonctionne bien tant que le trafic est faible ou que la communication reste interne. Lorsque les requêtes de fichiers explosent, le serveur d’application (Python) se retrouve bloqué dans la tâche de livraison, ce qui rend difficile l’exécution des autres logiques (vérification d’autorisation, traitement métier, API, etc.). C’est ici qu’intervient la technique **X‑Accel‑Redirect** : Django vérifie les droits, Nginx s’occupe de la transmission. --- ## Pourquoi l’envoi direct par Python crée un goulot d’étranglement ? Le flux typique est le suivant : 1. Réception de la requête 2. Vérification des droits 3. Lecture du fichier depuis le disque ou le stockage 4. Envoi du fichier via le processus Python (streaming) Les étapes 3 et 4 sont lourdes : * Plus le fichier est gros, plus le temps de transmission est long * Plus il y a de téléchargements simultanés, plus les workers/threads/processus sont bloqués * Cela entraîne des retards de réponse API, des time‑outs et la nécessité d’augmenter les ressources serveur Nginx, quant à lui, est optimisé pour la diffusion de fichiers statiques grâce à `sendfile`, un boucle d’événements efficace, le buffering et la prise en charge des requêtes `Range`. --- ## L’idée clé de X‑Accel‑Redirect **Django fait la vérification, Nginx fait la transmission.** ### Fonctionnement 1. Le client demande `/download/123` 2. Django effectue la requête DB et la vérification des droits 3. Django renvoie une réponse vide avec l’en-tête suivant : ``` X-Accel-Redirect: /_protected/real/path/to/file.webp ``` 4. Nginx lit cet en‑tête, trouve le fichier en interne et le transmet directement au client Ainsi, Django ne lit pas le contenu du fichier, il se contente de décider si l’utilisateur a le droit de le télécharger. --- ## Quand cette approche est particulièrement utile ### 1) Services à forte charge de téléchargement ou d’images * Communautés, messageries, pièces jointes, rapports PDF * Modèle « nombreux requêtes, logique simple » → X‑Accel‑Redirect brille ### 2) Fichiers volumineux ou requêtes `Range` critiques * Vidéos, audios, archives * Les navigateurs ou lecteurs utilisent `Range` pour la lecture ou le téléchargement progressif ; Nginx gère ces transferts de façon plus fiable ### 3) Réduction des coûts du serveur d’application * Les workers Python sont coûteux (mémoire/CPU) ; les bloquer sur la transmission est inefficace * En déléguant la transmission à Nginx, le serveur d’application peut se concentrer sur la logique métier --- ## Quand on peut s’en passer * Communication interne avec faible trafic * Peu de requêtes de fichiers, la logique API/DB est le vrai goulot * Fichiers stockés sur un service externe (S3, etc.) déjà servi par un CDN ou des URL pré‑signées Dans ces cas, `FileResponse` reste une solution simple et suffisante. --- ## Exemple d’implémentation : Django + Nginx ![Diagramme de flux de requête Web](/media/editor_temp/6/a1ad0374-979a-447e-b586-81ac02f2b447.png) ### Configuration Nginx L’essentiel est l’attribut `internal`. Un `location` marqué `internal` ne peut être accédé que par une redirection interne via `X‑Accel‑Redirect`. ```nginx # Point interne servant les fichiers protégés location /_protected/ { internal; # Répertoire contenant les fichiers réels alias /var/app/protected_media/; # Options de performance (à ajuster selon l’environnement) sendfile on; tcp_nopush on; # Gestion optionnelle du cache/headers # add_header Cache-Control "private, max-age=0"; } ``` * On suppose que les fichiers existent sous `/var/app/protected_media/` * L’URL publique est `/download/...` via une route Django * Le chemin interne est toujours `/_protected/...` --- ### Vue Django Django vérifie les droits puis renvoie uniquement l’en‑tête. ```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): # 1) Recherche DB + vérification des droits obj = get_file_object_or_404(file_id) # Exemple if not obj.can_download(request.user): raise Http404 # 2) Construction du chemin interne (sous /_protected/) internal_path = f"/_protected/{obj.storage_relpath}" # 3) En‑tête X‑Accel‑Redirect, corps vide response = HttpResponse() response["X-Accel-Redirect"] = iri_to_uri(internal_path) # (Optionnel) Nom de fichier / type MIME response["Content-Type"] = obj.content_type or "application/octet-stream" response["Content-Disposition"] = f'attachment; filename="{obj.download_name}"' return response ``` Points clés : * Pas de `FileResponse(open(...))` → pas d’I/O fichier * Le temps de traitement par le worker est réduit, il n’est pas bloqué par la transmission --- ## Checklist de sécurité ### 1) Le chemin interne doit être déterminé par le serveur * Empêcher les attaques de type `/_protected/../../etc/passwd` * Utiliser uniquement des chemins relatifs sûrs stockés en base ou une liste blanche ### 2) Le `location` doit être `internal` * Sans `internal`, un utilisateur pourrait accéder directement à `/_protected/...` ### 3) La logique d’autorisation doit rester dans Django * Nginx ne fait que transmettre ; toute décision d’accès doit être prise par Django --- ## Alternatives via un service tiers Si le budget le permet, on peut envisager de servir les fichiers depuis un stockage tiers (S3, etc.). * **CDN** : pour les fichiers publics, un CDN avant Nginx est encore plus performant * **URL pré‑signées** : pour les objets S3, une URL pré‑signée peut remplacer X‑Accel‑Redirect --- ## Conclusion En résumé, déléguer la diffusion de fichiers à Nginx via X‑Accel‑Redirect améliore nettement les performances et la scalabilité, surtout lorsqu’il y a un grand nombre de téléchargements ou des fichiers volumineux. Le serveur d’application reste concentré sur la logique métier, tandis que Nginx, optimisé pour le transfert de fichiers, gère le reste. Si le trafic est modeste, `FileResponse` reste une option propre. Mais dès que les requêtes de fichiers explosent, X‑Accel‑Redirect est la solution la plus rapide et la plus efficace. Mémorisez simplement : **« Django vérifie, Nginx transmet »**.