Node.js: ALB の裏でたまに 502 が出るなら keepAliveTimeout を ALB のアイドルタイムアウトより長くする
Node の http.Server はアイドルな keep-alive 接続を既定 5 秒で閉じるが、AWS ALB は既定 60 秒まで同じ接続を使い回す。ALB が「まだ使える」と思って送ったリクエストを、Node がちょうど閉じた接続で受けると 502 になる。Node 側を ALB より長くする。
どんな時に気にする?
- ALB(や他のロードバランサ・リバースプロキシ)の裏で Node(Express / Fastify / Next.js の自前サーバーなど)を動かしている
- 負荷が低い時間帯に、ランダムで少数の 502 が出る(アプリのログにはリクエストが届いていない)
- ALB のアクセスログで
elb_status_code=502、target_status_codeが空(-)
設定例
ts
import http from "node:http";
const server = http.createServer(app);
// ALB のアイドルタイムアウト(既定 60 秒)より長くする
server.keepAliveTimeout = 65_000;
// ヘッダー受信の待ち時間は keepAliveTimeout より長く(古い Node では逆転すると同じ症状が出た)
server.headersTimeout = 66_000;
server.listen(3000);- 考え方は「接続を閉じるのは、前に立つ側(ALB)が先」。後ろの Node が先に閉じると、閉じる瞬間と ALB の送信がすれ違う。
- ALB のアイドルタイムアウトを変えている場合は、その値 + 数秒にする。nginx や Cloudflare など別のプロキシでも同じ考え方(プロキシ側の upstream keep-alive の時間 < Node の
keepAliveTimeout)。 - Express は
app.listen()の戻り値がhttp.Serverなので、そこに設定する。
注意点
- 値を変えても、設定前に張られた接続には効かない(Node のドキュメントにも「接続時に設定される」とある)。起動直後、
listenの前後で設定する。 - Node の最近の版には
keepAliveTimeoutBufferというオプションもあり、実際のソケットのタイムアウトはkeepAliveTimeout + keepAliveTimeoutBufferになる。 headersTimeoutの既定値は Node 18.14 / 19.4 以降requestTimeoutと 60 秒の小さい方。keepAliveTimeoutを 65 秒にするなら、こちらも合わせて上げておくと安全。- Go のクライアント側で同じことを考えるなら、Go: 同じホストへ大量に呼ぶなら MaxIdleConnsPerHost を上げる(既定は 2) の「相手の keep-alive より
IdleConnTimeoutを短く」と同じ理屈(閉じるのは常に相手より先か後かをそろえる)。
出典
- @amitsinha__07 · 2026-10-21
- Node.js ドキュメント
server.keepAliveTimeout(既定 5000ms)/server.headersTimeout: nodejs.org