NGINX でレート制限する方法

NGINX のレート制限は、サーバーが処理するトラフィックの量を制御するための重要な機能です。これにより、DDoS やトラフィックの急増などの悪意のある攻撃によって、短期間に大量のリクエストが送信されてサーバーが過負荷になるのを防ぐことができます。レート制限を実装すると、リソースが効率的に使用され、正当なユーザーが中断することなくサービスにアクセスできるようになります。

このガイドでは、NGINX でレート制限を構成する方法を示し、受信トラフィックを効果的に管理および制御するのに役立つ明確な手順を示します。

NGINX のレート制限ディレクティブを理解する

主要な NGINX レート制限ディレクティブ

NGINX は、それぞれが独自の機能を果たす特定のディレクティブを使用してレート制限を設定します。

  • 制限要件ゾーン: NGINX の limit_req_zone ディレクティブは、レート制限情報を格納するための共有メモリ ゾーンを設定します。http コンテキストに配置され、リクエストの許容レートを決定し、レート制限のベースラインを効果的に設定しています。
  • 制限要件: 場所のコンテキストで使用される limit_req ディレクティブは、limit_req_zone によって設定されたレート制限を適用します。これらの制限を特定の場所または URL に適用し、これらのエンドポイントへのアクセス頻度を制御します。
  • 制限要求ステータス: ロケーション コンテキストに配置された limit_req_status ディレクティブは、要求レートが制限を超えたときに返される HTTP ステータス コードを指定します。このフィードバック メカニズムは、許可された要求頻度を超えたときにユーザーまたは自動化システムに通知するために重要です。

レート制限設定の作成

NGINX でレート制限を実装するには、NGINX 構成ファイルに適切なディレクティブを挿入します。次の基本的な例を検討してください。

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    server {
        ...
        location / {
            limit_req zone=mylimit burst=10;
            ...
        }
    }
}

この構成では、limit_req_zone ディレクティブは「mylimit」という名前のメモリ ゾーンを確立し、各クライアント IP アドレス ($binary_remote_addr) からの 1 秒あたり 5 件のリクエスト (5r/s) を許可します。次に、limit_req ディレクティブは、このレート制限をルート ロケーション (/) に適用し、バースト容量を 10 件のリクエストに設定して、厳格なレート制限と正当なトラフィック スパイクに対する柔軟性のバランスを実現します。

NGINX のレート制限: 実例

基本的なレート制限設定

このセクションでは、NGINX でサーバー全体に適用される基本的なレート制限構成について説明します。目的は、サーバーへのユーザー リクエストを制限し、安定したパフォーマンスを確保して、過負荷のリスクを軽減することです。

例: サーバー全体のレート制限

次の NGINX 構成を検討してください。

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=2r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=mylimit burst=5;
            proxy_pass http://backend;
        }
    }
}

この設定では、IPアドレスによって定義される各クライアントに対して、1秒あたり2リクエストの制限が設定されます($binary_remote_addr) 主要なコンポーネントを分解してみましょう。

  • 制限要件ゾーン: レート制限状態を保存するための 10 メガバイトのメモリ ゾーン (mylimit) を定義します。レート制限を 1 秒あたり 2 リクエスト (2r/s) に設定します。
  • サーバーブロック: example.com への着信トラフィックをポート 80 でリッスンします。
  • ロケーションブロック: ルート URL (/) にレート制限を適用します。burst パラメータは最大 5 リクエストのバーストを許可し、トラフィックの短期的な急増に柔軟に対応します。proxy_pass ディレクティブは、指定されたバックエンド サーバーにリクエストを転送します。
  • バーストパラメータ: limit_req ディレクティブの burst=5 設定により、設定されたレートを超えるリクエストを最大 5 件まで、一時的に増加させることができます。この機能は、ユーザー エクスペリエンスに影響を与えずに、トラフィックの突然の正当な増加を処理するために不可欠です。
  • プロキシパス: proxy_pass http://backend; ディレクティブは、トラフィックをバックエンド サーバーに転送します。これは、負荷分散シナリオや、NGINX がリバース プロキシとして機能する場合によく使用されます。

