Johannes Pertl
Johannes Pertl

Reputation: 983

How do I serve a generated file in Django via nginx as download?

I'm trying to serve a generated zip file in my media folder via nginx, but I got the following error: open() "/etc/nginx/htmltest.zip" failed (2: No such file or directory)

Somehow nginx is looking for the file in a weirdly malformed "/etc/nginx/html", I don't get why.

I'm using nginx via docker-compose, the code works just fine if I don't use nginx and just run Django in development mode.

folder_path = os.path.join(settings.MEDIA_ROOT, str(uuid.uuid4()))
os.mkdir(folder_path)

shutil.make_archive(os.path.join(folder_path, "test"), 'zip', folder_path, "test")

response = download(os.path.join(folder_path, f"{zip_name}.zip"))


def download(path):
    if os.path.exists(path):

        with open(path, 'rb') as f:
            response = HttpResponse(f.read(), content_type="application/zip")
            response['Content-Disposition'] = 'inline;filename=' + os.path.basename(path)
            response['X-Accel-Redirect'] = os.path.basename(path)
            return response

    raise Http404

My nginx.conf:

upstream django_app {
    server web:8000;
}

server {

    listen 80;

    location / {
        proxy_pass http://django_app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        client_max_body_size 100M;
    }

    location /static/ {
        alias /code/static/;
    }

    location /media/ {
        alias /code/media/;
    }

}

MEDIA_ROOT in settings.py:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Upvotes: 0

Views: 416

Answers (1)

stefanw
stefanw

Reputation: 10570

You are using nginx X-Accel-Redirect incorrectly.

When using X-Accel-Redirect you do not need to read and send the file from Django yourself, nginx will do it for you. That is the whole point of X-Accel-Redirect: offloading file sending from the app server to nginx (which is better at it).

So remove the X-Accel-Redirect header, then Django will serve the file directly.

If you want to use X-Accel-Redirect then you need to setup nginx as described in the documentation (your config is not complete as it is missing the internal location) and then give the internal URL in the X-Accel-Redirect header (you are incorrectly giving a file system path).

Upvotes: 1

Related Questions