OXY NOTES

Nginxで502 Bad Gatewayの原因が「upstream sent too big header~」の場合の対処法

管理しているWebサイトで502 Bad Gatewayが発生していました。
Nginxのエラーログを見ると以下のようなログが流れていました。

2019/04/18 20:00:33 [error] 6793#0: *14604 upstream sent too big header while reading response header from upstream, client: 0.0.0.0, server: example.com, request: "GET /hoge HTTP/1.0", upstream: "fastcgi://unix:/var/run/php-fpm/php-fpm.sock:", host: "example.com"

upstream sent too big header while reading response header from upstream」の意味は「レスポンスヘッダーのサイズが大きすぎる」とのこと。

大抵の場合、大量のCookieをやり取りする際に発生します。そういった場合は設定ファイルでFastCGIレスポンスのためのバッファサイズを大きくすると解決します。

それぞれの意味については以下を参照

コンテキスト(設定が有効なセクション)は「http, server, location」となっています。通常はサーバ全体に反映させるのでhttpセクションだと思います。

# vi /etc/nginx/nginx.conf
    proxy_buffers 8 32K; # default 8 4k|8k
    proxy_buffer_size 32k; # default 4k|8k
    proxy_busy_buffers_size 64k; # default 8k|16k

proxy_busy_buffers_sizeは上記2つの設定で制限されるとあるので、今回のような場合はあえて設定しなくてもいいかもしれません。
設定が完了したら再起動して有効にします。

# /etc/init.d/nginx restart

ちなみにproxy_buffersですが実際にどれだけのサイズを使っているか調べる方法があります。
以下のリンクで算出方法を紹介しています。
Nginx FastCGI response buffer sizes

ページ中程にあるDetermine actual FastCGI response sizesの項目です。まずはphp-fpm.sockの値だけ抜き出して別ファイルにまとめます。
続いてphpfpmonly-access.logの応答を元に値を算出します。

$ awk '($9 ~ /200/) { i++;sum+=$10;max=$10>max?$10:max; } END { printf("Maximum: %d\nAverage: %d\n",max,i?sum/i:0); }' phpfpmonly-access.log

すると最大値と平均値が出されます。
とりあえず最大値でも溢れないように設定すれば問題ないと思います。

と、ここまではよくある話。
問題がリバースプロキシのバッファサイズだった場合、上記の設定で問題が解決します。しかし今回は一向に改善しません。試しに10倍の値にしても502エラーが出続けました。

PHP-FPMが原因で動かなかった場合の対処法

次に注目したのが以下の部分。

upstream: "fastcgi://unix:/var/run/php-fpm/php-fpm.sock:"

特定のページやアプリではなく、PHP自体が停止の原因なのかもしれない…。ひょっとしたらPHP側にもバッファーの設定があるのか?と探したらありました。
fastcgi_bufferingという設定です。

解説の内、重要な部分は以下の部分

バッファリング無効な場合は、応答を受け取るとすぐにクライアントに同期して渡されます。nginxはFastCGIサーバから全ての応答を読み込もうとはしないでしょう。nginxがサーバから同時に受け取れるデータの最大サイズは、fastsgi_buffer_size ディレクティブによって設定されます。

どうやらPHP自体で大きなヘッダサイズの応答をする場合はこちらのほうも設定する必要があるようです。

それぞれの意味については以下を参照

今回は以下のように設定しました。

    fastcgi_buffers 8 32K; # default 8 4k|8k
    fastcgi_buffer_size 32k; # default 4k|8k
    fastcgi_busy_buffers_size 64k; # default 8k|16k

fastcgi_busy_buffers_sizeは上記の通り特に設定しなくても動きます。
この設定で再起動すると再び502エラーが出ることはありませんでした。上記2つの設定はあくまでバッファの最大サイズを増やしただけなので、大きなバッファサイズが必要なページは限定的なため、今回の設定によって特別メモリ消費が多くなることもありませんでした。


以上、よくあるproxy_buffersだけでなく、fastcgi_buffersも設定したほうが良いかもしれないよという投稿でした。
一番の問題はそんなに大きなヘッダサイズを消費するような設計ですが、自分の関知しないものもあるので、応急処置として設定しておきましょう。

がリバースプロキシの例と同じようにサイズを変更できるようです。