高度なレート制限の例

場所によって異なるレート制限

より複雑なシナリオでは、アプリケーションのさまざまな部分に異なるレート制限を適用する必要がある場合があります。これは、特定のエンドポイントがより多くのリソースを消費したり、悪用されたりする傾向がある場合に特に役立ちます。

次の構成を検討してください。

http {
    limit_req_zone $binary_remote_addr zone=low:10m rate=1r/s;
    limit_req_zone $binary_remote_addr zone=high:10m rate=10r/s;

    server {
        listen 80;
        server_name example.com;

        location /api/low {
            limit_req zone=low burst=3;
            proxy_pass http://backend;
        }

        location /api/high {
            limit_req zone=high burst=20;
            proxy_pass http://backend;
        }
    }
}

この構成では、/api/low の場所に低いレート制限 (1 秒あたり 1 リクエスト) が適用され、/api/high の場所に高いレート制限 (1 秒あたり 10 リクエスト) が適用されます。

追加の Nginx レート制限の例

リクエストタイプに基づくレート制限

GET、POST、PUT リクエストなどの特定のリクエストに基づいてレート制限を設定できます。これは、不正使用に対して脆弱であったり、サーバー リソースに大きな影響を与える特定のエンドポイントを保護する場合に特に便利です。

if ディレクティブと $request_method 変数を使用して、特定のリクエスト タイプにレート制限を適用できます。次に例を示します。

http {
    limit_req_zone $binary_remote_addr zone=get_limit:10m rate=5r/s;
    limit_req_zone $binary_remote_addr zone=post_limit:10m rate=2r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            if ($request_method = GET) {
                limit_req zone=get_limit burst=10;
            }

            if ($request_method = POST) {
                limit_req zone=post_limit burst=5;
            }

            proxy_pass http://backend;
        }
    }
}

この構成では、GET リクエスト用 (1 秒あたり 5 リクエスト) と POST リクエスト用 (1 秒あたり 2 リクエスト) の 2 つの個別のレート制限を設定しました。

ユーザーエージェントに基づくレート制限

もう 1 つの便利なテクニックは、クライアントから送信された User-Agent ヘッダーに基づいてレート制限を適用することです。これにより、問題を引き起こす特定のボットやクローラーからサービスを保護することができます。

User-Agent に基づいてレート制限を実装するには、map ディレクティブと $http_user_agent 変数を使用できます。

次に例を示します。

http {
    map $http_user_agent $limit_bots {
        default 0;
        ~*(Googlebot|Bingbot) 1;
    }

    limit_req_zone $binary_remote_addr zone=bot_limit:10m rate=1r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            if ($limit_bots) {
                limit_req zone=bot_limit burst=2;
            }

            proxy_pass http://backend;
        }
    }
}

この例では、User-Agent ヘッダーが「Googlebot」または「Bingbot」と一致する場合に $limit_bots 変数を 1 に設定するマップ ディレクティブを定義しました。次に、これらのボットからのリクエストに 1 秒あたり 1 リクエストのレート制限を適用します。

レート制限から IP をホワイトリストに登録する

信頼できるパートナーや内部サービスなどの特定のIPアドレスをレート制限から除外したい場合があります。これを実現するには、geoディレクティブと if 指令。

次に例を示します。

http {
    geo $rate_limit {
        default 1;
        192.168.0.0/24 0;
        10.0.0.0/8 0;
    }

    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    server {
        listen 80;
        server_name example.com;

        location / {
            if ($rate_limit) {
                limit_req zone=mylimit burst=10;
            }

            proxy_pass http://backend;
        }
    }
}

分散環境でのレート制限のスケーリング

分散環境で複数の Nginx インスタンスが実行されている場合、すべてのインスタンスでレート制限が一貫していることを確認する必要があります。これを実現するには、Redis などの集中型データ ストアを使用してレート制限を管理できます。これにより、すべての Nginx インスタンス間で共有されるグローバル レート制限を維持できます。

