- ネットワーク
504 Gateway Time-outの原因と直し方|502・503との違いと実例
結論
504 Gateway Time-outは、中継するサーバーが奥のサーバーの返事を待ちきれなかったという意味です。閲覧者側の原因は少なく、多くはサイト側の遅さかタイムアウト設定です。
この記事でわかること
- nginx で起こした504の画面とerror.log原文6種
- 500〜504の違い表と、Apacheで502になる実例
- nginx・ALB・CloudFrontなど6製品の既定の待ち時間
504 は、ブラウザとアプリのあいだにいる「中継役(ゲートウェイ)」が、決めた時間内に奥から返事をもらえなかったときに返すエラーです。
flowchart TD
B[ブラウザ] --> G[中継役のサーバー<br>nginx・ALB・CloudFront]
G --> A[奥のアプリ・API・DB]
A -->|時間内に返事| OK[200 などを表示]
A -.->|待ち時間を超えた| T[中継役が 504 を返す]
立場ごとに、最初にやることは次のとおりです。
| 立場・状況 | 最初にやること | 詳しくは |
|---|---|---|
| 閲覧者:ページを開いたら出た | 1〜数分おいて再読み込み | 閲覧者向けの対処 |
| 閲覧者:決済・送信の直後に出た | 再送信せず、完了メールや履歴を見る | 閲覧者向けの対処 |
| 運営者:自分のサイトで出た | error.log の upstream timed out を探す |
原因の切り分け |
| 開発者:重い処理だけ504になる | その処理の location だけ待ち時間を延ばす | proxy_read_timeoutで直す |
| 開発者:延ばしても直らない | アプリ側の遅さ・別の層の上限を調べる | 延ばしても直らないとき |
| AWSで出た | ALB・CloudFront・API Gateway の上限を見る | 既定のタイムアウト値 |
確認環境:Ubuntu 24.04・nginx 1.24.0(Ubuntu)・Apache 2.4.58(Ubuntu)・Python 3.11.15・curl 8.5.0・Chromium 141。わざと遅く返す上流サーバーを Python で作り、nginx と Apache の後ろに置いて 504・502・503 を実際に起こし、画面・error.log・かかった秒数を載せています。nginx・Apache の設定名と既定値は nginx.org と httpd.apache.org の公式ドキュメント、AWS の値は AWS の公式ドキュメント、Cloudflare の値は Cloudflare の公式ドキュメントで確かめました(確認日 2026年10月17日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「504 Gateway Time-outの原因と直し方|502・503との違いと実例」
504 Gateway Time-outとは
504 Gateway Timeout は、HTTP のステータスコード(サーバーが返す3桁の結果番号)の1つです。 HTTP の仕様(RFC 9110 の 15.6.5)で決められています。MDN は次のように説明しています。
サーバーがゲートウェイまたはプロキシとして動いているときに、リクエストを完了するために必要な応答を、上流のサーバーから時間内に受け取れなかったことを示す。
ここで出てくる言葉の意味は次のとおりです。
| 言葉 | 意味 | 例 |
|---|---|---|
| ゲートウェイ・プロキシ | ブラウザの代わりに奥のサーバーへ取り次ぐ中継役 | nginx・Apache・ALB・CloudFront・API Gateway |
| 上流(アップストリーム) | 中継役から見た奥のサーバー | Java・PHP・Python のアプリ、Lambda、別のAPI |
| タイムアウト | 決めた時間を過ぎたので待つのをやめること | nginx の既定は60秒 |
504 を返しているのは中継役で、遅いのはその奥です。 中継役のサーバー自体は動いています。止まっているか遅いのは、その奥のアプリ・データベース・外部API のどれかです。
「Gateway Time-out」と「Gateway Timeout」の表記
検索でよく見る 「504 Gateway Time-out」(ハイフンあり)は、nginx が返すエラーページの文言です。仕様上の名前は「Gateway Timeout」です。nginx 1.24.0 で実際に504を起こしたときの応答は次のとおりでした。
HTTP/1.1 504 Gateway Time-out
Server: nginx/1.24.0 (Ubuntu)
Date: Fri, 16 Oct 2026 17:11:05 GMT
Content-Type: text/html
Content-Length: 176
Connection: keep-alive
<html>
<head><title>504 Gateway Time-out</title></head>
<body>
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.24.0 (Ubuntu)</center>
</body>
</html>
画面の下に nginx と出ていれば、504 を返したのは nginx です。サイトによっては独自のエラーページに差し替えているため、「504 エラー」「ゲートウェイ タイムアウト」「サーバーからの応答がありません」など、表示は変わります。
500・501・502・503・504の違い
5つとも「サーバー側のエラー(5xx)」で、閲覧者のせいではない点は同じです。違いはどこが、何を見て諦めたかです。500・501 はアプリ(奥のサーバー)自身が返し、502・503・504 は主に中継役が返します。
| コード | 名前 | 何が起きたか | よくある原因 |
|---|---|---|---|
| 500 | Internal Server Error | アプリが想定外のエラーで処理を続けられなかった | 例外・バグ、設定ミス、DB のエラーを握りつぶさず返した |
| 501 | Not Implemented | サーバーがそのメソッドを知らない・持っていない | FOO など未知のメソッド、サーバーが実装していない機能 |
| 502 | Bad Gateway | 中継役に奥から不正な応答が来た、または接続を断られた | アプリが落ちている、ポート違い、途中で接続が切れた |
| 503 | Service Unavailable | サーバーが今は受け付けられない | メンテナンス中、過負荷、受け付け先が1台も無い |
| 504 | Gateway Timeout | 中継役に奥から時間内に返事が来なかった | 処理が遅い、DB待ち、外部APIが遅い、通信が遮断 |
MDN は 503 について、一時的な状態に使い、可能なら Retry-After ヘッダーで復旧の目安を返すとしています。
500と501はいつ返すか(開発者向け)
500 は「ほかに合う 5xx が無いときの、最後の受け皿」です。 MDN は 500 を「予期しない状態で要求を果たせなかった」ことを示す、サーバーの問題全般の受け皿(catch-all)と説明しています。メンテナンス中なら 503、中継先の待ち時間切れなら 504 のように、もっと合うコードがあればそちらを返し、どれにも当てはまらない想定外のエラーに 500 を使います。
501 は「そのメソッドを、どのURLに対しても受け付けられない」ときだけです。 MDN の説明は次のとおりです。
- サーバーがリクエストのメソッドを知らず、どのリソースにも対応できないときに返す。
GETとHEADはサーバーが必ず対応するメソッドなので、これらに 501 を返してはいけない。- メソッドは知っているが、そのURLでは意図して許していないなら
405 Method Not Allowedを返す。 - 501 は、キャッシュの指定が無ければ既定でキャッシュされうる。
| 状況 | 返すコード | 例 |
|---|---|---|
| 処理中に想定外の例外が起きた | 500 | 0 で割った、NULL を参照した |
| DB が止まっていて今は処理できない | 503(復旧の目安があれば Retry-After) |
メンテナンス・接続数の上限 |
FOO など、サーバーが知らないメソッドが来た |
501 | 打ち間違い・独自メソッド |
DELETE は知っているが、このURLでは許していない |
405(Allow ヘッダーで使えるメソッドを示す) |
読み取り専用の一覧に DELETE |
| 入力が間違っている | 400 番台(400・404・422 など) | 必須項目が空、存在しない ID |
入力の誤りに 500 を返さないことが、いちばん多い直しどころです。500 は「サーバー側の不具合」という意味なので、閲覧者や呼び出し側は直しようがなく、監視の 5xx も増えます。
手元で、Python の http.server で作った小さなアプリ(ポート 25191)と、その前に置いた nginx 1.24.0(ポート 25192。/static/ は nginx が直接ファイルを返す)に、curl でリクエストを送った結果です(Python 3.11.15)。
| 送ったもの | アプリに直接 | nginx 経由 |
|---|---|---|
GET /orders/1(中で例外を受け止めて 500 を返す) |
500 | 500(そのまま通る) |
GET /crash(例外を受け止めずに落ちる) |
応答なし(curl は 000) | 502 |
FOO /orders/1(未知のメソッド) |
501 | 501(アプリの応答が通る) |
PATCH /orders/1・DELETE /orders/1 |
501 | 501 |
FOO・POST・DELETE /static/a.txt(nginx が直接返す) |
― | 405 |
読み取れることは次の3つです。
- アプリが返した 500・501 は、nginx を通しても変わりません。 中継役は奥のコードをそのまま返します。
- アプリが応答を返さずに落ちると、500 ではなく 502 になります。 nginx の error.log には
upstream prematurely closed connection while reading response header from upstreamが出ていました。500 になるのは、アプリ(またはフレームワーク)がエラーを受け止めて 500 を返したときだけです。 http.serverは、処理を書いていないメソッドをすべて 501 にします。 応答はHTTP/1.0 501 Unsupported method ('FOO')でした。PATCH・DELETEのような一般的なメソッドにも 501 を返すため、MDN の使い分けでいえば、URL ごとに許していないだけなら 405 のほうが合います。nginx が直接返すファイルでは、POST・DELETE・FOOのどれも 405 でした。
nginx と Apache で実際に返ったコード
同じ「奥が遅い・落ちている」状況でも、中継役のソフトによって返るコードが違います。 同じ上流サーバーに対して、nginx 1.24.0 と Apache 2.4.58 で同じ状況を作った結果です。
| 起こした状況 | nginx 1.24.0 | Apache 2.4.58(mod_proxy_http) |
|---|---|---|
| 奥が返事をしない(読み取りの待ち時間切れ) | 504(5.006秒) | 502 Proxy Error(5.006秒) |
| 奥に接続できない(SYNを捨てる) | 504(3.004秒) | 503(3.003秒) |
| 奥のポートが閉じている(接続拒否) | 502(0.000秒) | 503(0.001秒) |
| 奥が返事をせずに接続を切った | 502(3.001秒) | ― |
Apache の後ろで処理が遅いときは、504 ではなく 502 が出ることがあります。 このときの Apache の error.log には AH01102: error reading status line from remote server と (70007)The timeout specified has expired が出ていました。コードだけで判断せず、error.log の文言と「何秒で返ったか」を合わせて見ると原因に近づけます。
関連記事「HTTPステータスコード 一覧|全コードの原因と対処・curl実例つき」で扱っています。
503とRetry-After:いつ返し、どう待つか
503 は「今は一時的に受け付けられない。少し待てば戻る」という意味で、Retry-After ヘッダーで「いつ戻るか」を伝えられます。 RFC 9110 の 15.6.4 は、503 を「一時的な過負荷か計画メンテナンスのため、今はリクエストを処理できない状態」とし、待つ時間の目安として Retry-After を送ってよい(MAY)としています。
500・504との違い
| コード | 誰が・どんなときに返すか | 待てば直るか |
|---|---|---|
| 500 | アプリが想定外のエラーに当たった | 分からない(不具合なら直るまで続く) |
| 503 | サーバーがわざと「今は受け付けない」と返す | 直る前提。Retry-After で目安を伝えられる |
| 504 | 中継役が、奥の返事を待ちきれなかった | 分からない(奥が遅い原因しだい) |
503 は、サーバー側が状況を分かったうえで返すコードです。 500・504 は「何かが起きた」結果として出るのに対し、503 はメンテナンスや過負荷を自分で判断して返します。そのため、復旧の目安を Retry-After で添えられます。
Retry-Afterの2つの書き方(RFC 9110)
RFC 9110 の 10.2.3 では、値は HTTP-date(日時)か、秒数(0以上の整数)のどちらかです。RFC に載っている例は次の2行で、2行目は「2分後」を意味します。
Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
Retry-After: 120
| 書き方 | 合う場面 | 注意点 |
|---|---|---|
秒数(120) |
過負荷・再起動など、終わる時刻が読めないとき | 応答を受け取った時点から数える |
HTTP-date(Sat, 17 Oct 2026 21:00:00 GMT) |
終了時刻が決まった計画メンテナンス | GMT で書く。サーバーの時計がずれると待ち時間もずれる |
RFC 9110 は、3xx(リダイレクト)に付けた場合は「リダイレクト先へ行くまでの最短の待ち時間」の意味になるとしています。
503を返す場面と、429との違い
| 状況 | 返すコード | Retry-After |
|---|---|---|
| 計画メンテナンス(DB の移行・リリース作業) | 503 | 終了時刻(HTTP-date)か秒数 |
| 過負荷で、一時的に新しい処理を断る | 503 | 秒数(短め) |
| 特定の利用者が短時間に送りすぎた(流量制限) | 429 Too Many Requests | その利用者が次に送れるまでの秒数 |
| 想定外の例外 | 500 | 付けない |
429 は「あなたが送りすぎ」、503 は「サーバー全体が今は無理」です。 429 は RFC 6585 の 4 で決められた 4xx(呼び出し側の問題)のコードで、MDN は 429 にも Retry-After を付けて待つ時間を示せるとしています。
nginx 1.24 でメンテナンス中の503を返す
nginx 1.24.0 で、return 503 と add_header Retry-After 120 を書いて curl で呼びました。always を付けないと、503 の応答に Retry-After が付きませんでした。
# always なし
location / {
add_header Retry-After 120;
return 503;
}
# always あり
location / {
add_header Retry-After 120 always;
return 503;
}
always なしの応答です。Retry-After の行がありません。
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.24.0 (Ubuntu)
Date: Sat, 17 Oct 2026 02:53:31 GMT
Content-Type: text/html
Content-Length: 206
Connection: keep-alive
always ありの応答です。最後に Retry-After: 120 が付きました。nginx の 503 の文言は「Service Temporarily Unavailable」です。
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.24.0 (Ubuntu)
Date: Sat, 17 Oct 2026 02:53:31 GMT
Content-Type: text/html
Content-Length: 206
Connection: keep-alive
Retry-After: 120
<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body>
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.24.0 (Ubuntu)</center>
</body>
</html>
nginx のドキュメントでは、add_header が付くのは 200・201・204・206・301・302・303・304・307・308 の応答だけで、always(1.7.5 から)を付けると応答コードに関係なく付きます。
503 に Retry-After を付けたい
add_header Retry-After 120;add_header Retry-After 120 always;nginx 1.24.0 の curl -i で確認。エラー用ページに付けるヘッダーも同じく always が要る
メンテナンス用ページを出し、特定のIPだけ通す
本番でメンテナンスに入るときの設定です。error_page 503 で独自のページを 503 のまま返し、作業者の IP だけはふだんどおり通します。
geo $maintenance {
default 1;
127.0.0.2 0; # 作業者の IP(本番では社内の固定 IP など)
}
server {
listen 80;
root /var/www/html;
error_page 503 /maintenance.html;
location = /maintenance.html {
internal; # 直接開かせない
add_header Retry-After 120 always;
add_header Cache-Control "no-store" always;
}
location / {
if ($maintenance) {
return 503;
}
try_files $uri $uri/ =404;
}
}
ふつうの IP(127.0.0.1)から呼ぶと、ステータスは 503 のまま、本文はメンテナンス用ページになりました。
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.24.0 (Ubuntu)
Date: Sat, 17 Oct 2026 02:53:36 GMT
Content-Type: text/html
Content-Length: 220
Connection: keep-alive
ETag: "6ad2e324-dc"
Retry-After: 120
Cache-Control: no-store
<!doctype html>
<html lang="ja"><head><meta charset="utf-8"><title>メンテナンス中</title></head>
<body><h1>ただいまメンテナンス中です</h1><p>10月18日 6:00 に再開予定です。</p></body></html>
作業者の IP(curl --interface 127.0.0.2)からは、ふだんのページが 200 で返りました。
HTTP/1.1 200 OK
Server: nginx/1.24.0 (Ubuntu)
Date: Sat, 17 Oct 2026 02:53:36 GMT
Content-Type: text/html
Content-Length: 7
…
app ok
| 確かめたこと | 結果 |
|---|---|
ふつうの IP で / |
503・メンテナンス用ページ・Retry-After: 120 |
作業者の IP で / |
200・ふだんのページ |
/maintenance.html を直接開く |
404(internal のため) |
メンテナンス用ページを 200 で返さないことが要点です。200 で返すと、メンテナンスの文言がそのURLの中身として扱われることがあります。Cache-Control: no-store は、CDN やブラウザがメンテナンス用ページを覚えて、終わった後も出し続けることを防ぎます。
受け取る側はRetry-Afterをどう扱うか
Retry-After を読んで待つかどうかは、受け取る側しだいです。 実際に試した結果と、ドキュメントの記述をまとめます。
| 受け取る側 | Retry-After の扱い | 根拠 |
|---|---|---|
| ブラウザ | 503 の画面を表示するだけ。自動で再読み込みしない | Chromium 141 で12秒待ってもリクエストは1回 |
curl --retry |
書かれた秒数・日時だけ待って再試行する | curl 8.5.0 で計測(下の表) |
| Googlebot | 503・429 の Retry-After を再クロールの目安にする | Google 検索セントラル |
| 自作のクライアント | 自分で読んで待つ処理を書く | ― |
ブラウザの結果は、Retry-After: 3 を付けた 503 のページを Chromium 141(ヘッドレス)で開き、12秒待ったときのものです。nginx のアクセスログに残ったブラウザからのリクエストは1回だけで、画面は 503 のページのままでした。
curl のマニュアル(curl --manual)には、--retry は一時的なエラー(タイムアウト、HTTP の 408・429・500・502・503・504)で再試行し、Retry-After: があればそれに従って次の再試行の時刻を決める(7.66.0 から)とあります。curl 8.5.0 で、待った秒数を測りました。
curl -o out.html -w 'status=%{http_code}\n' --retry 2 http://127.0.0.1:25153/
Warning: Problem : HTTP error. Will retry in 3 seconds. 2 retries left.
Warning: Problem : HTTP error. Will retry in 3 seconds. 1 retries left.
status=503
| 返したヘッダー | curl のオプション | かかった時間 |
|---|---|---|
Retry-After: 3 |
--retry 2 |
6.01秒(3秒×2回) |
| なし | --retry 2 |
3.14秒(1秒→2秒と倍に増える) |
| なし | --retry 3 |
7.02秒(1秒→2秒→4秒) |
Retry-After: 3 |
--retry 2 --retry-delay 1 |
6.06秒(Retry-After が優先) |
| 8秒後の日時(HTTP-date) | --retry 1 |
8.04秒(「Will retry in 8 seconds」) |
Retry-After: 120 |
--retry 1 --retry-max-time 10 |
0.03秒(再試行せずに終了) |
最後の行では、待つと上限を超えるため、curl は再試行せずに次の警告を出して終わりました。
Warning: The Retry-After: time would make this command line exceed the maximum
Warning: allowed time for retries.
-o /dev/null と --retry を一緒に使うと、curl 8.5.0 では再試行の前に curl: Failed to truncate file で止まりました(終了コード 23)。 再試行のときに出力先のファイルを空にし直すためです。-o out.html のように、ふつうのファイルに書き出すと最後まで再試行しました。
503を長く続けたときの検索への影響
Google 検索セントラルの「Google のクロール頻度を下げる」のページ(2026年10月6日更新)には、次のことが書かれています。
- 短い時間(数時間、または1〜2日)なら、200 の代わりに 500・503・429 を返してクロールを減らせる。エラーが減れば、クロールの頻度は自動で戻る。
- 503・429 を返すときは、
Retry-Afterで Google のクローラーがいつ再試行できるかを、秒数か UTC の日時で示せる。 - 1〜2日より長く続けることは勧めない。同じ URL で何日も続くと、インデックスから外れることがある。
長いメンテナンスでは、Retry-After に終わる時刻を書き、作業を1〜2日以内に収めるのが目安です。それより長く止めるなら、サイト全体を 503 にせず、止める機能のURLだけを 503 にする分け方もあります。
アプリ(Spring Boot)の中で、業務の例外を 503 と Retry-After に変えて返す書き方は、関連記事「Spring Boot 例外処理|ステータスコードの返し分けと503実例」で扱っています。
504エラーが出たときの対処(閲覧者向け)
504 の原因はほとんどがサイト側にあり、閲覧者ができることは限られます。それでも、次の順に試すと切り分けられます。
1〜数分おいて、ページを再読み込みする
アクセスが集中した一時的な遅れなら、時間をおくと開けます。何度も連打すると、サイトの負荷を上げることになります。
決済・申し込み・投稿の直後なら、再送信しない
504 が出ても、サイトの奥では処理が最後まで終わっていることがあります(下の「延ばしても直らないとき」で実際に確かめています)。完了メール・注文履歴・投稿一覧で結果を見てから、やり直すか決めます。
ほかのサイトが開けるかを見る
ほかのサイトも開けないなら、自分の回線・Wi-Fi・社内ネットワークの問題です。そのサイトだけなら、サイト側の問題の可能性が高くなります。
VPN・プロキシを切る、別の回線で開く
MDN は、ほかの人は使えているのに自分だけ504になる場合、VPN や独自のネットワーク設定、ファイアウォール・プロキシ・DNS の設定が原因のこともあるとしています。スマホのモバイル回線で開けるかを試すと切り分けられます。
続くなら、サイトの運営者に伝える
開いたURL・時刻・表示された文言(「504 Gateway Time-out」と下の「nginx」など)を伝えると、運営者がログから探しやすくなります。
504の原因の切り分け(運営者・開発者向け)
運営者・開発者が最初に見るのは、中継役のエラーログと504 が返るまでの秒数です。
まず見る2つ
中継役の error.log(nginx なら upstream timed out の行)
504 が返るまでの秒数(curl の time_total やアクセスログ)
そこから分かること
接続の段階か、返事待ちの段階か、途中の送信中か
どの層(nginx・ALB・CloudFront・API Gateway)の上限に当たったか
504 が返るまでの秒数で、どの層かを当てる
504 が返るまでの秒数は、どこかの待ち時間の上限とほぼ一致します。 既定値のままなら、秒数からどの層が諦めたかの見当がつきます(値は後の「既定のタイムアウト値」の表のとおり、公式ドキュメントで確かめたもの)。
| 504までの秒数 | 当たっている可能性がある上限 | 確かめる設定 |
|---|---|---|
| 約60秒 | nginx・Apache・ALB の既定 | proxy_read_timeout・Timeout・アイドルタイムアウト |
| 約30秒 | CloudFront の応答タイムアウト、API Gateway の HTTP API | オリジンの Response timeout、統合タイムアウト |
| 約29秒 | API Gateway の REST API | 統合タイムアウト |
| 約10秒 | ALB のターゲットへの接続 | セキュリティグループ・ネットワークACL |
| 上限の2倍・3倍 | 中継役が別のサーバーで再試行した | nginx の proxy_next_upstream |
| すぐ返る | 奥のサーバー自身が504を返している | 奥のサーバーのログ |
curl で秒数とコードを同時に見るコマンドです。
curl -s -o /dev/null -w 'status=%{http_code} time=%{time_total}s\n' 'https://example.com/slow-page'
nginx 1.24.0 の既定のまま、65秒かかる処理を呼んだときの出力です。60.06秒で504 になり、既定の proxy_read_timeout 60s と一致しました。
status=504 time=60.061462s
nginx のアクセスログに上流の時間を出す
nginx の標準のアクセスログには上流の時間が出ません。log_format に $upstream_response_time(上流の応答にかかった秒数)などを足すと、どの上流で何秒かかったかが1行で分かります。
http {
log_format timing '$remote_addr [$time_local] "$request" $status '
'rt=$request_time uct=$upstream_connect_time '
'urt=$upstream_response_time us=$upstream_status ua=$upstream_addr';
access_log /var/log/nginx/timing.log timing;
}
実際に出た行です。3行目は接続を断られた502、4行目は上流2台に順に問い合わせて、どちらも5秒で諦めた504です。
127.0.0.1 [17/Oct/2026:02:14:52 +0900] "GET /short/slow?sec=1 HTTP/1.1" 200 rt=1.001 uct=0.001 urt=1.001 us=200 ua=127.0.0.1:25101
127.0.0.1 [17/Oct/2026:02:14:57 +0900] "GET /short/slow?sec=8 HTTP/1.1" 504 rt=5.005 uct=0.000 urt=5.005 us=504 ua=127.0.0.1:25101
127.0.0.1 [17/Oct/2026:02:14:57 +0900] "GET /down/ HTTP/1.1" 502 rt=0.000 uct=- urt=0.000 us=502 ua=127.0.0.1:25199
127.0.0.1 [17/Oct/2026:02:15:18 +0900] "GET /two/slow?sec=8 HTTP/1.1" 504 rt=10.010 uct=0.000, 0.000 urt=5.005, 5.006 us=504, 504 ua=127.0.0.1:25101, 127.0.0.1:25102
すでにあるアクセスログから、502・503・504 の件数を数えるときは次のようにします(標準の combined 形式では9列目がステータス)。
awk '$9 ~ /^50[234]$/ {print $9}' /var/log/nginx/access.log | sort | uniq -c
3 502
5 504
nginxで504を再現する
原因を確かめるには、わざと504を起こして、ログの文言を自分の目で見ておくのが近道です。ここでは、指定した秒数だけ待ってから返す上流サーバーを Python で作り、nginx の後ろに置きました。
わざと遅く返す上流サーバー(Python)
# upstream.py 使い方: python3 upstream.py 25101
import socket, sys, time
from http.server import ThreadingHTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs
class H(BaseHTTPRequestHandler):
protocol_version = "HTTP/1.1"
def do_GET(self):
u = urlparse(self.path)
q = {k: v[0] for k, v in parse_qs(u.query).items()}
if u.path == "/slow": # 何も返さずに sec 秒待ってから返す
sec = float(q.get("sec", "0"))
time.sleep(sec)
body = f"done after {sec:g}s\n".encode()
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
elif u.path == "/drip": # ヘッダーを先に返し、every 秒ごとに1行ずつ送る
n, every = int(q.get("n", "5")), float(q.get("every", "3"))
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Transfer-Encoding", "chunked")
self.end_headers()
for i in range(n):
time.sleep(every)
line = f"line {i+1}\n".encode()
self.wfile.write(b"%x\r\n%s\r\n" % (len(line), line))
self.wfile.flush()
self.wfile.write(b"0\r\n\r\n")
elif u.path == "/die": # sec 秒後に、何も返さず接続を切る
time.sleep(float(q.get("sec", "3")))
self.close_connection = True
self.connection.shutdown(socket.SHUT_RDWR)
else:
self.send_response(200)
self.send_header("Content-Length", "3")
self.end_headers()
self.wfile.write(b"ok\n")
do_POST = do_GET
ThreadingHTTPServer(("127.0.0.1", int(sys.argv[1])), H).serve_forever()
nginx の設定
upstream app { server 127.0.0.1:25101; }
server {
listen 127.0.0.1:25100;
# 既定のまま(proxy_read_timeout 60s)
location / {
proxy_pass http://app;
}
# 試験用に読み取りの待ち時間を5秒にした場所
location /short/ {
proxy_pass http://app/;
proxy_read_timeout 5s;
}
}
結果:5秒で504、3秒なら200
curl -s -o /dev/null -w 'status=%{http_code} time=%{time_total}s\n' 'http://127.0.0.1:25100/short/slow?sec=8'
curl -s -w 'status=%{http_code} time=%{time_total}s\n' 'http://127.0.0.1:25100/short/slow?sec=3'
status=504 time=5.006084s
done after 3s
status=200 time=3.001488s
このとき nginx の error.log に出た行です。
2026/10/17 02:11:21 [error] 8535#8535: *3 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 127.0.0.1, server: , request: "GET /short/slow?sec=8 HTTP/1.1", upstream: "http://127.0.0.1:25101/slow?sec=8", host: "127.0.0.1:25100"
while reading response header from upstream は、「奥にはつながったが、返事の最初の部分(ヘッダー)が待ち時間内に来なかった」という意味です。 504 でいちばん多い形で、upstream: のところに、どの上流の何のURLで待たされたかが出ます。
error.logのエラー原文と原因の一覧
nginx 1.24.0 で状況を作って出た error.log の原文です。while の後ろを見ると、どの段階で止まったかが分かります。
| error.log の原文(要部) | 返ったコード | 止まった段階 | 主な直し方 |
|---|---|---|---|
upstream timed out (110: Connection timed out) while reading response header from upstream |
504 | 返事の最初が来ない | 処理を速くする、その場所だけ proxy_read_timeout を延ばす |
upstream timed out (110: Connection timed out) while connecting to upstream |
504 | 接続できない | ファイアウォール・セキュリティグループ・宛先IP を確かめる |
upstream timed out (110: Connection timed out) while reading upstream |
200(途中で切れる) | 返事の途中で止まった | 少しずつ返す処理の間隔を短くする、待ち時間を延ばす |
connect() failed (111: Connection refused) while connecting to upstream |
502 | 接続を断られた | アプリの起動・ポート番号を確かめる |
upstream prematurely closed connection while reading response header from upstream |
502 | 返事の前に切られた | アプリ側のタイムアウト(ワーカーの制限時間など)を確かめる |
no live upstreams while connecting to upstream |
502 | 上流が全部「一時停止」扱い | 直前の504の原因を直す(下の節を参照) |
3行目の while reading upstream は見落としやすい形です。ヘッダーがすでに返ったあとで止まったため、ステータスは200のまま、本文が途中で切れます。 curl では次のように出ました。
curl: (18) transfer closed with outstanding read data remaining
status=200 time=5.005427s
接続の段階の504(2行目)は、宛先が SYN(接続の申し込み)を捨てる状態を iptables で作り、proxy_connect_timeout 3s で起こしました。3.004秒で504が返りました。
関連記事「Nginxリバースプロキシ設定|proxy_passの書き方と502/504対処」で扱っています。
proxy_read_timeoutで504を直す
処理が遅いことが分かっていて、すぐには速くできないときは、その処理のURLだけ待ち時間を延ばします。サーバー全体(http や server)で延ばすと、本当に固まった処理でも長く待ち続け、接続が詰まりやすくなります。
nginx のタイムアウトの設定名と既定値
nginx.org のドキュメントで確かめた値です。どれも http・server・location に書けます。
| 設定名 | 既定値 | 何の待ち時間か |
|---|---|---|
proxy_read_timeout |
60s | 上流からの2回の読み取りのあいだの待ち時間 |
proxy_connect_timeout |
60s | 上流への接続を確立するまで(通常75秒を超えられない) |
proxy_send_timeout |
60s | 上流へ2回の書き込みのあいだの待ち時間 |
fastcgi_read_timeout |
60s | PHP-FPM など FastCGI からの読み取りのあいだ |
重い処理の location だけ延ばす
# 帳票の作成だけ120秒待つ
location /report/ {
proxy_pass http://app/;
proxy_read_timeout 120s;
}
設定を変えたら、文法を確かめてから読み込み直します。
sudo nginx -t && sudo systemctl reload nginx
既定のままでは60.06秒で504になった65秒の処理が、この location では最後まで返りました。
done after 65s
status=200 time=65.002562s
「全体の時間」ではなく「読み取りのあいだ」の時間
ドキュメントには、proxy_read_timeout は応答全体の時間ではなく、2回の読み取りのあいだにだけかかると書かれています。待ち時間5秒のまま、4秒ごとに1行ずつ返す処理を呼ぶと、合計20秒かかっても504になりませんでした。
line 1
line 2
line 3
line 4
line 5
status=200 time=20.002488s
長い処理の途中経過を少しずつ返す作り(ストリーミング)なら、待ち時間を延ばさなくても切れません。一方で、間隔が7秒になると5秒で切れ、前の節の「200のまま途中で切れる」形になりました。
関連記事「タイムアウト設計の値の決め方|接続・読み取りの違いと多段の計算例」で扱っています。
504がタイムアウトを延ばしても直らないとき
待ち時間を延ばす前と後に、次の点を確かめます。実際に動かして分かった、見落としやすい点です。
504 が出ても、奥の処理は止まっていない
nginx が 02:11:05 に504を返した65秒の処理は、上流のログでは 02:11:10 に 200 で終わっていました。 POST でも同じで、504 の3秒後に上流の処理が完了していました。
[upstream] 02:11:10 "GET /slow?sec=65 HTTP/1.0" 200 -
[upstream] 02:13:52 "POST /slow?sec=8 HTTP/1.0" 200 -
中継役が待つのをやめても、奥のアプリは処理を続けます。 注文・送金・メール送信のような処理で504が出たあと、利用者が送り直すと二重に実行されます。同じリクエストを2回受けても1回分しか実行しない作り(冪等にする)か、時間のかかる処理を受け付けだけ先に返して後で処理する作り(非同期化)にすると防げます。
上流が複数台だと、待ち時間が台数分に伸びる
nginx の proxy_next_upstream の既定は error timeout で、タイムアウトしたら次のサーバーに同じリクエストを送ります。上流2台・待ち時間5秒で試すと、GET は2台に順に送られ、10.01秒で504 になりました。
ドキュメントには、POST・LOCK・PATCH はすでに上流に送ったあとなら次のサーバーへ送らない(1.9.13 から)とあります。実際に POST は1台だけに送られ、5.00秒で504になりました。
504 の直後に 502 no live upstreams が出る
上の GET で2台ともタイムアウトした直後、別の POST を送ると、待たずに 502 が返り、error.log には次の行が出ました。
[warn] ... upstream server temporarily disabled while reading response header from upstream, ... upstream: "http://127.0.0.1:25101/slow?sec=8"
[error] ... no live upstreams while connecting to upstream, ... request: "POST /two/slow?sec=8 HTTP/1.1", upstream: "http://app2/slow?sec=8"
タイムアウトした上流は、しばらく「使えない」扱いになります。11秒おいて送り直すと、また上流に送られて504(5.00秒)になりました。502 と 504 が交互に出ているときは、根本は504の原因(遅さ)です。
奥のアプリにも、別の待ち時間がある
中継役だけ延ばしても、その奥にも上限があります。アプリのサーバーが処理の途中で接続を切ると、nginx 側は504ではなく 502(upstream prematurely closed connection) になります(上の一覧の5行目)。
| 層 | 待ち時間の例 | 超えたときの見え方 |
|---|---|---|
| CDN | CloudFront の応答タイムアウト 30秒 | CloudFront が504 |
| ロードバランサー | ALB のアイドルタイムアウト 60秒 | ALB が504 |
| Webサーバー | nginx の proxy_read_timeout 60秒 |
nginx が504 |
| アプリのサーバー | ワーカーの制限時間、PHP の実行時間の上限など | nginx が502 |
| DB・外部API | クエリの上限、HTTPクライアントのタイムアウト | アプリが500などを返す |
外側の層ほど待ち時間を長く、内側ほど短くすると、内側のエラーが外側まで届きます。 逆だと、内側は処理を続けているのに外側が先に504を返し、原因がログに残りにくくなります。
関連記事「Pythonのrequestsの使い方|タイムアウト・エラー処理・再試行まで」で扱っています。
Apache・AWS ALB・CloudFront・API Gatewayの既定のタイムアウト値
2026年10月17日時点の公式ドキュメントで確かめた値です。
| 製品 | 既定の待ち時間 | 設定名・上限 | 超えたときのコード |
|---|---|---|---|
| nginx | 読み取り60秒・接続60秒 | proxy_read_timeout・proxy_connect_timeout |
504 |
| Apache httpd 2.4 | 60秒 | Timeout。ProxyTimeout が無ければ Timeout を使う |
502・503(実測) |
| AWS ALB | アイドル60秒・接続10秒 | idle_timeout.timeout_seconds(1〜4000秒) |
504 |
| Amazon CloudFront | 応答30秒・接続10秒×3回 | Response timeout(1〜120秒、引き上げ申請可) | 504 |
| API Gateway(REST) | 最大29秒 | 統合タイムアウト(50ミリ秒〜29秒、リージョン・プライベートは申請で延長可) | 504 |
| API Gateway(HTTP API) | 最大30秒 | 統合タイムアウト(延長不可) | ― |
表を補う点です。
- Apache:Ubuntu 24.04 の Apache パッケージに入っている
/etc/apache2/apache2.confはTimeout 300になっていました。ドキュメントの既定(60秒)と、ディストリビューションの設定ファイルの値が違うことがあります。 - ALB:AWS のドキュメントは、504 の原因として、接続タイムアウト(10秒)までに接続できない、アイドルタイムアウトまでにターゲットが応答しない、サブネットのネットワークACLが一時ポート(1024〜65535)を通さない、
Content-Lengthが本文より大きい、などを挙げています。 - CloudFront:オリジン(元のサーバー)のファイアウォールやセキュリティグループが CloudFront を通さない場合も504になる、とドキュメントにあります。既定の接続10秒×3回で、別のオリジンへ切り替えるかエラーを返すまでに最大30秒かかります。
- API Gateway(REST):延長はできますが、ドキュメントには、リージョン単位のスロットリング(流量制限)の上限が下がる場合があると書かれています。統合のタイムアウトは
INTEGRATION_TIMEOUT(既定のステータス504)のゲートウェイレスポンスになります。 - Cloudflare:上流が時間内に応答しないときは 504 ではなく 524 を返します。ドキュメントでは Proxy Read Timeout の既定は125秒です。
関連記事「ALBをAWS CLIで作成|ターゲットグループ・リスナー・ルール設定」で扱っています。
504エラーはSEOに影響するか
Google 検索セントラルのドキュメントでは、5xx のエラーが返ると Google のクローラーは一時的にクロールを遅くし、2xx に戻ると徐々に元に戻すとしています。長く続くと、すでにインデックスされたURLも、最終的にはインデックスから外れると書かれています。数分の504で順位が落ちることを心配するより、504が続く状態を早く見つけて直す仕組み(監視と、上の切り分け)を持つほうが効果があります。
よくある質問
Q. 504 Gateway Time-outとは何ですか? A. 中継役のサーバー(nginx・ロードバランサー・CDN など)が、奥のサーバーの返事を決めた時間内にもらえなかったことを示すエラーです。詳しくは「504 Gateway Time-outとは」の節にあります。
Q. 504 エラーは自分のパソコンやスマホのせいですか? A. 多くはサイト側の問題です。ほかのサイトも開けないとき、VPN やプロキシを使っているときは、自分の側の可能性があります。「閲覧者向けの対処」の手順で切り分けられます。
Q. http 504 と 502 の違いは何ですか? A. 504 は「返事が時間内に来なかった」、502 は「不正な応答が来た・接続を断られた」です。ただし Apache の mod_proxy_http では、読み取りの待ち時間切れでも502が返りました。「500・501・502・503・504の違い」に表があります。
Q. 500 Internal Server Error と 504 の違いは何ですか? A. 500 はアプリ自身が「想定外のエラーで処理できなかった」と返すコード、504 は中継役が「奥から時間内に返事が来なかった」と返すコードです。アプリが返した 500 は nginx を通してもそのまま 500 で届きます。「500と501はいつ返すか」に実例があります。
Q. 501 Not Implemented はどんなときに使いますか? A. サーバーがリクエストのメソッドを知らず、どの URL でも対応できないときです。メソッドは知っているがその URL では許していないなら 405 を返します。GET と HEAD に 501 は返しません。
Q. 503 Service Unavailable と Retry-After はどう使いますか?
A. 503 はメンテナンスや過負荷で「今は一時的に受け付けない」ときに返し、Retry-After に再開までの秒数か日時を書きます。nginx では add_header Retry-After 120 always; のように always を付けないと 503 に付きません。ブラウザは自動で再読み込みせず、curl の --retry は Retry-After の秒数だけ待ちました。「503とRetry-After:いつ返し、どう待つか」に実例があります。
Q. gateway timeout はどれくらい待つと出ますか? A. 設定によります。nginx・Apache・ALB の既定は60秒、CloudFront は30秒、API Gateway の REST API は最大29秒です。504が返るまでの秒数から、どの層かの見当がつきます。
Q. 504エラーの原因は何ですか?
A. 奥の処理が遅い(重いSQL・外部APIの待ち・負荷)、接続が遮断されている(ファイアウォール・セキュリティグループ)、待ち時間の設定が短い、のどれかが多いです。nginx なら error.log の upstream timed out ... while の後ろで段階が分かります。
Q. 504 gateway timeout を nginx で直すには?
A. 遅い処理の location だけ proxy_read_timeout を延ばし、nginx -t のあと reload します。延ばす前に、処理そのものを速くできないか、奥のアプリの待ち時間が先に切れないかも確かめます。
まとめ
- 504 は、中継役が奥の返事を待ちきれなかったときのエラー。返しているのは中継役で、遅いのはその奥。
- 閲覧者は、時間をおいて再読み込み。決済・送信の直後なら再送信せず、結果を先に確かめる。
- 運営者は、error.log の
upstream timed out ... while ...と、504までの秒数で段階と層を特定する。 - nginx は遅い処理の location だけ
proxy_read_timeoutを延ばす。待ち時間は「読み取りのあいだ」の時間。 - 504 のあとも奥の処理は続く。二重実行を防ぐ作り(冪等・非同期化)が根本の対策になる。
- Apache の mod_proxy_http では、読み取りの待ち時間切れで502、接続の待ち時間切れで503が返った。
参考・出典
確認日はいずれも 2026年10月17日です。
- MDN「500 Internal Server Error」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/500
- MDN「501 Not Implemented」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/501
- MDN「504 Gateway Timeout」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/504
- MDN「502 Bad Gateway」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/502
- MDN「503 Service Unavailable」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/503
- MDN「Retry-After」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Retry-After
- MDN「429 Too Many Requests」:https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/429
- RFC 9110 HTTP Semantics(10.2.3 Retry-After・15.6 Server Error 5xx):https://www.rfc-editor.org/rfc/rfc9110
- RFC 6585 Additional HTTP Status Codes(4. 429 Too Many Requests):https://www.rfc-editor.org/rfc/rfc6585
- nginx「Module ngx_http_headers_module」(add_header):https://nginx.org/en/docs/http/ngx_http_headers_module.html
- curl「curl.1 the man page」(--retry):https://curl.se/docs/manpage.html
- nginx「Module ngx_http_proxy_module」:https://nginx.org/en/docs/http/ngx_http_proxy_module.html
- nginx「Module ngx_http_fastcgi_module」:https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html
- Apache HTTP Server 2.4「core - Timeout」:https://httpd.apache.org/docs/2.4/mod/core.html#timeout
- Apache HTTP Server 2.4「mod_proxy - ProxyTimeout」:https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxytimeout
- AWS「Edit attributes for your Application Load Balancer」:https://docs.aws.amazon.com/elasticloadbalancing/latest/application/edit-load-balancer-attributes.html
- AWS「Troubleshoot your Application Load Balancers」:https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-troubleshooting.html
- AWS「Origin settings(CloudFront)」:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesOrigin.html
- AWS「Quotas(CloudFront)」:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html
- AWS「HTTP 504 status code (Gateway Timeout)(CloudFront)」:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/http-504-gateway-timeout.html
- AWS「Amazon API Gateway quotas」:https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-execution-service-limits-table.html
- AWS「Quotas for configuring and running an HTTP API」:https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-quotas.html
- AWS「Gateway response types for API Gateway」:https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html
- Cloudflare「Error 524」:https://developers.cloudflare.com/support/troubleshooting/http-status-codes/cloudflare-5xx-errors/error-524/
- Google 検索セントラル「HTTP status codes, network and DNS errors」:https://developers.google.com/crawling/docs/troubleshooting/http-status-codes
- Google 検索セントラル「Google のクロール頻度を下げる」:https://developers.google.com/crawling/docs/crawlers-fetchers/reduce-crawl-rate
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「504 Gateway Time-outの原因と直し方|502・503との違いと実例」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。