Контролируемые скачивания в Nginx

Контролируемое скачивание, реализуемое в веб сервере Nginx с использованием заголовка X-Accel-Redirect, подразумевает следующий алгоритм при отдаче контента:

  • Клиент нажимает на ссылку "скачать файл"
  • Запрос передается веб серверу Nginx
  • Nginx в свою очередь передает запрос некоему скрипту на проверку
  • Скрипт, после проверки, например валидности запроса на скачивание, возвращает запрос в Nginx, устанавливая заголовок X-Accel-Redirect
  • Запрос с заголовком X-Accel-Redirect попадает в специальный внутренний location, сервера Nginx, откуда и отдается клиенту

Итак, в данном примере, используются: операционная система FreeBSD 7.1-STABLE amd64, веб сервер Nginx версии 0.7.64 (последний релиз из стабильной ветки на момент написания данного материала). В качестве бакэнда будем использовать PHP в режиме FastCGI сервера, запущенный с помощью утилиты spawn_fcgi.

Корень сайта у нас будет расположен в /home/test/public_html, файлы для скачивания /home/test/public_html/download_files. Для примера набросаем примитивный скрипт down.php и положим в корень сайта а в папку download_files, положим какой-нибудь файл для скачивания, например архив test.zip

  1. <?php 
  2. $path= $_GET['file_name']; 
  3. // принимаем имя файла 
  4. .............. 
  5. // делаем какую-то проверку или обработку 
  6. .............. 
  7. header("X-Accel-Redirect: /internal_files/" . $path); 
  8. // возвращаем запрос с установленным заголовком X-Accel-Redirect 
  9. ?>

Конфигурация Nginx у нас, будет выглядеть следующим образом:

   server {
        listen       192.168.50.20:80;
        server_name  nginx.grt;

        error_log       logs/nginx_error.log error;

        root   /usr/home/test/public_html;

        location / {
            index  index.php index.html index.htm;
        }

        location /downloads/ {
            rewrite ^/downloads/(.*) /down.php?file_name=$1 break;
            fastcgi_pass   unix:/tmp/fastcgi_socket;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

        location /internal_files {
            alias /home/test/public_html/download_files;
            add_header Content-type application/octet-stream;
            internal;
        }

        location ~ \.php$ {
            fastcgi_intercept_errors off;
            fastcgi_pass   unix:/tmp/fastcgi_socket;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }

Теперь что происходит при запросе http://nginx.grt/downloads/test.zip. Первоначально, запрос клиента попадает в location /downloads/, здесь, URI-часть запроса переписывается с помощью модуля ngx_http_rewrite_module, принимает вид, /down.php?file_name=test.zip и отправляется на выполнение, на FastCGI сервер. Скрипт, приняв в качестве параметра, путь к файлу, производит какие-то манипуляции и возвращает в Nginx запрос, в виде /internal_files/test.zip, с установленным заголовком X-Accel-Redirect, который в свою очередь будет обработан в location /internal_files.

В location /internal_files, прописана директива alias, указывающая путь на диске, до папки с файлами и заменяющая собой соответствующий location, и ключевое слово, Internal, говорящее, что данный location, обрабатывает только внутренние запросы сервера Nginx и запросы X-Accel-Redirect, то есть внешние запросы в этот location не попадут. В итоге всех этих манипуляций, с диска будет отдан файл /home/test/public_html/download_files/test.zip.

Вот собственно и все.

Комментарии

А если сделать запрос site.ru/download_files/test.zip то файл отдаётся. Проверьте.

Ну папка с файлами может называться например Hb1u1G7S9ghUr$59gks_a6F6khg4DJs58vb
Кроме того, внутренний location можно обозвать так-же как и папку с файлами

location /download_files {
      add_header Content-type application/octet-stream;
      internal;
}

извне туда уже не попадешь

в конце концов:

location /download_files {
    allow 127.0.0.1;
    deny all;
}

Тут приведен лишь общий принцип

Супер!!! Спасибо за статью!

А то сейчас раздаю из самого приложения, что создает неимоверную нагрузку.

А насчет некрасивого имени, лучше не стоит, как говорят - что знает один то знает и морская свинка.

пс, понтовая капча :)

спасибо :)

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
Регистр имеет значение
   .oooo.    oooooooooo.    ooooo   ooooo                .oooo.                
.dP""Y88b `888' `Y8b `888' `888' .dP""Y88b
]8P' 888 888 888 888 .oooooooo ]8P' oooo oooo
.d8P' 888 888 888ooooo888 888' `88b .d8P' `888 `888
.dP' 888 888 888 888 888 888 .dP' 888 888
.oP .o 888 d88' 888 888 `88bod8P' .oP .o 888 888
8888888888 o888bood8P' o888o o888o `8oooooo. 8888888888 `V88V"V8P'
d" YD
"Y88888P'
Введите код, изображенный в стиле ASCII-арт.