mirror of
https://github.com/jazzband/django-downloadview.git
synced 2026-05-17 20:11:12 +00:00
243 lines
6 KiB
Text
243 lines
6 KiB
Text
###################
|
|
Nginx optimisations
|
|
###################
|
|
|
|
If you serve Django behind Nginx, then you can delegate the file download
|
|
service to Nginx and get increased performance:
|
|
|
|
* lower resources used by Python/Django workers ;
|
|
* faster download.
|
|
|
|
See `Nginx X-accel documentation`_ for details.
|
|
|
|
|
|
****************************
|
|
Configure some download view
|
|
****************************
|
|
|
|
As an example, let's consider the following download view:
|
|
|
|
* mapped on ``/document/<object-slug>/download``
|
|
* returns DownloadResponse corresponding to Document's model FileField
|
|
* Document storage root is :file:`/var/www/files/`
|
|
* FileField's ``upload_to`` is "document".
|
|
|
|
Files live in ``/var/www/files/document/`` folder.
|
|
|
|
As is, Django is to serve the files, i.e. load chunks into memory and stream
|
|
them.
|
|
|
|
Nginx is much more efficient for the actual streaming.
|
|
|
|
|
|
***************
|
|
Configure Nginx
|
|
***************
|
|
|
|
See `Nginx X-accel documentation`_ for details.
|
|
|
|
In this documentation, let's suppose we have something like this:
|
|
|
|
.. code-block:: nginx
|
|
|
|
# Will serve /var/www/files/myfile.tar.gz
|
|
# When passed URI /protected_files/myfile.tar.gz
|
|
location /optimized-download {
|
|
internal;
|
|
alias /var/www/files;
|
|
}
|
|
|
|
.. note::
|
|
|
|
``/optimized-download`` is not available for the client, i.e. users
|
|
won't be able to download files via ``/optimized-download/<filename>``.
|
|
|
|
.. warning::
|
|
|
|
Make sure Nginx can read the files to download! Check permissions.
|
|
|
|
|
|
************************************************
|
|
Global delegation, with XAccelRedirectMiddleware
|
|
************************************************
|
|
|
|
If you want to delegate all file downloads to Nginx, then use
|
|
:py:class:`django_downloadview.nginx.XAccelRedirectMiddleware`.
|
|
|
|
Register it in your settings:
|
|
|
|
.. code-block:: python
|
|
|
|
MIDDLEWARE_CLASSES = (
|
|
# ...
|
|
'django_downloadview.nginx.XAccelRedirectMiddleware',
|
|
# ...
|
|
)
|
|
|
|
Optionally customize configuration (default is "use Nginx's defaults").
|
|
|
|
.. code-block:: python
|
|
|
|
NGINX_DOWNLOAD_MIDDLEWARE_MEDIA_ROOT = MEDIA_ROOT
|
|
NGINX_DOWNLOAD_MIDDLEWARE_MEDIA_URL = '/optimized-download'
|
|
NGINX_DOWNLOAD_MIDDLEWARE_EXPIRES = False # Force no expiration.
|
|
NGINX_DOWNLOAD_MIDDLEWARE_WITH_BUFFERING = False # Force buffering off.
|
|
NGINX_DOWNLOAD_MIDDLEWARE_LIMIT_RATE = False # Force limit rate off.
|
|
|
|
|
|
*************************************************
|
|
Local delegation, with x_accel_redirect decorator
|
|
*************************************************
|
|
|
|
If you want to delegate file downloads to Nginx on a per-view basis, then use
|
|
:py:func:`django_downloadview.nginx.x_accel_redirect` decorator.
|
|
|
|
In some urls.py:
|
|
|
|
.. code-block:: python
|
|
|
|
# ... import Document and django.core.urls
|
|
|
|
from django_downloadview import ObjectDownloadView
|
|
from django_downloadview.nginx import x_accel_redirect
|
|
|
|
|
|
download = x_accel_redirect(ObjectDownloadView.as_view(model=Document),
|
|
media_root=settings.MEDIA_ROOT,
|
|
media_url='/optimized-download')
|
|
|
|
# ... URL patterns using ``download``
|
|
|
|
|
|
********************
|
|
Sample configuration
|
|
********************
|
|
|
|
In this sample configuration...
|
|
|
|
* we register files in some "myapp.models.Document" model
|
|
* store files in :file:`/var/www/private/` folder
|
|
* publish files at ``/download/<pk>/`` URL
|
|
* restrict access to authenticated users with the ``login_required`` decorator
|
|
* delegate file download to Nginx, via ``/private/`` internal URL.
|
|
|
|
Nginx
|
|
=====
|
|
|
|
:file:`/etc/nginx/sites-available/default`:
|
|
|
|
.. code-block:: nginx
|
|
|
|
charset utf-8;
|
|
|
|
# Django-powered service.
|
|
upstream frontend {
|
|
server 127.0.0.1:8000 fail_timeout=0;
|
|
}
|
|
|
|
server {
|
|
listen 80 default;
|
|
|
|
# File-download proxy.
|
|
# See http://wiki.nginx.org/X-accel
|
|
# and https://github.com/benoitbryon/django-downloadview
|
|
location /private/ {
|
|
internal;
|
|
# Location to files on disk.
|
|
# See Django's settings.NGINX_DOWNLOAD_MIDDLEWARE_MEDIA_ROOT
|
|
alias /var/www/private/;
|
|
}
|
|
|
|
# Proxy to Django-powered frontend.
|
|
location / {
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header Host $http_host;
|
|
proxy_redirect off;
|
|
proxy_pass http://frontend;
|
|
}
|
|
}
|
|
|
|
Django settings
|
|
===============
|
|
|
|
:file:`settings.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
MYAPP_STORAGE_LOCATION = '/var/www/private/'
|
|
NGINX_DOWNLOAD_MIDDLEWARE_MEDIA_ROOT = MYAPP_STORAGE_LOCATION
|
|
MIDDLEWARE_CLASSES = (
|
|
# ...
|
|
'django_downloadview.nginx.XAccelRedirectMiddleware',
|
|
# ...
|
|
)
|
|
INSTALLED_APPS = (
|
|
# ...
|
|
'myapp',
|
|
# ...
|
|
)
|
|
|
|
In some model
|
|
=============
|
|
|
|
:file:`myapp/models.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.conf import settings
|
|
from django.db import models
|
|
from django.core.files.storage import FileSystemStorage
|
|
|
|
|
|
storage = FileSystemStorage(location=settings.MYAPP_STORAGE_LOCATION)
|
|
|
|
|
|
class Document(models.Model):
|
|
file = models.ImageField(storage=storage)
|
|
|
|
URL patterns
|
|
============
|
|
|
|
:file:`myapp/urls.py`:
|
|
|
|
.. code-block:: python
|
|
|
|
from django.conf.urls import url, url_patterns
|
|
from django.contrib.auth.decorators import login_required
|
|
|
|
from django_downloadview import ObjectDownloadView
|
|
|
|
from myapp.models import Document
|
|
|
|
|
|
download = login_required(ObjectDownloadView.as_view(model=Document))
|
|
|
|
url_patterns = ('',
|
|
url('^download/(?P<pk>[0-9]+/$', download, name='download'),
|
|
)
|
|
|
|
|
|
*************
|
|
Common issues
|
|
*************
|
|
|
|
``Unknown charset "utf-8" to override``
|
|
=======================================
|
|
|
|
Add ``charset utf-8;`` in your nginx configuration file.
|
|
|
|
``open() "path/to/something" failed (2: No such file or directory)``
|
|
====================================================================
|
|
|
|
Check your ``settings.NGINX_DOWNLOAD_MIDDLEWARE_MEDIA_ROOT`` in Django
|
|
configuration VS ``alias`` in nginx configuration: in a standard configuration,
|
|
they should be equal.
|
|
|
|
|
|
**********
|
|
References
|
|
**********
|
|
|
|
.. target-notes::
|
|
|
|
.. _`Nginx X-accel documentation`: http://wiki.nginx.org/X-accel
|