2026年9月8日
2026年9月8日
Nginxのタイムアウト設定を最適化する(504・408の原因とPHP-FPMとの合わせ方)
Nginx のタイムアウトは「クライアントとの間」と「上流(PHP-FPM やバックエンド)との間」の2系統に分かれており、504 Gateway Time-out の多くは後者の fastcgi_read_timeout や proxy_read_timeout と、PHP 側の制限が噛み合っていないことで起きます。この記事では、主要なタイムアウト項目の意味と既定値、エラーログからどの項目が原因かを読み取る方法、WordPress で長い処理だけに余裕を持たせる設定の仕方を説明します。
タイムアウトの全体像
Nginx を前に置いた WordPress では、1つのリクエストが次の区間を通ります。
- ブラウザ → (CDN・ロードバランサー) → Nginx
- Nginx → PHP-FPM(または別サーバーへのリバースプロキシ)
- PHP-FPM → PHP スクリプトの実行 → データベースや外部 API
それぞれの区間に別々のタイムアウトがあり、いちばん短いものが先に切れます。Nginx の値だけを伸ばしても、PHP-FPM や CDN が先に切ってしまえば症状は変わりません。値を変える前に「どの区間で切れているのか」を特定することが最初の作業です。
主なタイムアウト項目と既定値
以下は公式ドキュメントに記載された既定値です(2026年10月現在)。将来のバージョンで変わる可能性はあるため、お使いの版のドキュメントもあわせて確認してください。
クライアント側の項目:
client_header_timeout(既定 60s):リクエストヘッダーを受け取りきるまでの待ち時間。超えると 408 を返します。client_body_timeout(既定 60s):リクエスト本文の「連続する2回の読み取りの間隔」の上限です。アップロード全体の時間ではない点に注意してください。send_timeout(既定 60s):応答を送るとき、連続する2回の書き込みの間隔の上限です。keepalive_timeout(既定 75s):持続的接続を開けたまま待つ時間。
上流側の項目(FastCGI の場合。リバースプロキシなら proxy_ で始まる同名の項目):
fastcgi_connect_timeout(既定 60s):PHP-FPM への接続確立までの時間。通常は 75 秒を超えて設定できません。fastcgi_send_timeout(既定 60s):PHP-FPM へリクエストを送る際の書き込み間隔の上限。fastcgi_read_timeout(既定 60s):PHP-FPM からの読み取り間隔の上限。処理が長い PHP はここで 504 になります。
「間隔」の上限である項目が多いのが Nginx の特徴です。たとえば fastcgi_read_timeout 60s は「応答全体を60秒以内に返せ」ではなく「60秒間何も届かなければ切る」という意味です。
エラーログから原因の項目を特定する
504 や 408 が出たら、まずエラーログを確認します。
sudo tail -n 50 /var/log/nginx/error.log
sudo grep -i "timed out" /var/log/nginx/error.log | tail -n 20
よく見るメッセージと、対応する項目は次のとおりです。
upstream timed out (110: Connection timed out) while reading response header from upstream:PHP-FPM が応答ヘッダーを返す前にfastcgi_read_timeout(またはproxy_read_timeout)を超えた。最も多いパターンです。upstream timed out ... while connecting to upstream:接続自体に時間がかかっている。PHP-FPM のプロセスが埋まっているか、バックエンドが停止している可能性があります。client timed out ... while reading client request headers/body:クライアント側。回線が遅い、または低速攻撃の可能性があります。upstream prematurely closed connection:Nginx ではなく PHP-FPM 側が先に処理を打ち切った。この場合は 502 になることが多く、PHP 側の制限を見直します。
アクセスログに $request_time や $upstream_response_time を記録していれば、どの URL が何秒かかっているかも分かります。特定の管理画面の操作だけが遅いのか、全体が遅いのかで対処が変わります。
PHP 側の制限と順番をそろえる
PHP の実行時間を縛る設定は主に2つあります。
max_execution_time(php.ini):スクリプトの実行時間の上限。Linux などでは、データベース待ちやスリープなどの時間は含まれないため、実際の経過時間はこの値より長くなることがあります。request_terminate_timeout(PHP-FPM のプール設定):経過時間で強制終了する上限。既定は 0(無効)です。
おすすめは「PHP 側の上限 ≦ Nginx の fastcgi_read_timeout」にそろえることです。PHP が先に止まれば WordPress 側でエラーとして記録され、原因を追いやすくなります。逆に Nginx が先に切ると、PHP はバックグラウンドで処理を続けたまま利用者には 504 が返り、二重送信などの問題が起きやすくなります。
; /etc/php/8.3/fpm/pool.d/www.conf(パスはディストリビューションと PHP のバージョンで異なります)
request_terminate_timeout = 120s
PHP-FPM の設定を変えたら sudo systemctl reload php8.3-fpm のようにサービス名を合わせて再読み込みします。
WordPress では長い処理の場所だけ伸ばす
サイト全体の fastcgi_read_timeout を何百秒にも伸ばすと、遅いリクエストがワーカーや PHP-FPM のプロセスを長時間占有し、混雑時にほかのページまで遅くなります。長い処理が必要なのは、多くの場合インポートやバックアップ、管理画面の一部の操作だけです。
# 管理画面配下だけ余裕を持たせる(具体的なほうを先に書く)
location ~ ^/wp-admin/.+\.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 180s;
}
# 通常の PHP
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 60s;
}
snippets/fastcgi-php.conf は Debian・Ubuntu のパッケージに含まれるファイルです。ほかの環境では fastcgi_params を読み込み、SCRIPT_FILENAME を自分で指定します。ソケットのパスも PHP のバージョンや環境で変わるので、既存の設定に合わせてください。正規表現の location は書かれた順に評価され、最初に一致したものが使われます。順番を逆にすると /wp-admin/ のリクエストも通常の PHP 側に一致してしまい、延長が効きません。
そもそも何分もかかる処理は、ブラウザ経由で実行しないのが根本的な解決です。大量の投稿のインポートや置換は WP-CLI でサーバー上から実行する、プラグインがバックグラウンド処理(WP-Cron や Action Scheduler など)に対応していればそちらを使う、といった方法を検討してください。
Nginx の外側にもタイムアウトがある
Nginx と PHP の値をそろえても、手前の CDN やロードバランサーが先に切ることがあります。Cloudflare 経由なら独自のエラー画面(524 など)が出ますし、クラウドのロードバランサーにもアイドルタイムアウトの設定があります。既定値はサービスやプランによって異なり変更されることもあるため、利用しているサービスの最新ドキュメントで確認してください。Nginx のログにエラーが一切ないのに利用者側でタイムアウトする場合は、外側を疑います。
クライアント側は短めにして接続を守る
上流側とは逆に、クライアント側のタイムアウトは短めにするのが一般的です。ヘッダーや本文を極端にゆっくり送り続けて接続を占有する低速攻撃への対策になるからです。
# http { } 内の例。環境に合わせて調整してください
client_header_timeout 15s;
client_body_timeout 30s;
send_timeout 30s;
keepalive_timeout 30s;
大きなファイルのアップロードで失敗する場合、原因は時間よりも client_max_body_size(既定 1m)の不足で 413 が返っていることが多いので、ステータスコードを見て切り分けてください。
変更の手順
- 設定ファイルをバックアップする
- 値を変更し、
sudo nginx -tで構文を確認する sudo systemctl reload nginxで反映する- 問題の操作を再現し、エラーログとアクセスログの時間を確認する
本番で試す前に、可能ならステージング環境で同じ処理を流して所要時間を測っておくと、必要な値を推測ではなく実測で決められます。
まとめ
- タイムアウトはクライアント側と上流側に分かれ、多くの項目は「全体の時間」ではなく「通信の間隔」の上限
- 504 はエラーログの
upstream timed outの文言から、接続・読み取りのどこで切れたかを読む - PHP 側の上限(
max_execution_time・request_terminate_timeout)は Nginx 以下にそろえる - 長い処理が必要な場所だけ伸ばし、重い処理は WP-CLI やバックグラウンド処理に移す
- CDN やロードバランサーのタイムアウトも確認する。クライアント側は短めにして接続を守る