Redis でレート制限を設定するには、nginx-module-redis モジュールをインストールして構成する必要があります。モジュールをインストールしたら、レート制限に Redis を使用するように Nginx 構成を更新できます。

次に例を示します。

load_module modules/ngx_http_redis_module.so;

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/s;

    upstream redis_server {
        server 127.0.0.1:6379;
        keepalive 32;
    }

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req_redis zone=mylimit burst=10 redis_server=redis_server;
            proxy_pass http://backend;
        }
    }
}

この例では、Redis サーバーのアップストリーム ブロックを定義し、標準の limit_req ディレクティブの代わりに limit_req_redis ディレクティブを使用するように location ブロックを更新しました。この構成により、共有 Redis データ ストアを使用してレート制限が適用され、複数の Nginx インスタンス間で一貫したレート制限が提供されます。

動的レート制限

状況によっては、特定の条件やサーバーの現在の負荷に基づいて、レート制限を動的に調整する必要がある場合があります。たとえば、トラフィックのピーク時に厳しいレート制限を適用して、サーバー リソースをより適切に管理する必要がある場合があります。

動的なレート制限を実装するには、 map 特定の条件に基づいてレート制限を定義するためのディレクティブ。

次に例を示します。

http {
    map $http_x_traffic $dynamic_rate {
        default "5r/s";
        high "2r/s";
    }

    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=$dynamic_rate;

    server {
        listen 80;
        server_name example.com;

        location / {
            limit_req zone=mylimit burst=10;
            proxy_pass http://backend;
        }
    }
}

この設定では、カスタム ヘッダー X-Traffic から派生した $http_x_traffic 変数を使用します。このヘッダーの値に基づいて、レート制限を動的に設定します。ヘッダー値が「高」の場合、1 秒あたり 2 リクエストというより厳しいレート制限が適用されます。それ以外の場合は、1 秒あたり 5 リクエストというデフォルトのレートが使用されます。

この例では、バックエンド サーバーまたはインフラストラクチャ内の別のコンポーネントが、必要な条件に基づいて X-Traffic ヘッダーを設定することを前提としていることに注意してください。

NGINX 設定でレート制限をテストする

curl によるレート制限の検証

シンプルなリクエストテストに curl を使用する

NGINX でのレート制限設定の有効性を検証するには、HTTP リクエストを送信するためのコマンドライン ツールである curl が非常に役立ちます。curl を使用すると、複数のリクエストをサーバーにすばやく送信できるため、レート制限がアクティブかどうかを評価できます。

for i in {1..10}; do curl -I http://example.com; done
  • このコマンドは、http://example.com を対象に、サーバーに 10 個の HEAD リクエストを発行します。
  • これらのリクエストからの HTTP 応答ヘッダーを分析して、レート制限機能を確認します。
  • リクエストのレートが指定した制限を超えると、NGINX は 429 Too Many Requests ステータス コードを返します。

Apache Bench によるテスト (ab)

Apache Bench によるサーバー応答のベンチマーク

Apache Bench (ab) は、高トラフィック状況をシミュレートしてレート制限をテストするのに最適な効果的なベンチマーク ツールです。リクエストの急増時に NGINX サーバーがどのように動作するかを理解するのに役立ちます。

ab -n 100 -c 10 http://example.com/
  • このコマンドは、同時実行レベル 10 で 100 件のリクエストを http://example.com に送信するように ab に指示します。
  • ab からの出力は、レート制限の有効性に関する洞察を提供します。
  • 出力内の失敗したリクエストの数に注目してください。これは、NGINX レート制限構成の設定と一致する必要があります。

NGINX 構成をテストするための最適な方法を採用することで、レート制限ルールが意図したとおりに機能することが保証されます。

結論

NGINX でレート制限を設定すると、過剰なトラフィックや潜在的な不正使用からサーバーを保護できます。これにより、サービスのパフォーマンスと可用性が維持され、正当なユーザーのエクスペリエンスが向上します。レート制限設定を定期的に監視して調整し、セキュリティとアクセシビリティのバランスをとってください。これらの制御を実装することは、サーバーのリソースを効率的に管理するために不可欠です。

Joshua James

コメントを残す