エラーの内容
/var/log/nginx/error.log に記録されたエラーの全文:
2024/01/15 10:23:45 [error] 12345#0: *1 upstream sent too big header while reading response header from upstream,
client: 10.0.0.1, server: example.com,
request: "GET /api/dashboard HTTP/1.1",
upstream: "http://127.0.0.1:3000/api/dashboard",
host: "example.com"
ブラウザには真っ白な 502 Bad Gateway が表示されます。バックエンドは正常に動作しているのに、Nginx がレスポンスヘッダーの処理で詰まっているのが原因です。
根本原因
Nginx はアップストリームからのレスポンスヘッダーを読み取るために固定サイズのバッファを確保します。デフォルトは 4KB(ビルドによっては 8KB)です。アップストリームがこのバッファを超えるサイズのヘッダーを送信すると、Nginx はこのエラーを出してレスポンスを破棄します。
4KB は十分に思えますが、実際の認証フローを動かすとすぐに限界が来ます。よくある原因は以下のとおりです:
- 大きなセッション Cookie — PHP セッション、Rails の暗号化 Cookie、Cookie に保存した JWT トークンは、簡単に 4〜8KB に達します。
- 大量の
Set-Cookieヘッダー — OAuth フロー、マルチドメイン認証、フィーチャーフラグシステムは Cookie を次々と積み重ねます。 - フレームワークの冗長なヘッダー — Spring Boot や Django REST アプリは、カスタムレスポンスヘッダーを驚くほど多く追加することがあります。
- CDN や認証ミドルウェアによるヘッダー注入 — Cloudflare、Keycloak、社内 API ゲートウェイなどが、レスポンスが Nginx に到達する前にヘッダーサイズを膨らませることがあります。
関連する Nginx ディレクティブのデフォルト値は 2005 年当時には妥当でした。しかし現代の Web アプリはそれを日常的に超えてしまいます。
修正方法
オプション 1:プロキシバッファサイズを増やす(最も一般的な対処法)
Nginx のサイト設定ファイルを編集します。通常は /etc/nginx/sites-available/your-site、または /etc/nginx/nginx.conf 内の該当する server ブロックです:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
# 修正:ヘッダーバッファサイズを増やす
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
}
}
各ディレクティブの意味:
proxy_buffer_size— アップストリームレスポンスの最初の部分(ステータスライン+ヘッダー)用のバッファ。このエラーに対して最も重要な設定です。proxy_buffers— レスポンスボディ全体用のバッファの個数×サイズ。proxy_busy_buffers_size— クライアントへの送信中に使用できる最大サイズ。proxy_buffersの合計サイズを超えてはいけません。
オプション 2:http ブロックでグローバルに適用する
同じ問題を抱えたアップストリームサービスが複数ある場合は、/etc/nginx/nginx.conf の http ブロックで一度だけ設定します:
http {
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
include /etc/nginx/sites-enabled/*;
}
location ブロックで個別に設定した値はこのグローバル設定を上書きするため、明示的な値を持つ設定が壊れることはありません。
オプション 3:FastCGI 向け設定(PHP-FPM)
FastCGI 経由で PHP を動かしている場合は、ディレクティブ名が異なります:
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
}
修正を適用する
# まず設定の構文を確認する
nginx -t
# ダウンタイムなしでリロードする
systemctl reload nginx
修正の確認
エラーが発生していたエンドポイントにアクセスしながら、エラーログを監視します:
# エラーログをリアルタイムで監視する
tail -f /var/log/nginx/error.log
# エラーが発生していたエンドポイントにアクセスする
curl -v https://example.com/api/dashboard 2>&1 | grep -E '< HTTP|< Set-Cookie|< X-'
Cookie の肥大化が最も一般的な原因です。実際のヘッダーサイズを次のコマンドで計測できます:
curl -sI https://example.com/api/dashboard | awk '{total += length($0)} END {print "Total header size: " total " bytes"}'
4096 バイト前後またはそれ以上であれば、根本原因が確認できます。
詳しく調べる:大きなヘッダーの発生源を特定する
バッファサイズを増やすのは有効な応急処置です。ただし、実際に何がヘッダーを膨らませているのか、2分ほど使って確認しましょう。Nginx のバッファをどんどん大きくするより、Cookie のペイロードを削減することが正しい答えである場合もあります。
# Nginx を経由せずにアップストリームから直接レスポンスヘッダーを確認する
curl -sI http://127.0.0.1:3000/api/dashboard
# 全ヘッダーの合計バイト数を取得する
curl -sI http://127.0.0.1:3000/api/dashboard | wc -c
Set-Cookie が原因の場合、問題はたいていセッションストアにあります。Rails のデフォルトの CookieStore はセッションのペイロード全体を Cookie にシリアライズします。Cookie が 4KB を超える典型的な原因がこれです。Redis やデータベースを使ったセッションストアに切り替えれば、Cookie は小さなセッション ID のみに縮小されます。
予防策
- バッファを事前に設定しておく — 新しい Nginx プロキシを設定するたびに、特に OAuth や JWT Cookie を使用するアプリでは、ユーザーが 502 エラーに遭遇する前に設定しておきましょう。
- セッションはサーバーサイドで管理する — Cookie にペイロードをシリアライズするのではなく、Redis・Memcached・データベースを使用し、Cookie にはセッション ID だけを保持します。
- 定期的にヘッダーを監査する — 認証ミドルウェアやフレームワークは気づかないうちにヘッダーを追加していきます。月に一度
curl -sIを実行するだけで、障害になる前に問題を発見できます。 - アプリ側で Cookie サイズを制限する — 4KB を超える Cookie はほぼ確実に壊れたセッションロジックが原因であり、正当なユースケースではありません。Nginx が検知する前に、アプリケーション層で捕捉しましょう。
ヒント
このようなネットワーク層の問題をデバッグする際、私は ToolCraft の IP サブネット計算ツールを併用することがあります。プロキシ設定でアップストリームの内部ネットワーク範囲を整理したり、CIDR ブロックを確認したりするときに便利です。ブラウザ上で完結し、データのアップロードは一切ありません。
クイックリファレンス
# 最小限の修正 — location または server ブロックに追加する
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;
# その後:
nginx -t && systemctl reload nginx

