この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。RFC 9110のHTTPステータス定義とnginx公式のproxy/FastCGIドキュメントを確認し、Web障害の最初の切り分けに使える形へ整理しています。検証ステータス:🧪 RFC・nginx公式情報確認済み・localhostで404確認済み・502/504の故意の再現は未実施
HTTP 404・502・504はどの層で起きる? ― Nginxとアプリの通り道から切り分ける
404、502、504 はすべてHTTPステータスですが、意味は同じではありません。NginxをリバースプロキシやFastCGIの入口にしているなら、ステータス番号だけで原因を決めつけず、ブラウザ → Nginx → upstreamのどこまで処理が進んだかを確認します。
まずHTTP上の意味を分ける
| Status | RFC上の意味を短く言うと | 最初に考えること |
|---|---|---|
| 404 Not Found | origin serverが対象リソースの現在の表現を見つけられない、または存在を明かしたくない | URL・routing・静的ファイル・アプリ側route |
| 502 Bad Gateway | gateway/proxyが上流から無効な応答を受け取った | upstream接続先・プロトコル・サービス・socket |
| 504 Gateway Timeout | gateway/proxyが上流から必要な応答を時間内に得られなかった | upstream遅延・timeout・詰まり |
大切なのは、502 = PHPの文法エラー、504 = Nginxが壊れた のように製品固有の原因へ直結させないことです。RFCが定義するのはHTTP応答の意味であり、実際の原因は構成によって変わります。
Nginxが間にいると通り道が増える
sequenceDiagram
participant B as Browser
participant N as Nginx
participant U as Upstream / PHP-FPM
B->>N: HTTP request
alt Nginx自身で処理
N-->>B: 2xx / 4xx など
else upstreamへ転送
N->>U: proxy_pass / fastcgi_pass
U-->>N: response または失敗
N-->>B: HTTP response
end
同じ 404 でも、Nginxの静的ファイル探索で返った404と、upstreamアプリが返した404では調べる場所が違います。したがって、「誰がそのレスポンスを作ったか」を確認するのが第一歩です。
404ならURLだけを見ない
404では次を順に確認します。
ブラウザが要求したpathは期待どおりか
Nginxの
locationがどこへ振り分けているか静的ファイルなら実ファイルとroot/aliasの関係は正しいか
upstreamアプリなら、そのrouteが本当に存在するか
なおRFC 9110では、サーバーが対象リソースの存在を明かしたくない場合にも404を使えるため、404だけから「物理ファイルがない」とは断定できません。
502ならupstreamとの境界を見る
Nginxの proxy_pass や fastcgi_pass は、Nginxの先に別のサーバーやFastCGIプロセスがいる構成です。502が出たら、たとえば次を確認します。
upstreamのホスト・ポート・Unix socketは正しいか
upstreamプロセスは起動しているか
Nginxから接続できる権限・経路になっているか
HTTPで話す相手なのかFastCGIで話す相手なのか
error logにupstream接続時の具体的な失敗が残っていないか
「上流が落ちている」だけでなく、接続先の取り違えやsocket権限でも境界は壊れます。
504なら「遅い場所」を探す
504はgateway/proxyが上流応答を時間内に受け取れなかった状態です。単純にtimeout値を大きくする前に、upstream側で処理が止まっていないか、外部APIやDB待ちが長くないかを確認します。
timeoutの延長だけで症状が見えなくなると、根本原因の発見が遅れることがあります。
すぐ試す:localhostで404を本当に出してみる
説明だけでなく、まず404を自分のPCで観察してみます。Nginxの設定は変更せず、Pythonの簡易HTTPサーバーを 127.0.0.1 だけで起動します。
ターミナル1:
python3 -m http.server 8000 --bind 127.0.0.1
ターミナル2:
curl -i http://127.0.0.1:8000/not-found
not-found というファイルは作っていないので、簡易HTTPサーバーから 404 File not found が返ります。これで「404はHTTPレスポンスとして実際に返ってくる」というところを安全に確認できます。
実サイトの切り分けでは、本文を大量に表示せずstatus・header・接続先だけ見たいことがあります。GitHubサンプルでは次のように使えます。
./check-http-status.sh https://example.com/
表示するのは主にresponse header、HTTP status、remote IP、total timeです。URLは自分の確認対象へ置き換えます。
502や504を学ぶために本番Nginxのupstream設定を故意に壊す必要はありません。まずstatusを観察し、502ならupstreamとの接続境界、504ならupstreamの処理時間やtimeoutへ進む方が安全です。
最初の切り分け
flowchart TD
A[HTTPエラーを確認] --> B{404?}
B -- はい --> C[URL / location / route / fileを確認]
B -- いいえ --> D{502?}
D -- はい --> E[upstream接続・socket・protocol・logを確認]
D -- いいえ --> F{504?}
F -- はい --> G[upstream処理時間・timeout・依存先を確認]
F -- いいえ --> H[別のstatus定義へ]
