web-dev-qa-db-ja.com

nginxで大きなファイルのアップロードを防ぐ

NginxをWebサーバーとして使用してWebサイトにサービスを提供しています。私はユーザーにアップロード機能を提供しているので(ユーザーは最大5Mbの写真を送信できます)、サーバー構成に_client_max_body_size 5M;_というディレクティブがあります。私が気付いたのは、ファイルをアップロードしようとしても、Webサーバーが大きなファイルのアップロードを妨げないということです。例として、700Mbの非常に大きなビデオ(映画)をアップロードしようとしたとします。サーバーはアップロードを即座に拒否しませんが、データ全体をバッファリングし(非常に時間がかかり、サーバーの速度が低下します)、アップロードの最後にのみ_413 Request entity too large_エラーを返します。

したがって、問題は、送信されたデータが私の_client_max_body_size_制限を超え始めたときに、大きなファイルのアップロードをブロックするようにNginxを適切に構成する方法はありますか?

私の実際の設定で本番環境に移行するのは本当に安全ではないと思います。グーグルで役立つものを見つけることができませんでした。

編集:

バックエンドとして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はある種の予防的チェックを行いますが、アップロード要求を停止/チャンクしません...

また、アップロードを処理するページでecho 'something'; die();を発行して、phpがアップロードを制御できるかどうかを確認しようとしましたが、何も出力されず、アップロード要求が停止しませんでした。したがって、完全に送信されるまでアップロード全体を継続させるのは、nginxまたはいくつかのphp内部である必要があります...

別の編集:大きなファイルのアップロードが進行中(nginxが過負荷になる)のときの私のtop(nginxとphpの監視)のビューは次のとおりです。 top: monitoring php and 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;
    }
}
_
4
Luciano Mammino

ここで役立つ情報: https://stackoverflow.com/questions/4947107/nginx-upload-client-max-body-size-issue

私は(私の場合)最も興味深い答えの一部を引用します:

ほとんどのクライアントは、リクエスト本文全体が送信されるまで応答を読み取りません。 nginxが接続を閉じるため、クライアントは閉じたソケットにデータを送信し、TCP RSTを引き起こします。

もしそうなら、それは私のウェブサーバーに影響を与えない(オーバーロードする)ブラウザの問題だけです。大きな(700mb)ファイルをアップロードするときにnginxとphp-fastcgiの両方が本当に過負荷になっていないことを示した私のメモリ検査に不満があるようです。

ブラウザの問題には、次のようないくつかの方法で対処できます。

  • フォームに<input type="hidden" name="MAX_FILE_SIZE" value="5242880" />を追加します
  • カスタム413nginxエラーページを使用する
3
Luciano Mammino

アップロードする前にサイズを確認する必要があるため、phpまたはRailsなど)を使用していますか?.
set post_max_sizeおよびpload_max_filesizefile: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');
0
Harrys Kavan