Server Fault is a question and answer site for system and network administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I am doing a setup where Apache runs the web application and NginX serves files that users download. The files should be downloaded with their real names instead of the names their are being stored with. The real names are retrieved from a database. I do not understand why am I failing to force NginX to download the files with their real names. I send the following headers in php from Apache to NginX:

header('Location: ' . "" . $file['upload_id']);
header('Content-type: ' . $this->mime);
header('Content-Disposition: attachment; filename="' . $file['file_name'] . '"');
header('Last-Modified: ' . date('D, d M Y H:i:s \G\M\T' , $this->data_mod));

It looks like NginX ignores the content-disposition header? Or am I failing in the syntax?

Edit:Output of

curl --head http://…/your/file.ext

is as follows:

HTTP/1.1 200 OK
Server: nginx/1.0.5
Date: Sat, 16 Feb 2013 14:26:33 GMT
Content-Type: application/octet-stream
Content-Length: 38807550
Last-Modified: Sun, 06 Jan 2013 14:37:36 GMT
Connection: keep-alive
Accept-Ranges: bytes
share|improve this question
Please, provide output of curl --head http://…/your/file.ext. – user134336 Feb 16 '13 at 14:15
I have added the output of the curl command to the question. Thank you! – user160301 Feb 16 '13 at 14:30
As you see, nginx is not sending it. Content-Disposition is not a standard header. It could be filtered inside Apache or nginx due to security considerations. Try to disable all security modules (mod_security?) temporary and check again. – user134336 Feb 16 '13 at 15:16
up vote 0 down vote accepted

nginx isn't going to know it needs to return the header just because the header was return from Apache. The request to Apache is going to return that header, but you're also telling the client to go fetch that file from nginx, and nginx isn't going to receive that header nor know to send it back unless you have something in the nginx configuration to do that.

Here's the way it's working now (... represents other headers unimportant to this discussion):

Request to Apache

GET /your/file.ext HTTP/1.1

Response from Apache

HTTP/1.1 302 Redirect
Content-Disposition: attachment; filename="filename"

When your web client receives this, it's basically being told to go somewhere else. That's going to initiate a new request:

Request to nginx

GET /fileid HTTP/1.1

Response from nginx

HTTP/1.1 200 OK
... (no Content-Disposition header)

You need to have the nginx response return the Content-Disposition header, not the Apache/PHP response. You have a few options here:

  • Pass the nginx request through to a script that will translate the fileid form to the file.ext form, send back the Content-Dispotion: header and return the data (this is very similar to your PHP script, except it also needs to return the file data).
  • Request the file.ext form from nginx and configure nginx to always add a Content-Disposition: header with the filename= portion set the file.ext of the request.
  • Update your PHP script to proxy the nginx request internally, so that rather than returning the Location: header and subsequent redirect, it returns the header it needs, then fetches the data from nginx internally and dumps it out to the client.

The second option seems cleanest to me, but your setup may not support it.

share|improve this answer
Thank you very much for your response! I would like to go with the second option. Could you be that kind to tell me what exactly should I put in the Nginx config file to allow it to always add a content-disposition header? – user160301 Feb 16 '13 at 15:25
The answer to 'custom HTTP headers for static files with Django' has an example of how to add a Content-Disposition: header for a file. – hrunting Feb 16 '13 at 17:28

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.