django-downloadview/docs/nginx.txt

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