

ALB配下のEC2でnginxって要る?フレームワーク別に見てみた
この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。
きっかけ
AWSでALB配下にEC2を置いてWebアプリを動かすとき、たまに迷うことがある。
アプリを3000番ポートとかで単体起動した場合、
ALB → nginx → appにすべき?それともALB → appで直結して問題ない?
このあたりの判断が本当に妥当なのか、あらためて整理してみた。
結論:単一アプリならALB直結でOK
先に結論を書くと、単一アプリのシンプルな構成なら ALB → app の直結で問題ない。
ALBはL7ロードバランサーとして、TLS終端・ヘルスチェック・パスベース/ホストベースのルーティングなどをすでにこなしてくれる。単一アプリでこの範囲の機能が足りているなら、わざわざnginxを挟む理由がない。
nginxを挟んだほうがいいケース
とはいえ、以下に当てはまるならnginxを検討する価値はある。
- 静的ファイル配信を分離したい(アプリ本体にやらせるより効率的)
- gzip圧縮・キャッシュ制御を細かく調整したい
- バッファリング/keep-aliveをアプリの手前で吸収したい
- 同一EC2内で複数アプリをルーティングしたい(ALB側のリスナー/ターゲットグループを増やしたくない場合)
- ALBのヘルスチェックの限界を補いたいとき。ALBはHTTPステータスコードだけで健全性を判定するので、アプリが200番台のエラーページを返す設計だと不健全な状態を見逃すことがある。nginx側でpassiveなヘルスチェックを組めば補完できる
直結する場合の実務上の注意点
nginxを挟まずALBから直結する場合、以下は意識しておいたほうがいい。
- アプリ側の keep-alive timeoutをALBのidle timeout(デフォルト60秒)より長く設定する(逆だと接続が中途半端に切れる)
- graceful shutdownをアプリ側で実装しておく(デプロイ時にALBのderegistration delayと噛み合わないと502が出る)
- セキュリティグループで ALBからのみアプリのポートを許可する
「組み込みHTTPサーバ=開発用」は思い込みだった
今回整理していて気づいたのが、「アプリの組み込みHTTPサーバは開発用途」という思い込みが、実は言語・フレームワークによって全然違うということ。
これはDjangoのrunserverのような「明確に開発専用」なケースに引きずられていた感覚で、Node.jsなどは組み込みサーバがそもそも本番運用前提で設計されている。
フレームワーク別・ALB直結可否リスト
ALBがTLS終端とヘルスチェックを担っている前提で整理するとこうなる。
| 言語/フレームワーク | 組み込みサーバ | ALB直結 | 理由 |
|---|---|---|---|
| Node.js(Express, Fastify, AdonisJS) | 標準 | ○ | 本番運用前提の設計。長時間プロセス常駐が標準モデル |
| Go(net/http, Gin, Echo) | 標準 | ○ | 標準ライブラリ自体が本番グレード |
| Rust(actix-web, axum) | 標準 | ○ | 非同期ランタイム前提で高性能、そのまま公開できる設計 |
| Laravel Octane(Swoole/RoadRunner/FrankenPHP) | Octane導入時 | ○ | 常駐ワーカー型に変わるのでNode.jsと同じ扱いになる |
| Elixir Phoenix(Cowboy/Bandit) | 標準 | ○ | BEAM/OTP前提で堅牢、そのまま本番運用される文化 |
| ASP.NET Core(Kestrel) | 標準 | △ | Microsoft公式は「必須ではないが推奨」というスタンス。ALBがTLS終端とヘルスチェックをやっているなら直結でも実質問題ない |
| Java(Spring Boot、組み込みTomcat/Netty) | 標準 | ○ | 組み込みTomcatも本番運用前提 |
| Python(FastAPI + Uvicorn/Gunicorn) | 標準+ASGI | ○ | Uvicorn/Gunicorn自体が本番運用向け |
| Ruby(Rails + Puma) | 標準(Puma) | ○ | Pumaはマルチスレッド対応の本番グレードサーバ(旧WEBrickは非推奨) |
| PHP(素のLaravel, Symfony等) | php artisan serve等 |
× | リクエストごとにフレームワーク全体を起動し直す仕組みで、組み込みサーバー自体が開発専用。nginx/Apache + PHP-FPMが必須 |
| Python(Django) | runserver |
× | 完全に開発専用、公式でも本番禁止。Gunicorn/uWSGI等の別サーバが必要(ただしそのサーバ自体は直結でも可) |
ざっくり見分けるなら、
- 常駐プロセス型(Node, Go, Rust, Phoenix, Java, Octane, Puma, Uvicorn/Gunicorn)→ 基本直結OK
- リクエストごとに起動し直す型(素のPHP, Django
runserver)→ 別途本番サーバが必須。ただしそのサーバ自体は大抵直結できる
という軸で整理すると分かりやすい。
nginx併用がよく見られる理由(ALB構成では該当しにくい)
世の中の記事でnginxを併用している例が多いのは、以下のような理由がほとんどで、ALB構成では該当しない。
- TLS終端を自前でやりたい(自宅サーバーでcertbotを使いたいなど)
- サブパス配信をしたい(
example.com/codeのような形にしたい場合) - 同一ホストに他のサービスも同居させたい
まとめ/チェックリスト
ALB配下でアプリを直結するかどうかを検討するときは、以下を順に確認するとよさそう。
- アプリのフレームワークは常駐プロセス型か?(上の表を参照)
- ALBの標準機能(TLS終端/ヘルスチェック/パスルーティング)だけで足りるか?
- 静的配信・細かいバッファ制御・複数アプリの内部ルーティングなど、ALB以上の制御が必要か?
- keep-alive timeout、graceful shutdown、セキュリティグループの設定は済んでいるか?
nginxを外して直結にする(あるいはその逆をやる)場合は、切り替え後に以下も忘れずに。
- ALBのヘルスチェックパスがアプリ側で正しく応答するか確認する
- 旧構成のnginx設定・関連セキュリティグループルールなど、不要になった設定は片付けておく
というわけで、ALB配下のリバースプロキシ要否はこんな感じ。単純な構成なら直結、フレームワーク特有の事情がある場合だけ挟む、くらいの温度感で考えておけば大きく外さないと思う。
なお、どうしてもnginx+Node.jsの2コンテナ構成をECS Fargateで続ける場合のCPU/メモリ配分は、ECS FargateでnginxとNode.js動かすなら、まずtask cpu 512 / memory 1024でよさそう にまとめた。
また、ゼロトラスト寄りにALB↔バックエンドもHTTPSにする場合、ALBはターゲット証明書のチェーンを検証しない(自己署名でも通る)。当時nginxでTLS終端していた検証メモは ALBはバックエンド証明書を検証しない、が公式仕様だった に書いた。Node.js直結でも、アプリ側でTLSを受ければ同じ話になる。