Wed 1 Nov 2006
Using X-Accel-Redirect Header With Nginx to Implement Controlled Downloads (with rails and php examples)
Posted by Scoundrel under Development ·
Sometimes you may need to implement controlled downloads when all downloads requests being sent to your script and then this script decides what to do: to send some file to the user or to show some access denied page or, maybe, do something else. In lighttpd server it can be done by returning X-Sendfile header from script. Nginx have its own implementation of such idea using X-Accel-Redirect header. In this short post I will try to describe how to use this feature from PHP and Rails applications.
Lets assume, that you have some site and using Apache with PHP or Rails for dynamic content on this site. If you will use nginx as reverse-proxy in front of your Apache server, you will reach two goals:
- You would be able free some resources on server while nginx will handle all slow requests to dynamic content (details are here).
- You would be able to implement controlled downloads of static files from site.
In this article I will assume, that site is located in /var/www directory and there are some static files (like movies or song or something else) in /var/www/files directory. Apache is listening on http://127.0.0.1:8080.
First of all, lets take a look at our nginx configuration:
....
server {
listen 80;
server_name your-domain.com;
location / {
rewrite ^/download/(.*) /down.php?path=$1 last;
proxy_pass http://127.0.0.1:8080/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
location /files {
root /var/www;
internal;
}
}
}
As you can see, we have additional “internal” location /files there. This keyword “internal” allow us to have some locations, that will be available for user only in internal redirects and X-Accel-Redirect responses from backend scripts. So, we can use simple PHP script or Rails code on backend server to implement controlled downloads that will support Ranges header and all other features supported by direct static downloads from nginx servers.
Here is down.php script:
// Get requested file name
$path = $_GET["path"];
//...
// Perform any required security checks, validation
// and/or stats accounting
//...
// And redirect user to internal location
header("X-Accel-Redirect: /files/" . $path);
?>
In Rails applications you can use following code in your controller:
path = @params["path"]
# ...
# Perform any required security checks, validation
# and/or stats accounting
# ...
# And redirect user to internal location
@response.headers['X-Accel-Redirect'] = "/files/" + path
That’s it! With described approach we are able to create very flexible and extremely performance systems for file distribution!
- Using Nginx, SSI and Memcache to Make Your Web Applications Faster
- 32bit VS 64bit - what do you use?
- HAProxy - The Reliable, High Performance TCP/HTTP Load Balancer
- Compiling nginx in RedHat Linux: PCRE library problem
- Using Nginx As Reverse-Proxy Server On High-Loaded Sites
2006-11-01 at 9.55 am
cool article
I have add it to the wiki site http://wiki.codemongers.com/NginxXSendfile
2006-11-07 at 6.31 am
Класс!
2006-12-28 at 7.49 pm
Will it work if you want to use the flv module with start=XXX parameter?
2006-12-28 at 8.55 pm
2Rapsey: Why not?
2006-12-29 at 7.20 am
because it would be to awesome.
2007-03-04 at 8.08 am
привет!
я реализовал контролируемые скачивания, но есть одна проблема - nginx со всеми файлами передает заголовок text/html, и браузер его соответственно открывает. не подскажете, с чем это может быть связано, и как испраить?
2007-03-27 at 9.08 pm
$r->send_http_header posulaet eto,
4to-bu zapretit - powli pustoj $r->send_http_header();
2007-03-28 at 4.04 am
да я затупил, короче… там ошибка была, типа, нет такого темплейта. она и заменяла заголовок на text/html, а тело документа менялось на содержимое файла.
2007-04-05 at 8.41 am
[...] 原文链接:Using X-Accel-Redirect Header With Nginx to Implement Controlled Downloads (with rails and php examples) [...]
2007-04-05 at 9.11 am
good article.
I have thanslated it into Simplified-Chinese:
http://bianbian.sunshow.net/index.php/technology/154.html
enjoy~
2007-04-23 at 8.34 am
Неужели и не решили проблеммы с сменой заголовка ??
2007-05-16 at 4.35 pm
Здорово. Часто под контролируемым скачиванием понимают еще и отметку, когда скачивание файла было закончено. Тут nginx помочь может?
2007-05-16 at 6.18 pm
2pereksid: Можно и такое. Называлось вроде post_action - нгинкс умеет дергать нужный урл когда юзер все докачает.
2007-06-20 at 3.35 pm
Можно по подробнее, из-за чего nginx выдает на .exe файлы, text/html вместо application/octet-stream?
2007-06-26 at 4.21 pm
> Можно по подробнее, из-за чего nginx выдает на .exe файлы, text/html вместо application/octet-stream?
Это может быть потому, что процесс выдает ошибку “500 No template for action download”
так как ошибка выводится в html, то она подменяет заголовок на text/html.
проверьте логи ruby
2007-07-07 at 11.34 pm
DOES NGINX IPV6 CAPABLE ???????!!!!!!!!!!!!!??????????????????!!!!!!!!!!!!!???????????????????!!!!!!!!!!!!!!!!!!!!
2007-07-13 at 12.51 pm
нет, это статья не все. если использовать пхп как модуль апача, то сервер ляжет под нагрузкой, когда обратятся несколько юзверов при помощи флашгета с 10 потоками. Лучшим вариантом будет запуск проверяющего скрипта на фастCGI.
2007-07-15 at 8.30 pm
Как вы смотрите на то, чтобы для уменьшения нагрузки дописать к nginx модуль или фильтр какой нить для реализации антилича.
2007-07-18 at 8.22 pm
2si-rus: он реализуется родными средствами (if + regexp) в конфиге.
2007-07-31 at 2.35 am
[...] Using X-Accel-Redirect Header With Nginx (tags: rails nginx x-accel-redirect) [...]
2007-08-14 at 3.10 pm
[...] Understanding FastCGI Application Performance Squid: Accelerator Mode XCache Faster Is Possible Using X-Accel-Redirect Header With Nginx to Implement Controlled Downloads Lighttpd X-Sendfile Scaling with MySQL replication Может чего и забыл - у меня [...]
2007-10-30 at 3.43 am
Ошибочка маленькая в rewrite, должно быть так, видимо:
rewrite ^/download/(.*)$ /down.php?path=$1 last;
2 Andrey Popov:
Попробуй перед редиректом (X-Accel-Redirect) отдавать заголовок руками т.е.:
Content-type: application/octet-stream
2007-11-08 at 7.51 am
What about the rest of the code for the rails controller.
This confuses me because you have to render something….?
I have nginx setup and I am setting the header, but then what? render :text => “”???
2007-11-09 at 10.59 am
For explorer 6 users downloading pdfs you also need to set the cache-control header, or you get a ‘document not found’ error message from the acrobat reader. It seems this is because the explorer regards the file as temporary and deletes it before acrobat can see it.
anyway, i use this to make pdf downloads work:
Otherwise, I’ve been very happy with nginx and this download control mechanism (and I’ve written a radiant plugin to make use of it, which should appear soon). thank you.
2007-11-09 at 6.54 pm
a sto tut delat???
2007-11-12 at 1.00 pm
[...] X-Accel-Redirect с Nginx для реализации контролируемых [...]
2007-11-13 at 10.23 pm
[...] so you too can send files, flowers and love without crashing mongrels with nginx’s equivalent X-Accel-Redirect [...]
2007-11-13 at 10.31 pm
This works great for me. I modified the x_send_file rails plugin to work with nginx.
http://spongetech.wordpress.com/2007/11/13/the-complete-nginx-solution-to-sending-flowers-and-files-with-rails/
2007-11-24 at 9.28 pm
При таком подходе в заголовке Content-Type всегда оказывается text/html. Соответственно, бинарный файл загружается браузером в окно а не предлагается для скачивания.
Как оказалось, это заголовок по умолчанию, который выдает сам PHP скрипт, и nginx его уже не трогает.
Выход довольно прост, надо запретить PHP выдавать этот заголовок, например, так:
ini_set(’default_mimetype’, ”);
Если кто подскажет, как это сделать более элегантно - буду благодарен.
2007-12-26 at 9.37 am
перед X-Accel-Redirect вставьте:
header(”Content-Disposition: attachment; filename=\”" . $filename . “\”");
где $filename - имя файла (только имя, путь - отсутствует).
После этого все браузеры должны открывать окно с приглашением сохранить файл или открыть. Ну у MIME типы уже сам nginx отдаст если в его конфиге добавлено include conf/mime.types
2008-01-15 at 11.20 am
Добрый день. А никто не сталкивался со следующей ситуацией: есть файл который отдается через X-Accel-Redirect. При попытке его скачать с двух различных машин - качается только на одной. Проблема имеет место только при скачивании через браузер (тестировался ie6-7 и ff2), выдается невозможность отобразить страницу. При использовании менеджера закачек - все качается нормально.
2008-01-15 at 2.37 pm
в тему предыдущего коммента - вопрос закрыт. проблема была в размере файла - больше 4 гб. Интернет експлорер побоялся что на машине фат32 и не стал качать.
2008-01-21 at 9.44 am
При попытке использовать описанную схему контролируемого скачивания (nginx+apache+php) столкнулся со след. проблемой: иногда вместо предложения сохранить файл в браузер выдается ошибка :
502 Bad Gateway
nginx/0.5.33
При этом в PHP скрипт передается $path с запорченным окончанием - последние несколько символов заменены на 0×0. В error.log nginx’а при этом выдается сообщение:
upstream prematurely closed connection while reading response header from
upstream …
Как с этим бороться?
2008-01-25 at 3.40 pm
>What about the rest of the code for the rails controller.
>This confuses me because you have to render something….?
>I have nginx setup and I am setting the header, but then what? >render :text => “”???
render :nothing => true
2008-02-21 at 1.09 pm
[...] 原文链接:Using X-Accel-Redirect Header With Nginx to Implement Controlled Downloads (with rails and php examp… [...]
2008-03-28 at 6.14 am
[...] делает X-Accel-Redirect. Подробнее описано в статьях “Использование X-Accel-Redirect с Nginx для реализации контролир…” и “Использование Nginx Как Reverse-Proxy Сервера На [...]
2008-04-10 at 9.02 am
Про использование в lighttpd контролируемых скачек с помощью скриптов можно поподробнее?
2008-04-24 at 11.58 am
Спасибо за статью.
С заголовками таки что-то не то - FF и IE отрабатывают нормально, а вот Опера упорно предлагает сохранить в html …
2008-06-16 at 7.35 pm
Чтобы правильно отдавать тип и имя файла:
<?php
header(”Content-type: video/mpeg”);
header(”Content-Disposition: attachment; filename=\”file.mpeg\”");
//или подставить свой
Чтобы не задалбывали потоками reget, dmaster etc..
в nginx.conf
http {
limit_zone one $binary_remote_addr 10m;
…
location /files {
root /home/www/…/files;
internal;
limit_conn one 1;
}
где one-имя зоны, 1-количество подкл. с одного ip
2008-06-16 at 7.40 pm
Кстати, есть такая функция в php
string mime_content_type ( string filename)
не тестировал, но если работает - удобно