Запрет загрузки большого файла с помощью 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');