Запрет загрузки большого файла с помощью nginx
Я обслуживаю свой сайт, используя Nginx в качестве веб-сервера. Я предлагаю пользователям возможность загрузки (им разрешено отправлять изображения размером до 5 Мб), поэтому у меня есть директива: client_max_body_size 5M;
в моем конфиге сервера. Что я заметил, так это то, что если я пытаюсь загрузить какой-либо файл, веб-сервер не препятствует загрузке больших файлов. В качестве примера, предположим, я пытаюсь загрузить действительно большое видео (фильм) размером 700 Мб. Сервер не отклоняет загрузку мгновенно, но он буферизирует все данные (занимает так много времени и замедляет работу сервера) и только в конце загрузки возвращает 413 Request entity too large
ошибка.
Таким образом, вопрос: есть ли способ правильно настроить Nginx для блокировки загрузки больших файлов, когда передаваемые данные начинают преодолевать мои client_max_body_size
ограничение?
Я думаю, что было бы действительно небезопасно продолжать работу с моими фактическими настройками, и я не смог найти ничего полезного в Google.
Редактировать:
Я использую php и Symfony2 в качестве бэкэнда...
Изменить (снова):
Вот что появляется в моем error.log:
2013/01/28 11:14:11 [error] 11328#0: *37 client intended to send too large body: 725207449 bytes, client: 33.33.33.1, server: www.local.example.com, request: "POST /app_dev.php/api/image/add/byuploader HTTP/1.1", host: "local.example.com", referrer: "http://local.example.com/app_dev.php/"`
Странно то, что я слежу за своим nginx error.log
с tail -f error.log
и сообщение появляется сразу же после начала загрузки (до ее окончания). Итак, nginx делает какую-то превентивную проверку, но не останавливает / не блокирует запрос на загрузку...
Я также попытался проверить, получает ли php контроль над загрузкой, выполнив echo 'something'; die();
на странице, которая обрабатывает загрузку, но она ничего не распечатывает и не останавливает запрос на загрузку. Так что это должен быть nginx или несколько внутренних элементов php, которые заставляют всю загрузку продолжаться, пока она не будет полностью передана...
другое редактирование: вот мой взгляд top
(мониторинг nginx и php), когда идет загрузка большого файла (nginx перегружается):
редактировать: вот моя конфигурация nginx
server {
listen 80;
server_name www.local.example.com local.example.com;
access_log /vagrant/logs/example.com/access.log;
error_log /vagrant/logs/example.com/error.log;
root /vagrant/example.com/web;
index app.php;
client_max_body_size 6M;
location /phpmyadmin {
root /usr/share;
index index.php;
location ~* \.php {
fastcgi_intercept_errors on;
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
location / {
try_files $uri @rewriteapp;
}
location @rewriteapp {
rewrite ^(.*)$ /app.php/$1 last;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ ^/(app|app_dev)\.php(/|$) {
fastcgi_intercept_errors on;
fastcgi_pass 127.0.0.1:9000;
fastcgi_split_path_info ^(.+\.php)(/.*)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
}
}
2 ответа
Полезная информация здесь: https://stackoverflow.com/questions/4947107/nginx-upload-client-max-body-size-issue
Цитирую часть самого интересного ответа (для моего случая):
Большинство клиентов не читают ответы, пока не будет отправлено все тело запроса. Поскольку nginx закрывает соединение, клиент отправляет данные в закрытый сокет, вызывая TCP RST.
Если это так, то это только проблема браузера, которая не повлияет (перегрузит) мой веб-сервер. Кажется, мне жаль, что проверка памяти показала, что nginx и php-fastcgi не были действительно перегружены при загрузке большого (700 МБ) файла.
Я мог бы решить проблему с браузером несколькими способами, например:
- добавить
<input type="hidden" name="MAX_FILE_SIZE" value="5242880" />
в моей форме - используйте пользовательскую страницу ошибки 413 nginx
Что вы используете PHP или рельсы или что-то? потому что вы должны проверить размер перед загрузкой.
установите post_max_size и upload_max_filesize в соответствующее значение в файле:php.ini
редактировать: попробуйте написать что-то подобное в свою загрузку
$element = new Zend_Form_Element_File('foo');
$element->setLabel('Upload a file:')
->setDestination('/var/www/upload');
// make sure its only 1 file
$element->addValidator('Count', false, 1);
// Maximal 100k
$element->addValidator('Size', false, 102400);
// only JPEG, PNG, and GIFs
$element->addValidator('Extension', false, 'jpg,png,gif');
$form->addElement($element, 'foo');