Настройка nginx для скачивания файлов
3. Даже так не работает докачка в IE 9.
Да. На сколько я понял методом простого тыка, IE требует поддержки ETag сервером для работы докачки. Игорь Сысоев (разработчик nginx) отказался внедрять в nginx поддержку ETag. Поэтому из коробки работать докачка в IE 9 не будет точно. Если это жизненно необходимо, пробуйте смотреть сюда (Ctrl+F Etag).
Замена RewriteRule в nginx
Итак, имеем веб сервер Nginx в качестве фронтэнда, на бакэндах Apache и какой-нибудь fastcgi (spawn-fcgi или php-fpm). Функциональные возможности серверов, nginx и apache, несколько различаются, и одно из различий как раз в том, что nginx не поддерживает обработку файлов htaccess, которые в apache используются практически повсеместно. Большинство сайтовых движков (CMS), поддерживают возможность генерировать так называемые ЧПУ(человекопонятный урл, в оригинале, SEF - search engines friendly url), но для этого, веб сервер, должен обрабатывать строку запроса определенным образом, что apache и делает с помощью mod_rewrite и правил в файле .htaccess. Задача: заменить правила .htaccess, соответствующими директивами в конфигурационном файле nginx.conf.
Установка и настройка spawn-fcgi для запуска FastCGI сарвера PHP
Процесс сборки и установки длится меньше минуты. По завершению, будет создано несколько файлов:
Полный список опций программы spawn-fcgi, приведен тут Spawn-fcgi запуск процессов в FastCGI режиме
Не забываем добавить строку spawn_fcgi_enable="YES" в стартовый скрипт /etc/rc.conf, для запуска FastCGI сервера при старте системы.
Пробуем запустить spawn-fcgi:
FastCGI сервер готов к работе
2. Настраиваем Nginx
Доработайте конфиг под свои особенности и защитите /files от прямого доступа из браузера.
Получается такой путь:
Запрашивается файл /download/file.zip , Nginx переписывает адрес и кидает в скрипт /down.php?path=file.zip .
Скрипт отправляет файл в антивирус (реализацию напишите сами)
Скрипт отдает Nginx заголовок X-Accel-Redirect: /files/file.zip и Nginx уже отправляет файл в браузер.
По сути, файл на проверку отправляет написанный скрипт. Если отправка - медленный процесс, используйте очереди.
По сути похож на первый вариант.
1. Мы хотим контролировать скачивание больших файлов, проверяя права доступа или считая количество закачек. Мы используем nginx и PHP (или другой серверный язык).
Это реализуется очень просто через заголовок Accel-Redirect. nginx получает запрос, передает его скрипту, скрипт в заголовки ответа выдает Accel-Redirect с ссылкой на файл, который нужно выдать пользователю. Если файл выдавать нельзя (например, нет прав), скрипт просто выдаст ошибку (например, 403).
В данном случае не важно, работает ваш PHP через проксирование из nginx на Apache, либо на *CGI. Предположим, что вы хотите отдавать на скачку файлы, которые находятся в каталоге /var/files. Тогда в секции server в nginx добавьте:
В скрипте, который контролирует закачку, в том месте, где мы хотим отдать пользователю файл, должен быть следующий код:
Никакой выдачи (echo) делать не надо, после отдачи заголовка можно завершить работу скрипта. В этом случае будет скачан файл /var/files/filename.zip. Вместо filename.zip может быть любой длинный путь с каталогами, который должен повторять путь к файлу в /var/files/.
В принципе этого достаточно, чтобы переложить выдачу файла на плечи nginx. Если нужно обязательно показать диалог закачки (даже если файл такого типа, который браузер может показать сам), нужно добавить выдачу заголовка:
Обратите так же внимание на то, что в случае проксирования на Apache последний обязательно установит Content-Type (по умолчанию обычно text/html) в случае PHP-скриптов, и этот тип отправится пользователю, так как nginx его не перепишет при выполнении Accel-Redirect. Т.е. в этом случае эту строку нужно писать обязательно. Как будет в случаях с *CGI, не знаю — не проверял.
Чтобы предложить пользователю имя файла для сохранения, отличное от того, что в адресной строке (это особо актуально в случаях «download.php&file_id=12332»), отправим такой заголовок:
1 ответ 1
Насколько мне известно, Nginx такое не умеет. Но есть варианты
X-Accel-Redirect используется для контролируемых скачиваний. Как должно работать:
PHP с поддержкой FastCGI интерфейса
Настройку сервера Nginx, сделаем чуть позже, сначала настроим FastCGI сервер, установив все необходимое. Что вообще такое, FastCGI. В общем понимании, это протокол взаимодействия, между веб сервером и приложением, не зависимый от языка приложения и являющийся куда более производительным и безопасным, нежели обычный CGI. Если коротко, обычную CGI программу, веб серверу, приходится запускать на каждый запрос, в то время как FastCGI, постоянно держит запущенный процесс, который и обслуживает приходящие ему запросы. Кроме того веб сервер, связывается с FastCGI сервером, через так называемый "Unix domain socket" или через TCP/IP, в отличии от обычного CGI, который взаимодействует с сервером через стандартный ввод/вывод, что дает возможность располагать FastCGI сервер, не только в рамках одной машины, но и вообще где угодно в сети.
В контексте данного материала, речь идет о языке PHP, собранном с поддержкой FastCGI и запущенном с помощью специального приложения.
Для поддержки данного режима работы, PHP, должен быть скомпилирован с соответствующими опциями и иметь необходимый бинарник ( запускаемый файл, по умолчанию php-cgi.) Следующие опции необходимы для сборки PHP с поддержкой FasCGI и обеспечения необходимого уровня безопасности:
--enable-fastcgi
--enable-force-cgi-redirect
--enable-discard-path
Остальные опции ставите в зависимости от ваших потребностей.
Посмотреть опции, с которыми собран PHP, можно так:
N+1 способ: правильный
Не буду дальше утомлять вас несмешными шутками и скажу волшебное слово: X-Accel-Redirect. Для тех, кому лень открывать ссылку, процитирую:
X-accel allows for internal redirection to a location determined by a header returned from a backend. This allows you to handle authentication, logging or whatever else you please in your backend and then have Nginx handle serving the contents from redirected location to the end user, thus freeing up the backend to handle other requests. This feature is commonly known as X-Sendfile.
Для самых маленьких и тупых я покажу как это работает.
Для начала сам скрипт, обрабатывающий запросы на скачивание файла. Новый storage написан на werkzeug, но это должно вас мало интересовать, потому что основную часть я все-таки вырежу:
Простой метод из которого вырезано все не нужное. Мы делаем ровно то, что описывали в начале, а затем, если все хорошо, делаем. да-да, редирект. Вот только обычный редирект, как мы помним, делается через статус-код 3xx хедер Location, а тут через обычный статус 2хх и хедер X-Accel-Redirect. То же на РНР:
header("X-Accel-Redirect: /path_to_file/" . $filename);
Поле данных Response можно оставлять пустым, насрать. Когда запрос обрабатывается, он отдается впередистоящему nginx, который в свою очередь отлавливает заголовок X-Accel-Redirect, удаляет его и дальше делает все сам. Не подменяя URL он заменяет ответ своим. Всякие add_header и gzip_static тоже работают. Кому нужно, можете насильно прописать content_type и отдавать, например, картинки и текст как файлы. А скрипт работу закончил и освободил воркера, как уже отдать файл пользователю решит nginx. У него это получается лучше всего. Как поговаривают в этих ваших интернетах nginx в таком случае даже сам умеет управлять докачкой. Для него это обычный статик-файл.
Этот location очень похож на обычный, только вот если вы попробуете обратиться к нему напрямую, то получите 404. Слово internal говорит, что эти файлы являются внутренними и доступны только для самого сервера.
И чо, это работает? Ага:
🚨 Роскомнадзор банит одну соцсеть за другой, поэтому я рекомендую подписаться как по почте (её сложнее заблокировать), так и на вашей любимой площадке. Тогда у нас будет хотя бы два канала для связи.
2. Настраиваем Nginx
Поправьте пути и порты под свои реалии. Документация.
Скрипт отправляет файл в антивирус (реализацию напишите сами)
Есть проект OpenResty который позволяет писать программы на Lua прямо в конфигах Nginx. Обычный Nginx также позволяет это делать, но нужно будет в него добавить модуль Lua.
А способ похож на предыдущие два: получаем запрос, ставим в очередь проверки, а клиенту отдаем файл.
Самый интересный на мой взгляд способ, но требует изучения Lua и OpenResty.
В location, с которого скачиваются файлы, пишите access_log в отдельный файл. А отдельный скрипт читает этот файл и отправляет на проверку. Может быть, даже это будет не файл, а сокет, тогда не придется следить за файлом, а сразу вычитывать из сокета, но я не уверен, что Nginx может писать в сокеты. Попробуйте.
Привет, мои маленькие прогродрузья. Сегодня я расскажу вам то, о чем, как выяснилось, не знают многие веб-прогроммисты. Совсем недавно я переписал свой storage, потому что предыдущий не устраивал меня по нескольким причинам: он был написан мною давным давно на РНР, и по началу вполне устраивал меня, но времена меняются, про РНР я давно забыл, а память, отжираемая apache, стала слишком дефицитным ресурсом, потому что стала требоваться еще многим более важным процессам на сервере. Потому примерно в то же время я перешел на nginx и с тех пор жил счастливо. Пришлось, правда, поебаться со сборкой php-fpm, по крайней мере тогда (2 года назад) под debian даже готовых пакетов с этим добром не было (либо были под древние версии, под etch и sarge). Потому как работает PHP на моем сервере мне всегда не нравилось и я начал избавляться от таких проектов. После глобальной чистки оставалось всего 2 необходимых мне сервиса - это тот самый storage и phpmyadmin. Теперь остался один, да и тот в основном для работы.
Так к чему это я веду. В первой версии сторадж представлял из себя просто файл index.php, который сканировал папку, в которой лежал, разбивал все файлы по категориям, и выводил списком. Скачивались файлы, естественно, по давней традиции тупо по хотлинку. От этой практики я решил тоже отказаться, что уж говорить, 4 года назад я был настолько туп, что первые пару дней даже не фильтровал заливку туда файлов с расширением *.php, а никакого chroot там в помине не было. В общем во второй версии я решил завести для всего этого дела небольшую БД (sqlite вполне подошел) и переписать-таки все на питоне.
Стандартно, прямолинейно, ничего нового. Любой, кто работал с файлообменниками, переживал еще большую анальную боль при попытке скачать файл. Сюда можно добавить еще таймеры, капчи, генерацию "временных эксклюзивных url", кнопку "БАБЛО", etc. У нас случай простейший и написать такое под силу даже Студенту АВТФ, успешно сдавшему лабораторную работу по курсу ООП и БД. Но остается один вопрос, описанный в теме поста: как отдать файл пользователю? Я расскажу несколько способов со смешными кодовыми названиями, которые я придумал только что.
Настройка связки Nginx Apache FastCGI
В предыдущей статье "Установка и настройка веб сервера Nginx в качестве проксирующего фронтэнда к Apache", был рассмотрен простой вариант установки и использования Nginx, с настройками по-умолчанию, в качестве проксирующего сервера, с сервером Apache в качестве проксиркемого бакэнда.
Веб сервер Nginx, обзор функциональных возможностей
В предыдущей статье "Установка и настройка веб сервера Nginx в качестве проксирующего фронтэнда к Apache", был рассмотрен простой вариант установки и использования Nginx, с настройками по-умолчанию, в качестве проксирующего сервера, с сервером Apache в качестве проксиркемого бакэнда.
Схема работы связки Nginx - Apache - FastCGI, выглядит следующим образом:
Теперь на словах. Все запросы приходят на адрес, на котором сервер Nginx принимает соединения. Согласно настройкам в конфигурационном файле Nginx:
- Все статические запросы ( HTML файлы, картинки ), будут обработаны веб сервером Nginx самостоятельно, после чего результат будет выдан клиенту;
- Запросы к CGI и Perl ( файлы CGI, PL ) скриптам, будут отправлены на обработку Apache, после обработки, результат будет передан в Nginx и отдан клиенту;
- Все запросы к скриптам PHP, будут перенаправлены на сервер FastCGI, после обработки, результат опять-же будет возвращен в Nginx и выдан клиенту;
Итак, что мы имеем: операционная система FreeBSD 7.1 STABLE ( платформа amd64 ), установленный веб сервер Apache/2.2.9. Установка Nginx производилась со следующими опциями:
1 способ: "долбоеб"
Открыть папку с файлами в паблик через nginx. После всех этих обработок просто редиректнуть юзера на хотлинк на файл.
Плюсы:
1) Звенящая простота и очевидность реализации (отсюда и название)
2) Раздача через nginx
Минусы:
1) Летит к хуям вся система контроля. Один пользователь выложил хотлинк на картинку в твиттере и дальше понятно.
Собственно, этого минуса нам уже достаточно.
3 способ: "умный долбоеб-педераст"
А что если про рефералу не банить, а перестроить систему так, чтобы nginx редиректил при неправильном реферале на скрипт, который затем опять редиректил на прямой линк.
Плюсы:
1) Те же, что у предыдущего способа
2) "Наверняка теперь все будет круто"
Минусы:
1) Три изменения url и два редиректа? Да вы ебанулись.
2) А если я захочу отдавать файлы только по ID?
5 способ: "хабрахабр головного мозга"
Ладно, забудем про рефералы, будем помнить про способ прострелить ногу через file.open и обратимся к профессионалам. Сразу несколько опрошенных мною человек рекомендуют написать модуль для nginx, который будет обрабатывать такие запросы и. WHUT? МОДУЛЬ ДЛЯ NGINX?
Плюсы:
1) Наверное это будет работать
Минусы:
1) Писать модуль, компилить с ним nginx, надеясь, что все заработает, терять поддержку обновлений для всего сервера и постоянно бояться, что что-то сломал?
Настройка веб сервера Apache
Настройка сервера Apache, аналогична той, которую мы делали в статье "Установка и настройка веб сервера Nginx в качестве проксирующего фронтэнда к Apache". То есть задача сводится к смене IP адреса и, если необходимо, порта, на которых веб-сервер Apache будет принимать запросы от Nginx и опять-же по мере надобности, настройка виртуальных хостов, так-же затронутая в вышеприведенной статье. Напомню, сервер Apache будет принимать соединения на локальном адресе 127.0.0.1, порт 80. Кроме того, все в той-же статье, мы настроили модуль сервера Apache, mod_rpaf, для передачи в Apache, реальных адресов клиентов, а не внутреннего адреса сервера Nginx.
1. Пишем скрипт на любом языке
В скрипте отправляем файл на проверку, в конце отдаем 2xx код.
Контролируемые скачивания в Nginx
Контролируемое скачивание, реализуемое в веб сервере Nginx с использованием заголовка X-Accel-Redirect, подразумевает следующий алгоритм при отдаче контента:
- Клиент нажимает на ссылку "скачать файл"
- Запрос передается веб серверу Nginx
- Nginx в свою очередь передает запрос некоему скрипту на проверку
- Скрипт, после проверки, например валидности запроса на скачивание, возвращает запрос в Nginx, устанавливая заголовок X-Accel-Redirect
- Запрос с заголовком X-Accel-Redirect попадает в специальный внутренний location, сервера Nginx, откуда и отдается клиенту
6 — N способ: "место для вашей рекламы"
Сюда можете придумать еще несколько смешных способов прострелить себе ногу.
Плюсы:
1) Вы придумали его сами или по крайней мере знаете
Минусы:
1) Он подходит только вам и только в вашем конкретном случае
Nginx в качестве проксирующего сервера Apache
В предыдущей статье, "Веб сервер Nginx, обзор функциональных возможностей", речь шла об основных функциональных возможностях сервера Nginx, а так-же затронут вопрос его использования в качестве проксирующего фронтенд-сервера в связке с веб сервером Apache. Здесь хотелось-бы рассказать о практической стороне вопроса, то есть перейти непосредственно к установке и настройке вышеупомянутой связки, Nginx - Apache. Так как всем остальным *nix системам, я предпочитаю FreeBSD, на ней и будем все это поднимать.
4. А как работает докачка в других браузерах?
Везде есть свои особенности. В общих чертах случай докачки выглядит так. Запрос/ответ на скачку (начало скачки):
Запрос/ответ на докачку:
На практике ни один браузер не ограничивается таким набором заголовков. Все хотят защитить пользователя от скачки битого файла. Это может получиться так: начал закачку, поставил на паузу; в это время на сервере скачиваемый файл обновился; продолжил закачку с нужно места и получил кусок обновленного файла. В результате скачается «битый» файл — половина старая версия, половина — новая.
Opera. Она шлет указание на то, что «если файл не менялся со времени Last-Modified в первом ответе, дай мне указанный кусок; иначе — отдай мне весь файл заново». Делается это с помощью заголовка If-Range в запросе:
Firefox. Он делает немного иначе. Используется заголовок If-Unmodified-Since с указанием того же времени из Last-Modified. В этом случае сервер либо вернет запрошенный кусок (если файл не менялся), либо отдаст ошибку 412 Precondition Failed. Выглядит это так:
Chrome. Этот «пильмень» — самый хитрый. Он вообще не поддерживает докачку, хотя делает вид, что поддерживает. При постановке закачка на паузу он просто шлет некие TCP-пакеты для поддержания соединения. Когда сервер понимает, что его дурят, он разрывает соединение. Если дождаться этого момента и нажать в Хроме «Продолжить», он сделает умный вид, будто файл полностью скачался и все ОК, но при этом он останется в том размере, в котором успел скачаться до паузы.
Вся эта информация получена методом наблюдения. Возможно в какой-то другой ситуации Хром повел бы себя иначе, но я через WireShark наблюдал именно такую картину.
IE. Про версию 9 уже сказано выше. Она требует работы Etag для поддержки докачки. В данном контексте ETag — это просто контрольная сумма файла. Когда Etag файла передается в первом ответе от сервера, IE даст возможность прервать скачку. При попытке докачки он отдаст заголовки:
В добавок к If-Range он передает нестадартный заголовок Unless-Modified-Since — вероятено IIS его обрабатывает (только не понятно, зачем он, если есть стандартный If-Unmodified-Since; может для поддержки старых версий IIS?).
Собственно в первом ответе Etag выглядит примерно так (если он поддерживается сервером, например, Apache):
Собственно зачем вообще запрещать доступ к сайту по географическому признаку ? Да просто 80% IP адресов участвующих в ddos атаке, как правило принадлежат странам, жители которых никогда не зайдут на данный сайт, естественно это сугубо индивидуально для каждого ресурса и если вы знаете что часть ваших посетителей приходит из Эфиопии или Чили, блокировать их, вы вряд-ли захотите. У большинства-же моих клиентов, географическое расположение посетителей, как правило ограничивается Европой и бывшим СССР, остальных можно смело игнорировать.
1. Пишем скрипт на любом языке
4 способ: "студент АВТФ"
Да ну вас нахуй, давайте читать файл и отдавать его сразу из скрипта. Я по-другому не умею. Я буду читать гигабайтный файл в RAM через open() и затем отдавать как обычный Response(), да еще и заюзаю костыль для определения правильного mimetype.
Плюсы:
1) Охуенно!
2) Решает все проблемы со всеми ссылками.
Минусы:
1) Если повезет и стандартная библиотека вашего любимого языка будет сначала читать весь файл в память, или вы не подумав написали какой-нить return file.realAll(), то вы Хороший Программист!
2) А если не будет и она (скорее всего) умеет читать и отдавать его по-частям, то я вам желаю удачи с пользователями с Дальнего Востока, где интернет по талонам и скорость в кб/с больше похожа на короткий номер службы спасения. вы лишаетесь одного воркера на час. А так как у меня даже самые нужные проекты запускаются с 5-10 воркерами и чувствуют себя отлично, то может наступить пизд^W Bad Gateway или что-то в этом духе.
NGINX - 301 Редирект Moved Permanently
301 Moved Permanently, редирект, говорящий что ресурс перемещен на постоянной основе. В интернетах пишут что мол типа архинеобходимо для SEO, мол поисковики это дюже уважают), спорить не буду, не вникал. В веб сервере Nginx 301 редирект настраивается в конфигурационном файле ( в apache можно через файл .htaccess ), таким образом:
Nginx RewriteRules для движка DLE
По работе, периодически приходиться заниматься переносом уже работающих ресурсов с веб сервера Apache на связку nginx - fastcgi, или со старого сервера на новый с уже установленным веб сервером nginx. Ни в коем разе не допускаю мысли, что Apache плохой веб сервер, учитывая количество модулей, он очень универсален, можно решать практически любые задачи, но его монстрообразность предъявляет определенные требования к ресурсам системы.
Место публикации личных заметок. Технологии, управление, бизнес, жизнь
Как контролировать скачивание больших файлов, проверяя права доступа или считая количество закачек? Как сделать, чтобы при проксировании на Apache работала докачка? Как вообще работает докачка, почему она не работает с nginx в IE 9 и как она работает в других браузерах?
2 способ: "долбоеб-педераст"
Похож на предыдущий способ открывания папки в паблик, но с добавлением проверки по рефералу. Если пришел по хотлинку - файл не давать.
Плюсы:
1) Те же, что у предыдущего способа
2) Теперь никто не даст хотлинк
Минусы:
1) Нужна лопатка для соскребания говна, вылитого на тебя конечными пользователями такой системы.
2) Лишний редирект
Замена RewriteRules для Server Stat System
Думаю многие играли или играют или хотя-бы слышали о такой популярной игрухе как Counter Strike. Серверов с этой игрой в сети как грязи нынче.
В общем случилось поднимать игровой сервак + веб морду для модуля статистики Server Stat System.
Настройка веб сервера Nginx, на работу с бакэндами, Apache и FastCGI
Опции с которыми был установлен сервер Nginx, приводились выше, то есть по сути, это "умолчальная" установка, изменены некоторые пути, как мне привычней и включен модуль для просмотра статусной страницы Nginx.
Перейдем к конфигурационному файлу.
Хотелось-бы отметить, что окончательный вид конфигурационного файла Nginx, зависит от вашей конкретной системы, то есть например, различные таймауты, размеры и количество буферов, передаваемые заголовки и т.д., должны быть установлены, исходя из задач, решаемых на данном сервере. Поэтому давать рекомендации в стиле, "поставьте этого столько а того столько и напишите это.. потому что у меня это работает.. ", считаю неуместным.
Здесь у нас рабочий вариант конфигурационного файла nginx, так сказать, без наворотов, лишь необходимый минимум. Выглядит он у нас следующим образом:
Проверяем правильность файла конфигурации:
Все в порядке, можно запускать
Проверим что у нас там показывает netstat:
Теперь все это можно проверить через браузер, набрав имя хоста Nginx или IP адрес. Что-бы убедиться что PHP скрипты обрабатываются нашим FastCGI сервером, можно создать файл следующего содержания:
и положить его в корневую директорию документов сайта. Теперь запросив его через браузер, мы увидим страницу PHP, с кучей различной технической информации, включая опции сборки, настройки, модули, расширения, конфигурационные файлы и т.д. Находим строку Server API, и видим в каком режиме работает PHP на данном хосте, это у нас, CGI/FastCGI, то есть, то что нам и было нужно.
Проверить, что и остальные Location, отрабатывают должным образом, передавая запросы бакэндам, можно так, создать необходимый файл, запросить его через строку браузера и проверить лог файлы. То есть, запрос к файлу test.pl, можно будет обнаружить в файле access.log, виртуального хоста, сервера Apache, а запрос к файлу test.html, в лог файле веб сервера Nginx.
У нас nginx работает как прокси сервер для онлайн хранилища файлов. Как можно настроить, что бы при скачивании файла (или при прохождении любого трафика через этот прокси), nginx передавал файл как пользователю, который его запрашивает, так и другому серверу (у нас там антивирус)? Тоесть сразу в 2 места.
Нужно сначала проверить антивирусом а потом отдавать пользователю если все ОК? Или просто вторым запросом слать в антивирь и сразу отдавать пользователю?
2. В такой схеме при проксировании на Apache не работает докачка. Исправляем.
Первый вариант просит отдать весь файл, начиная с 33 байта (включительно). Второй вариант просит отдать с 33 байта по 100. Чтобы браузер понял, что докачка поддерживается, сервер отдает в ответе заголовок:
Исправляется это довольно легко — просто зануляйте при проксировании Range (это нужно добавить туда, где у вас описано проксирование на Apache в конфиге nginx):
Тогда Apache (или PHP-скрипт) ничего знать про него не будут и спокойно сделают свое дело. А nginx после Accel-Redirect отдаст ответ в соответствии с запрошенным Range.
Если жизненно необходимо видеть в скрипте запрошенный Range, то его можно либо передать через дополнительный заголовок при проксировании (proxy_add_header), либо последовать совету отсюда.
Читайте также: