Quick Start

  1. Django settings set up settings.py:

INSTALLED_APPS = (
    ...
    'nginx_secure_links',
    ...
)
MEDIA_ROOT = '/var/www/media/'
MEDIA_URL = '/media/'
DEFAULT_FILE_STORAGE = 'nginx_secure_links.storages.FileStorage'
SECURE_LINK_SECRET_KEY = 'KfM6aA6M7H'
  1. Create a private file inside your settings.MEDIA_ROOT:

echo "I'm private text file" > /var/www/media/sample.txt

3. Let’s start runserver and access the file outside of Django file storage. It works and the file is available. There is no access denied, because of runserver mode:

curl http://127.0.0.1:8000/media/sample.txt
  1. Set up Nginx virtual host file site.conf:

server 127.0.0.1;
listen 80;

...

location /media/ {
    secure_link $arg_token,$arg_expires;
    secure_link_md5 "$secure_link_expires$uri KfM6aA6M7H";

    if ($secure_link = "") {
        return 403;
    }

    if ($secure_link = "0") {
        return 410;
    }

    alias /var/www/media/;
}

...
  1. Let’s access the file through Nginx host/port.

curl http://127.0.0.1/media/sample.txt

Because of Nginx secure link module protection, the file won’t be served without ?token=...&expires=... parameters. Only django users will be able to access files which urls generated by django storage.

Usage

models.py

class Report(models.Model):
    pdf_file = models.FileField(upload_to='reports')

views.py

def report_details(request, report_id)
    instance = Report.objects.get(id=report_id)
    return JsonResponse({'url': instance.pdf_file.url})

json response

{
  "url": "/media/reports/29974.pdf?expires=1599214310&token=ErLcMm96-4h2qsuj2Avo-w"
}

That’s it, all uploaded media files through Django will be pre-signed. If you work locally and do not want to install Nginx, let’s skip it for local development- django will generate pre-signed urls, but all files will be available because of runserver command serves files and does not provide 3rd-party nginx-secure-link module functionality.