2026年7月5日
2026年7月5日
WordPressで「429 Too Many Requests」が出るときの原因と解決方法
WordPressで「429 Too Many Requests」が表示されるのは、短時間に送られたリクエストが多すぎると、どこかの層が判断してアクセスを一時的に止めているためです。429を返しているのはWordPress本体ではなく、CDN、サーバー会社のWAF、Webサーバーの設定、セキュリティプラグインのいずれかであることがほとんどなので、まず「誰が429を返しているか」を特定し、その層の設定か、リクエストを増やしている原因を直します。この記事では、返している層の見分け方、ログでの確認方法、WordPressでよくある原因ごとの対処を解説します。
429 Too Many Requestsとは
HTTPステータスコード429は、クライアントが一定時間内に送ったリクエストの数が上限を超えたことを表します。不正ログインの総当たりや、サイトを大量に巡回するボットからサーバーを守るための仕組み(レート制限)が働いた結果です。応答に Retry-After ヘッダーが付いていれば、何秒後に再試行してよいかの目安になります。
つまり、429が出ること自体は、制限が意図どおりに動いている証拠でもあります。問題になるのは、正規の訪問者や管理者、検索エンジンのクローラーまで止められている場合です。
誰が429を返しているかを見分ける
対処する場所を決めるため、最初に429を返している層を確認します。手元のPCから、429が出るURLの応答ヘッダーを表示します。
curl -sI https://example.com/wp-login.php
見るべき点は次のとおりです。
server: cloudflareやcf-rayがあれば、Cloudflareのルールで止まっている可能性が高いです。Cloudflareのダッシュボードのセキュリティイベントで、どのルールが働いたか確認できます。server: nginxで、Nginxの標準的なエラーページが返っていれば、Nginxのlimit_reqなどの設定が考えられます。- サーバー会社独自のエラーページであれば、サーバー会社のWAFやアクセス制限の機能です。コントロールパネルの設定やログを確認します。
- WordPressのデザインに近いブロック画面や、セキュリティプラグインの名前が入った画面であれば、プラグインのレート制限です。
ブラウザの開発者ツールのネットワークタブでも、同じヘッダーを確認できます。
サーバーのアクセスログで確認する
サーバーにログインできる場合は、アクセスログで429がどのIPアドレス、どのURLに対して返っているかを集計します。一般的なcombined形式のログでは、9番目の項目がステータスコードです。
# 429を受けたIPアドレスの上位
awk '$9 == 429 {print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 429が返ったURLの上位
awk '$9 == 429 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
Apacheの場合はログのパスを /var/log/apache2/access.log などに置き換えます。サーバーのログに429が1件も無いのに訪問者が429を受けているなら、Webサーバーより手前のCDNやWAFで止まっていると判断できます。
集計結果から、原因はおおむね次のどれかに絞り込めます。
原因1:ログイン画面やXML-RPCへの大量アクセス
/wp-login.php や /xmlrpc.php への429が多く、送信元が多数の海外IPアドレスに分散している場合は、総当たり攻撃に制限が働いている状態です。制限は正しく動いているので、緩める必要はありません。
ただし、管理者自身が止められてしまうなら、次のような対応を検討します。
- XML-RPCを使っていない場合(Jetpackやスマートフォンアプリからの投稿などで使っていない場合)は、XML-RPCへのアクセスそのものを止め、ボットのリクエストを減らす
- 管理者の固定IPアドレスがあれば、そのアドレスを制限の対象外にする
- ログイン画面には、回数制限に加えて二段階認証を入れ、制限の値に頼りすぎない構成にする
原因2:管理画面のHeartbeatによるadmin-ajax.phpへの連続リクエスト
管理者がログイン中に429を受け、ログで /wp-admin/admin-ajax.php への429が目立つ場合は、Heartbeat APIが原因のことがあります。WordPressは投稿の編集中などに、自動保存やロック状態の確認のため、一定間隔で admin-ajax.php にリクエストを送ります。複数の管理画面のタブを開いたままにしたり、複数人が同じIPアドレスから作業したりすると、回数の多い制限に引っかかりやすくなります。
heartbeat_settings フィルターで送信間隔を広げると、リクエストの数を減らせます。
<?php
// 子テーマの functions.php または独自プラグインに記述
add_filter( 'heartbeat_settings', function ( $settings ) {
$settings['interval'] = 60; // 送信間隔(秒)
return $settings;
} );
Heartbeatを止めてしまうと、自動保存や同時編集の警告が働かなくなるため、停止ではなく間隔の調整にとどめるのが無難です。
原因3:CDNやリバースプロキシの経由で全員が同じIPに見えている
CDNやロードバランサーを経由している場合、Webサーバーやプラグインが訪問者の本当のIPアドレスではなく、CDNのIPアドレスを見ていることがあります。この状態でIPアドレスごとのレート制限をかけると、多数の訪問者のリクエストが少数のIPアドレスからのものとして数えられ、普通にアクセスしているだけの人まで429になります。
Nginxでは、ngx_http_realip_module で、信頼するプロキシのIPアドレス範囲と、本当のIPアドレスが入っているヘッダーを指定します。
# http または server ブロック
# 信頼するプロキシのIP範囲(CDNが公開している最新の範囲に置き換える)
set_real_ip_from 203.0.113.0/24;
# Cloudflareの場合は CF-Connecting-IP、一般的なプロキシなら X-Forwarded-For
real_ip_header CF-Connecting-IP;
Apacheでは mod_remoteip の RemoteIPHeader と RemoteIPTrustedProxy で同じことができます。信頼する範囲を広く取りすぎると、ヘッダーを偽装したアクセスで制限をすり抜けられるため、CDNが公開している範囲だけを指定し、定期的に見直します。
原因4:Webサーバーのレート制限が厳しすぎる
Nginxの limit_req を自分で設定している場合、すべてのURLに同じ制限をかけていたり、一時的な集中を許す burst を指定していなかったりすると、画像やCSSを多く読み込むページを開いただけで制限を超えることがあります。制限はログイン画面など守りたいURLに絞って設定します。
設定を変える前に、元の設定ファイルを別名でコピーしておきます。
# http ブロック:IPアドレスごとに1分あたり5回まで
limit_req_zone $binary_remote_addr zone=wp_login:10m rate=5r/m;
# 制限時に返すステータス(標準は503)
limit_req_status 429;
# server ブロック:wp-login.php だけに制限をかける
location = /wp-login.php {
# 超過しても5回までは待たせずに受け付ける
limit_req zone=wp_login burst=5 nodelay;
# PHPへの受け渡しは、既存の location ~ \.php$ と同じ内容にする
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
location = /wp-login.php を作ると、既存のPHP用の location ではなくこちらが使われるため、PHPへの受け渡しの設定も中に書く必要があります。ここが抜けると、ログイン画面のPHPファイルがダウンロードされたり404になったりします。fastcgi_pass のソケットのパスは環境によって異なるので、既存の設定に合わせてください。変更後は sudo nginx -t で構文を確認してから sudo systemctl reload nginx で反映します。
原因5:WordPressから外部APIへのリクエストが429を受けている
サイトの表示ではなく、プラグインの同期処理や外部サービスとの連携で「429」が記録されている場合は、WordPressが外部APIの上限を超えています。ページが表示されるたびにAPIを呼んでいる、WP-Cronで短い間隔の処理を何本も動かしている、といったことが原因になります。
自作のコードであれば、取得結果をトランジェントに保存してAPIを呼ぶ回数を減らし、429を受けたら Retry-After の時間だけ再試行を止めるようにします。
<?php
function my_get_remote_items() {
$cached = get_transient( 'my_remote_items' );
if ( false !== $cached ) {
return $cached;
}
// 429を受けた直後は、待機時間が過ぎるまでAPIを呼ばない
if ( get_transient( 'my_remote_items_backoff' ) ) {
return null;
}
$response = wp_remote_get( 'https://api.example.com/v1/items', array( 'timeout' => 10 ) );
if ( is_wp_error( $response ) ) {
return null;
}
$code = (int) wp_remote_retrieve_response_code( $response );
if ( 429 === $code ) {
// Retry-After が秒数ならその秒数、日時形式などで読めなければ5分待つ
$retry_after = (int) wp_remote_retrieve_header( $response, 'retry-after' );
$wait = $retry_after > 0 ? $retry_after : 5 * MINUTE_IN_SECONDS;
set_transient( 'my_remote_items_backoff', 1, $wait );
return null;
}
if ( 200 !== $code ) {
return null;
}
$items = json_decode( wp_remote_retrieve_body( $response ), true );
set_transient( 'my_remote_items', $items, 10 * MINUTE_IN_SECONDS );
return $items;
}
既製のプラグインで起きている場合は、同期の間隔を広げる設定が無いか確認し、無ければ開発元に報告します。
検索エンジンのクローラーへの影響
Googleは429を「サーバーの負荷が高い」という合図として扱い、クロールの頻度を下げると案内しています。一時的であれば大きな問題にはなりにくいものの、長く続くとページの再クロールや新しいページの発見が遅れるおそれがあります。Search Consoleのクロールの統計情報で、429を含むエラーが増えていないか確認し、正規のクローラーまで止めている制限は見直します。仕様は変わることがあるため、2026年10月現在の情報として、最新の扱いは公式ドキュメントで確認してください。
まとめ
- 429はレート制限が働いた結果で、返しているのはCDN、サーバー会社のWAF、Webサーバー、セキュリティプラグインのどれかであることがほとんどです。
curl -sIの応答ヘッダーとアクセスログの集計で、返している層と、対象のIPアドレス・URLを特定します。- ログイン画面やXML-RPCへの攻撃なら制限は維持し、管理者の除外や不要な機能の停止で対応します。
- Heartbeatの間隔、CDN経由の本当のIPアドレスの取得、
limit_reqの対象とburstを見直すと、正規の利用者が止められる状況を減らせます。 - 外部APIの429は、キャッシュと
Retry-Afterに従った待機で呼び出し回数を抑えます。