Next.jsプロジェクトをAWS ECS Fargateでデプロイし、Cloudflareを接続する過程で数時間ハマった記録を残します。結論から言うと、「自分のアプリが何番ポートで待機しているか」を正確に把握することがインフラ設定の肝でした。
-
問題の始まり:「Task failed ELB health checks」
ECSサービスを立ち上げたものの、コンテナーが起動しては消え、また起動しては消えるという無限ループに陥りました。ログには Ready in 851ms と出ておりアプリ自体は正常に動いているようでしたが、ロードバランサー(ALB)側で Unhealthy 判定が下され、コンテナーが即座にパージ(Draining)されていました。 -
第一のハマりどころ:リスナーとターゲットグループの混同
最初はユーザーがアクセスする80番ポート(HTTP)の設定ミスだと思っていました。しかし、真の犯人はターゲットグループ(Target Group)のポート設定にありました。
現象: ALBのリスナーは80番で開いていたものの、ターゲットグループもデフォルトの80番のままでした。
原因: Next.jsアプリはコンテナー内部で 3000番ポート で待機していたのに対し、ロードバランサーは80番ポートを叩きにいっていました。当然、応答がないためヘルスチェック失敗となります。
- 第二のハマりどころ:修正できないターゲットグループのポート
ターゲットグループの設定からポート番号だけを3000に変更しようとしましたが、AWSの仕様上、ターゲットグループのポートは作成後に変更が不可能でした。
解決策: 結局、既存のターゲットグループを捨て、Port: 3000、Type: IP で新しくターゲットグループを作成し直しました。
注意点: この時、リスナー(Listener)は80番のままでOKです。ユーザーは80(または443)でアクセスし、ロードバランサーが内部的に3000番に「翻訳」してコンテナーへ流してくれる構造が正解です。
- 第三のハマりどころ:タスク定義(Task Definition)のポートマッピング
ターゲットグループを3000番に変えても、依然として Draining が発生しました。ECSサービスの設定内にある コンテナーポートマッピング が80番のままになっていたためです。
対応: 1. タスク定義(Task Definition)の新しいリビジョンを作成。
2. ポートマッピングを 80 -> 3000 に変更。
3. ECSサービスの更新時に、この最新リビジョンを適用し、「新しいデプロイの強制」にチェックを入れて実行。
このステップを経て、ようやくターゲットグループで Healthy(緑色のチェック) を確認することができました。
- 仕上げ:Cloudflareの Error 1016
AWS側の設定をすべて修正したのも束の間、次はCloudflareで 1016 Origin DNS Error が発生。
原因: ロードバランサーを再作成したことでDNS名が変わったにもかかわらず、CloudflareのCNAMEレコードが古いALBのDNS名を指したままでした。
解決策: CloudflareのDNS設定でCNAMEのターゲットを新しいALBのDNS名に更新。この際、末尾の不要なスラッシュ(/)や http:// が混じっていないか注意して修正したところ、即座に接続されました。
💡 まとめと教訓
ポートの整合性: App Port(3000) == Task Definition Port(3000) == Target Group Port(3000)。この三拍子が揃って初めてヘルスチェックが通る。
ALBリスナーの役割: 外部公開ポート(80)と内部アプリポート(3000)は別物で良い。ロードバランサーがその橋渡し役となる。
強制デプロイ: 設定変更後は、古い設定で残っている「ゴーストコンテナー」を確実に停止させ、新しい設定を即時反映させることが重要。
インフラは一度絡まると厄介ですが、ポート番号の一つひとつの流れを追っていけば必ず解決できるということを痛感した一件でした。