📘 Day24:ネットワークからアプリケーションへ:Application Load Balancer と Amazon API Gateway
📝 概要
こちらの投稿は2025 Japan AWS Jr.Championsの有志メンバーで作成した『30日間で主要AWSサービスを構築できるようになる』をテーマにした初学者向けのハンズオン問題集のDAY24になります!
問題集の趣旨や作成に至るまでの経緯は以下の記事をご覧いただければと思います。
https://qiita.com/satosato_kozakana/items/446971c2deca7e27d0aa
| 項目 | 内容 |
|---|---|
| 所要時間 | 約5時間 |
| メインサービス | Application Load Balancer, Amazon API Gateway |
| 学べること | 3 層アーキテクチャをもつアプリケーションを作成し公開する方法 |
| 想定費用 | 約300円(※ハンズオンを行った時間や実際にサービスを試した回数により変動します) |
⚠️ 注意:以下のリソースを削除し忘れると課金が継続します。
🎯 課題内容
フロントエンド(EC2上)とバックエンド(API Gateway + Lambda)が分離されたアプリケーションをネットワークに公開します。
これまで Amazon EC2(EC2) や Amazon DynamoDB(DynamoDB)、AWS Lambda(Lambda)、Amazon VPC(VPC)といった様々なサービスのハンズオンをしてきました。これらのサービスを組み合わせて Web アプリケーションを構築します。AWS には、異なるサービス間の通信を制御・仲介するための仕組みがいくつかあります。その中でも Application Load Balancer (ALB) および Amazon API Gateway (API Gateway) を使用して Web アプリケーションを構築していきます。
📊 アーキテクチャ図
🔧 実装機能
- ALB の DNS 名をブラウザで開くと、アプリケーションを利用できます。
- アプリケーションの内容は、AWS アイコンクイズです。ランキング機能も実装しましょう。
- ランキング機能を実装するためにデータを永続化する必要があります。データの永続化のためには、DynamoDB を使用しましょう。
- DynamoDB への通信はAPI Gateway を経由して、Lambda に処理を任せましょう。この構成は 3 層アーキテクチャに基づいています。
- 問題は、DynamoDB で管理しましょう。
遊び方
ユーザーがアクセスすると、「ユーザ名」を入力する欄と「スタート」ボタンが現れます。

「ユーザーネーム」欄を埋めた後に「スタート」ボタンを押すと、4 択からの選択肢つきアイコン当てクイズが 5 問出題されます。一番下に「提出」ボタンも現れます。

私のミスでアイコンの色が全てオレンジ色になっています。すみません。誰か直してください。
「提出」ボタンを押すと、そのときに選択していた回答が送信されます。自分のスコアと現状の世界ランキングが表示されます。

「トップに戻る」ボタンを押すと、アクセス時の画面に戻ります。
3 層アーキテクチャ
システムを 3 つの層に分ける設計です。
- プレゼンテーション層(EC2)
- ユーザーとのやり取りを担当します。
- アプリケーション層(Lambda)
- 主要な処理を担当します。API Gateway と混同されがちですが、API Gateway はアプリケーション層のエントリポイントとして機能しており、実際の処理は Lambda が行います。
- データ層(DynamoDB)
- データの保存・取得を担当します。
今回のアプリケーションは、機能要件が少し多くなっています。自力で実装することでさらに力がつきますが、このハンズオンの主目的は、ALB と API Gateway を使用してアプリケーションを安全にインターネットへ公開することです。適宜、 GitHub レポジトリ を使用して実装の負担を減らすことをおすすめします。
💡 実装のヒントおよび解答
今回の課題はとても難しいです。ヒントを活用しつつ、解いていくことをおすすめします。解答を読みつつ進めても、十分に力がつきます。
API の要件を考える
遊び方から、どのような API が必要かを考えます。
今回は、以下の API を作成します。
| API | 内容 |
|---|---|
GET /questions
|
Lambda が DynamoDB からクイズを取得し、レスポンスとして返します。統一して 5 問返します。クエリパラメータで username を受け取ります。 |
POST /answer
|
ユーザーの回答を受け取ってスコアを計算し、DynamoDB へ記録します。計算したスコアを返します。 |
GET /ranking
|
DynamoDB からユーザーのスコアを取得し、ランキングを返します。上位 5 つを返します。 |
DynamoDB テーブルの要件を考える
先ほど検討した API から DynamoDB のテーブルをどのように構築していくか考えます。
Questions テーブル
| 項目 | 内容 |
|---|---|
| question_id | 問題を一意に識別するために振られます。パーティションキーになります。 |
| image_svg | 今回はsvgを直接埋め込みます。AWS ICONS からアイコンを選び、copy SVG で HTML を取得して直接埋め込みます。 |
| choices | 4 つの AWS サービス名です。問題の選択肢となります。問題の答えが含まれている必要があります。 |
| answer | 問題の答えです。 |
QuizResults テーブル
| 項目 | 内容 |
|---|---|
| quiz_id | クイズの結果を一意に識別するために振られます。パーティションキーになります。 |
| username | ユーザー名です。これがランキングに載ります。 |
| correct | 正答数です。0 から 5 の値になります。 |
Lambda に関連付ける IAM ロール
Lambda は、DynamoDB テーブルにアクセスする必要があります。また、ログを Amazon CloudWatch Logs に出力したいです。そこで、これらの許可をもつ IAM ロールを作成し、Lambda 関数に関連づける必要があります。
API Gateway とは
API Gateway とは、クライアント(ブラウザやモバイルアプリ、CLI など)からの HTTP リクエストを受け取り、それをバックエンド(AWS Lambda、Amazon EC2、他の API など)に転送するためのマネージドサービスです。以下の 3 種類が用意されています。
- HTTP API
- OIDC や OAuth2 などの組み込み機能およびネイティブ CORS サポートを使用して、低レイテンシーでコスト効率の高い HTTP ベースの API を構築します。
- WebSocket API
- チャットアプリケーションやダッシュボードなど、リアルタイムのユースケース向けの永続的な接続を使用する WebSocket API を構築します。
- REST API
- API 管理機能とともに、リクエストとレスポンスを完全に制御できる REST API を開発します。
今回は、 HTTP API を使用していきます。これに Lambda を統合することで、API Gateway が HTTP リクエストを受け取ったとき、そのリクエストを Lambda イベントに変換して Lambda 関数を呼び出します。
API Gateway を経由する理由
- データベースアクセスの統一管理
- API Gatewayを介することで、データベースへのアクセスを一元的に制御できます。これにより、認証認可を統合的に実装し、アクセス制御を細かく設定可能です。 API Gatewayで認証や認可を行い、Lambdaでビジネスロジックやデータ操作を集中させることで、アーキテクチャの責任範囲が明確になり、コードの保守性や可読性が向上します。
- セキュリティ強化
- 直接 Lambda を外部に晒さずに API を公開することができます。 直接データベースにアクセスさせず API Gatewayを経由させることで、データベースがインターネットから直接アクセスされるリスクを回避できます。
- データベースアクセスの抽象化
- API Gatewayは、バックエンドのデータベースアクセス方法を抽象化します。これにより、データベースの変更や、異なるデータソースへの切り替えを行っても、APIのインターフェースは変わらず、クライアント側への影響を最小化できます。
- モニタリングとロギング
- API Gatewayは、すべてのリクエスト・レスポンスをCloudWatchに自動的に記録できます。これにより、アクセスパターンの監視、エラーログの分析、リクエストのトラフィックの追跡が可能となり、システムの運用監視が容易になります。
- 統一的なAPI管理
- APIのバージョン管理やエンドポイントのルーティングも簡単に設定可能となり、スムーズな運用が実現できます。
EC2 でフロントエンドをホスティングする
EC2 インスタンスを用いて、80 番ポートでフロントエンドをホスティングします。今回のフロントエンドは VueとTypeScript によるシングルページアプリケーション(SPA)として実装されており、これをビルドして作成された静的ファイルを Nginx を使用して配信します。
これらのビルドからホスティングまでの一連の流れを簡単に行う方法として、以下があります。
- セッションマネージャーで EC2 インスタンスに接続し、手動でコマンドを実行する
- user data を使用する
どちらでも好きな方で良いですが、セッションマネージャーを使用する際は EC2 インスタンスに適切なポリシー(例えば、AmazonSSMManagedInstanceCore)のアタッチされた IAM ロールを関連付ける必要があります。
静的ファイルのホスティング
今回はフロントエンド側の実装を簡潔にするため静的ファイルのホスティングをテーマにして EC2 を使用していますが、静的ファイルのホスティングに関しては Amazon S3 においた静的ファイルを CloudFront を使用して配信する形の方がベストプラクティスです。実際に EC2 などのコンピューティングリソースが必要となるのは、動的生成が必要な場合です。例えば、サーバーサイドレンダリング(SSR)などが挙げられます。
ALB とは
AWS が提供するマネージドなロードバランサーです。ターゲットグループとして送信先を定義し、それらに対するルーティングをポートおよびパスなどの条件を元に制御することができます。ALB が リクエストを受け付けるポートをリスナーと呼び、リスナーにきたリクエストをターゲットグループに振り分けるルールをリスナールールと呼びます。
リバースプロキシとしても動作するだけではなく、ログの一元化や証明書管理の集中化にも優れています。
EC2 を直接外部に晒さずに特定ポートのみを ALB 経由で公開することができるので、セキュリティ的な観点からも優れています。
リバースプロキシ
ある Web サイトにアクセスする際に、仲介する役目を果たすサーバーのことをプロキシと呼びます。特にクライアント側から見えないものをリバースプロキシと呼びます。
CORS 設定
ここまでの設定をうまく行ってフロントエンドに ALB のドメイン名を使用してアクセスできても API Gateway へのリクエスト時にエラーが起きる場合があります。これは同一オリジンポリシーにより、異なるオリジンへのアクセスが制限されているためです。これは、ブラウザ上の JavaScript が自分と異なるオリジンのリソースへアクセスする場合、明示的な許可(CORS設定)が必要であるという意味です。
ALB と API Gateway は別のオリジンとなっています。そこで CORS(Cross-Origin Resource Sharing)の設定をする必要があります。この設定は、API Gateway にて一括で行うことができます。
🧰 使用資材
GitHub レポジトリ を参照してください。
ここでは、そのファイル構成を紹介します。
11-ALB_and_APIGateway
├── backend # API Gateway と統合する Lambda 関数のサンプルコードが置いてあります。
│ ├── get_questions.py # get-question の Lambda 関数のサンプルコードです。これを lambda_function.py にコピーアンドペーストしてください。
│ ├── post_answer.py # post-answer の Lambda 関数のサンプルコードです。これを lambda_function.py にコピーアンドペーストしてください。
│ └── get_ranking.py # get-ranking の Lambda 関数のサンプルコードです。これを lambda_function.py にコピーアンドペーストしてください。
└── frontend # フロントエンドのサンプルコードです。`npm run build` とすることでビルドができます。
├── src
│ ├── api
│ │ └── quiz.ts
│ ├── router
│ │ └── index.ts
│ ├── types
│ │ └── quiz.ts
│ ├── views
│ │ ├── HomeView.vue
│ │ ├── QuizView.vue
│ │ └── ResultView.vue
│ ├── App.vue
│ └── main.ts
├── index.html
├── package-lock.json
├── package.json
└── vite.config.ts
🔗 リファレンスリンク
🛠️ 解答・構築手順(クリックで開く)
解答と構築手順を見る
✅ ステップ1:Amazon DynamoDB の作成
今回のアプリケーションでは、クイズの問題とユーザーのスコア結果を保存・取得するために DynamoDB を利用しています。ここでは、クイズ問題を管理するための「Questions」テーブルと、ユーザーのスコア結果を保存・取得するための「QuizResults」テーブルの二つを作成します。
-
「テーブルの作成」を押して、テーブルを作成します。
-
まずは、「Questions」テーブルです。「question_id」をパーティションキーとします。入力した後に、一番下の「テーブルの作成」を押してテーブルを作成します。

-
次に、「QuizResults」テーブルを作成します。「quiz_id」をパーティションキーとして先ほどと同様に作成します。左のメニューから「テーブル」を開くと、「テーブルを作成」のボタンが出てくるので、そこから作成することができます。

-
テーブル一覧で、自分が作成した二つのテーブルを確認しましょう。左のメニューから「テーブル」を開くと、作成したテーブルの一覧が出てきます。

✅ ステップ2:Amazon DynamoDB Questions テーブルにサンプルデータを格納する
今後、アプリケーションの挙動を確認するときに「Questions」テーブルに少なくとも 5 問の問題が必要になります。作成していきましょう。
-
「テーブルアイテムの探索」をクリックします。ここから、現在 DynamoDB テーブルに入っているデータが確認できます。

-
「新しい属性の追加」を押すことで、データに新しいカラムを追加できます。下の画像のように「image_svg」「choices」「answer」を追加していきましょう。

-
「question_id」は適当な値で埋めてしまいましょう。「image_svg」の値は、AWS ICONS から探していきます。今回は、「DynamoDB」を追加していきます。「Copy SVG」を押して、そのまま貼り付けましょう。


6. 「answer」「choices」も埋めます。その後、項目を作成を押して、項目が作られます。

これを、残り 4 問行いましょう。もっとたくさんの問題を追加しても良いです。
✅ ステップ3:Lambda 関数の作成
API の処理を実際に行う Lambda 関数を作成します。
-
「関数の作成」を押して、関数を作成します。一から作成を選択し、関数名を「get-questions」でランタイムを「Python 3.13」とします。それ以外はデフォルトのままで構いません。下にある「関数の作成」ボタンを押して、関数を作成しましょう。

-
3 と同様にして、「post-answer」「get-ranking」の二つの関数を作成します。関数名以外は、先ほどと同じで十分です。


4. 「関数」タブを押して、関数の一覧を表示します。三つの関数が作成されていることを確認しましょう。

✅ ステップ4:AWS Lambda 関数のアップデート
Lambda 関数は作成した直後は、以下のようなデフォルトコードが入っています。
import json
def lambda_handler(event, context):
# TODO implement
return {
'statusCode': 200,
'body': json.dumps('Hello from Lambda!')
}
この関数を、アプリケーションに合わせた処理内容に書き換えます。コードは、上の「使用資材」を参考にコピーアンドペーストしましょう。
- Lambda の関数一覧から、「get-questions」関数を選択します。
- 下の「コード」タブ内にある「コードソース」を直接更新します。もともと書いてあるコードを削除して、「使用資材の」
backend/get_questions.pyをコピーアンドペーストします。
- この状態だと更新は反映されていません。左にある「Deploy」のボタンを押しましょう。上部に「関数 get-questions が正常に更新されました。」と出てきます。これで関数の更新が終了します。
- 1~3 の手順を、「post-answer」「get-ranking」の残り二つにも行います。それぞれ
backend/post_answer.py、backend/get_ranking.pyに対応します。
✅ ステップ5:Lambda の IAM ロールに DynamoDB アクセス権限を追加する
Lambda 関数を作成したときに IAM ロールがそれぞれ作成されていました。デフォルトでは「AWSLambdaBasicExecutionRole-XXX」というポリシーが付与されており、こちらには AWS CloudWatch Logs のロググループおよびログストリームを作成する権限とログイベントを保存する権限しか付与されていません。Lambda 関数が DynamoDB のデータを読み書きできるようにするために、IAM ロールに追加のアクセス権限を付与します。
今回は、「AmazonDynamoDBFullAccess_v2」という名前のポリシーを追加で付与していきます。こちらは、DynamoDB へのフルアクセスを許可するポリシーです。
- マネジメントコンソール左上の検索タブで「IAM」と検索して、Identity and Access Management(IAM)のページを開きます。
- 左にある「ロール」タブを押します。そして「get-questions」で始まる IAM ロールを探してクリックします。
- 「許可」タブの中の「許可ポリシー」欄内にある「許可を追加」から、「ポリシーをアタッチ」をクリックします。

4. 検索タブから「DynamoDB」と検索し、「AmazonDynamoDBFullAccess_v2」を探して、選択します。すると「許可を追加」ボタンが押せるようになります。


5. 許可ポリシーが追加されたことを確認しましょう。

6. 「post-answer」「get-ranking」で始まる IAM ロールに対しても同様にします。
最小権限の原則
実は、「AmazonDynamoDBFullAccess_v2」は簡単に設定できる一方で、全ての DynamoDB テーブルへのフルアクセス権限を与えてしまいます。
実際の運用では、各 Lambda 関数ごとにアクセスが必要なテーブル・操作(読み取り・書き取り)を限定したインラインポリシーを作成するのがベストプラクティスです。
余力がある方はやってみましょう。権限が不足している場合は AWS CloudWatch Logs からどの権限が不足していたか確認できます。これを用いて調整していくと良いです。
✅ ステップ6:Amazon API Gateway を作成する
これまでに作成した三つの Lambda 関数をまとめて外部公開できるように、API Gateway を構築します。API Gateway を使用することで、複数の Lambda 関数を一元的に管理し、統一された API エンドポイントを通してアクセスできるようになります。
また、ステージ URL(デプロイ先の URL)を利用することで、Lambda を直接公開せずに安全に呼び出せるようになります。
- マネジメントコンソール左上の検索タブで「API」と検索して、API Gateway のページを開きます。
- 「API の作成」を押して API を作成に進みます。ヒントで解説したように三つのタイプがありますが、今回は HTTP API を使用します。「構築」をクリックします。
- API 名を「quiz-api」とします。統合を追加から Lambda を選択し、これまで作成してきた三つの関数「get-questions」「post-answer」「get-ranking」を追加します。

- ルートを以下の画像のように三つ追加します。それぞれメソッドとリソースパスに気をつけて作成します。
- ステージを設定します。ステージ名は、「prod」とします。自動デプロイもオンのままで構いません。
- 全体の設定をもう一度確認して作成しましょう。
セキュリティリスク
API Gateway は、インターネット上にデプロイ URL を介して公開されています。本番運用では、悪意を持ったユーザーからの攻撃に対する防御として AWS WAF(Web Application Firewall)を使用することをおすすめします。また、API Gateway は、Cognito や IAM 認証を組み合わせることも可能です。これらの工夫によって、セキュリティリスクを減らすことが可能です。
✅ ステップ7:Amazon API Gateway をローカルから呼び出してみる
ここまでで作成した API Gateway と Lambda 関数が正しく連携して動作しているかを確認します。実際にローカル環境から API にアクセスして、レスポンスが返ってくることを確認してみましょう。この確認を行うことで、API Gateway → Lambda → DynamoDB の通信がすべて正常に機能しているかを確かめることができます。
※このステップは任意です。実行しなくても次のステップには進めます。


2. 「prod」をクリックすると、右側にステージの詳細が出てきます。こちらの「URL を呼び出す」に書かれている URL をコピーします。

3. 自分の PC のターミナルを開きます。以下のコマンドを実行して、レスポンスが返ってくることを確認します。正しく動いている場合は、{"message": {"questions": [...]}} から始まるとても長い JSON データが表示されます。
curl "<確認した URL>/questions?username=test-user"
curl とは、多種多様なプロトコルをサポートする、URL で指定されたサーバーとデータを送受信できるオープンソースのツールです。上では、GET リクエストを送りました。当然 POST リクエストも送ることができます。
余裕がある方は、「POST /answer」に対しても curl を使用してリクエストを送ってみましょう。
✅ ステップ8:Amazon VPC、サブネット、NAT Gateway を作成する
今回のハンズオンでは、フロントエンドのホスティングに EC2 を使用します。EC2 は、プライベートサブネットのなかに作成する必要があります。そのための準備をしていきます。今回は、AWS が提供する「VPC など」の作成ウィザードを使って、必要な構成を一度に作成します。「VPCなど」を選ぶと、VPC 本体に加えて以下のリソースも自動的にまとめて作成されます。
- パブリックサブネット
- プライベートサブネット
- インターネットゲートウェイ
- NAT ゲートウェイ
- ルートテーブル
- マネジメントコンソール左上の検索タブで「VPC」と検索して、Amazon VPC のページを開きます。
- 「VPC を作成」を押します。まとめて作るために、「VPC の設定」を「VPC など」に変更します。名前タグの自動生成を「quiz-app」とします。
- さらに以下の画像のように設定します。ポイントは、NAT Gateway を設置したことです。EC2 はプライベートサブネットに設置します。セキュリティのため EC2 は直接インターネットに接続できませんが、NAT Gateway を通すことでパッケージのインストールなど「外向きの通信」ができるようになります。
- VPC を作成をクリックします。しばらく待つと VPC とその周辺のリソースが作成されます。
✅ ステップ9:Amazon EC2 用の IAM ロールを作成する
ALB の特徴を知るために、Amazon EC2 インスタンスは 2 台立てます。全く同じ権限を使用することになるので、共通の IAM ロールを先に作成しておきましょう。
- マネジメントコンソール左上の検索タブで「IAM」と検索して、Identity and Access Management(IAM)のページを開きます。
- 「ロールの作成」をクリックし、ロール作成に進みます。ユースケースは EC2 です。「次へ」を押して、設定を進めます。

3. 「許可を追加」の画面で、「CloudWatchAgentServerPolicy」「AmazonSSMManagedInstanceCore」の二つのポリシーをアタッチします。

4. 「quiz-instance-role」というロール名にし、「ロールを作成」ボタンを押します。これで IAM ロールが作成できます。
✅ ステップ10:Amazon EC2 用のセキュリティグループを作成する
上の IAM ロールと同様に、セキュリティグループも先に作成しておきましょう。
- マネジメントコンソール左上の検索タブで「EC2」と検索して、Amazon EC2 のページを開きます。
- 左のメニュータブから「セキュリティグループ」を押します。「セキュリティグループを作成」ボタンからセキュリティグループの作成に進みます。
- セキュリティグループ名を「quiz-instance-sg」とします。VPC タブを開き、先ほど作成した「quiz-app-vpc」を選択します。特にルールを変更する必要はありません。「説明」は適当に埋めてしまいましょう。
- 「セキュリティグループを作成」ボタンから、セキュリティグループを作成しましょう。
✅ ステップ11:Amazon EC2 インスタンスを作成する
ステップ8、ステップ9 で、Amazon EC2 を作成する準備をしてきました。これらのパーツを使用して、EC2 インスタンスを作成しましょう。
- 左のメニュータブから「インスタンス」を押します。「インスタンスを起動」ボタンを押して、仮想サーバーの起動に進みます。 名前を「quiz-instance-1」とします。AMI はデフォルトの「Amazon Linux 2023 kernel-6.1 AMI」を選択します。アーキテクチャも「64ビット(x86)」で問題ありません。インスタンスタイプもデフォルトの「t2.micro」で問題ありません。
- 以下の画像のように変更します。VPC を「quiz-app-vpc」にし、サブネットを「quiz-app-subnet-private1-ap-northeast-1a」、既存のセキュリティグループを選択で「quiz-instance-sg」とします。サブネットが「private」であることが重要です。
- ストレージサイズも増やしておきましょう。15 GiB としておきます。
- 高度な詳細を開き、先ほど作成した「quiz-instance-role」を IAM インスタンスプロフィールに設定しておきます。これで「インスタンスを起動」ボタンを押しましょう。
- キーペアの有無を聞かれると思いますが、キーペアなしで続行で構いません。「インスタンスを起動」を押して起動します。
- インスタンス一覧に先ほど作成した EC2 インスタンスが表示されていることを確認しましょう。しばらく待つとインスタンスが実行中になります。
プライベートサブネットに EC2 を起きます。EC2 に直接ユーザーがアクセスすることはとてもリスクがあります。ALB がパブリックサブネットに置かれユーザーはそのドメイン名に対してアクセスしますが、この構成には以下のメリットがあります。
- 外部からは ALB しか見えないので、EC2 の OS 層への直接攻撃リスクがなくなる。
- ALB 側に SSL 証明書の設定をすれば良くて、EC2 ごとに証明書を用意する必要がなくなる。
- AWS WAF(Web Application Firewall)との統合が簡単になります。
- ALB で設定したポート以外は外部からアクセスできなくなる。
✅ ステップ12:Amazon EC2 インスタンスに SSH 接続してポート 80 でアプリケーションを公開する
アプリケーションを EC2 のなかで起動します。80 番ポートでリクエストを受け付けるようにします。
この後、セッションマネージャーにて以下のコマンドを順に打ちます。空行ごとに区切って入力してください。
# Git および Nginx をインストールします。
sudo dnf install -y git nginx
# Nodejs をインストールします。バージョンが `20.0` 以上である必要があります。
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs
# ホームディレクトリへ移動します。
cd
# フロントエンド用のソースコードをダウンロードします。
sudo git clone https://github.com/2025-Japan-AWS-Jr-Champions/30-days-handson-11-ALB_and_APIGateway-code.git
# フロントエンド用のソースコードのルートへ移動します。
cd 30-days-handson-11-ALB_and_APIGateway-code/frontend
# Vim で一部のファイルを編集します。Vim の使い方はここでは解説しません。
sudo vi src/api/quiz.ts
# `BASE_API` の部分を API Gateway への接続テストの時に用いたステージ URL に変更します。
# 例: const BASE_API = "https://<API Gateway の ID>.execute-api.ap-northeast-1.amazonaws.com/prod";
# npm が使用するライブラリをインストールします。
sudo npm install
# ソースコードをビルドします。
sudo npm run build
# ビルドして作成した静的ファイルを Nginx が指定するフォルダに移動します。
sudo mv dist/* /usr/share/nginx/html/
# Nginx の起動設定を作成します。
sudo tee /etc/nginx/nginx.conf > /dev/null << 'EOF'
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
}
EOF
# Nginx を再起動します。
sudo nginx -t && sudo systemctl restart nginx
もう一つ、インスタンスが必要です。EC2 インスタンスをもう一つ起動しましょう。名前は、「quiz-instance-2」としましょう。またセキュリティグループは、「quiz-app-subnet-private2-ap-northeast-1c」を選択します。それ以外の設定は全く同じで問題ないです。
✅ ステップ13:ALB 用のセキュリティグループを作成する
セキュリティグループを ALB 用に作成します。ステップ 10 と手順は同じです。セキュリティグループ名を「alb-sg」とします。
インバウンドルールの設定の部分のみ書き換える必要があります。すべてのトラフィックから 0.0.0.0/0 のルールを追加しましょう。

インバウンドルール
ALB はパブリックサブネットに設置するので、インバウンドルールで許可した通信を受け付けることになります。通常、インターネットに公開する際は AWS WAF などを設置し、攻撃に備えましょう。
✅ ステップ14:Application Load Balancer を作成する
- マネジメントコンソール左上の検索タブで「EC2」と検索して、Amazon EC2 のページを開きます。
- 左側のメニュータブから「ロードバランサー」を押します。
- ロードバランサータイプから「Application Load Balancer」の「作成」ボタンを押します。
- ロードバランサー名を「quiz-alb」とします。
- ネットワークマッピングを編集します。VPC を「quiz-app-vpc」として アベイラビリティゾーンとサブネットを「quiz-app-subnet-public1-ap-northeast-1a」「quiz-app-subnet-public2-ap-northeast-1c」サブネットとします。「public」を選択するように注意します。
- セキュリティグループに先ほど作成した「alb-sg」を選択します。
- デフォルトアクションを定義します。今回は「固定レスポンス」を「HTTP」での「80」番ポートへのアクセス時に返すように設定しましょう。
- 最後に確認をして、「ロードバランサーの作成」ボタンからロードバランサーを作成しましょう。
✅ ステップ15:ターゲットグループを作成する
- 左側のメニュータブから「ターゲットグループ」を押します。
- 「ターゲットグループの作成」を押して、ターゲットグループの作成に進みます。
- ターゲットタイプの選択から「インスタンス」を選び、ターゲットグループ名を「quiz-tg」とします。
- プロトコルは HTTP でよくポートも 80 のままにします。VPC を「quiz-app-vpc」に変更します。ヘルスチェックもそのままで良いです。「次へ」を押してターゲットの登録に進みます。
- インスタンスを先ほど作成した二つのインスタンスに設定し、選択したインスタンスのポートは 80 のままで、「保留中として以下を含める」ボタンを押します。

6. 「ターゲットグループの作成」ボタンを押して、作成します。
✅ ステップ16:リスナールールを追加する
- 左側のメニュータブから「ロードバランサー」を押して、先ほど作成したロードバランサーの画面に進みます。
- 「リスナーとルール」タブの中の「HTTP:80」を押します。
- 「ルールを追加する」ボタンを押し、リスナールールを作成します。条件を定義します。パス条件を
/*として、全てのリクエストに対してこのリスナールールを使用するように設定します。
- アクションから、「ターゲットグループへの転送」を選択し、ターゲットグループとして「quiz-tg」を選択します。そのほかはデフォルト設定で良いです。「次へ」で進みます。
- 優先度を 1 に設定します。「次へ」で進みます。さらに確認をして「ルールを追加する」ボタンを押して、ルールを追加します。
✅ ステップ17:Amazon EC2 用のセキュリティグループを編集する
EC2 は、ALB からの通信を許可しなければなりません。以前作成した EC2 用のセキュリティグループを編集して、ALB からのインバウンドルールを許可しましょう。
- 左のメニュータブから「セキュリティグループ」を押します。「quiz-instance-sg」をクリックします。
- インバウンドルールを編集して、ALB 用のセキュリティグループ「alb-sg」からの HTTP プロトコルによるポート 80 への通信を許可します。

3. 「ルールを保存」ボタンから、セキュリティグループへの変更を保存しましょう。
✅ ステップ18:API Gateway 側で CORS の設定をする
- マネジメントコンソール左上の検索タブで「API」と検索して、API Gateway のページを開きます。「API」から作成済みの API の一覧を表示し、「quiz-app」を選択します。

- 左のメニュータブから、CORS を選択します。設定を押して編集を開始します。
- Access-Control-Allow-Origin に ALB のドメイン名を入力します。Access-Control-Allow-Headers には、「content-type」を設定します。Access-Control-Allow-Methods には、「GET」および「POST」を設定します。
- 「保存」を押して、設定を保存しましょう。
✅ ステップ19:ブラウザからアプリケーションへアクセスして自作アプリで遊んでみよう
- Application Load Balancer のドメイン名にブラウザを経由してアクセスします。
- 実際にゲームを何度か遊んでみましょう。ランキングが逐一更新されるのがわかると思います。
🧹 片付け(リソース削除)
以下のリソースを削除していきましょう。
- ALB「quiz-app」
- ターゲットグループ「quiz-tg」
- EC2 インスタンス「quiz-instance-1」「quiz-instance-2」
- セキュリティグループ「alb-sg」「quiz-instance-sg」
- API Gateway「quiz-api」
- Lambda 関数「get-questions」「post-answer」「get-ranking」
- DynamoDB テーブル「Questions」「QuizResults」
- NAT Gateway「quiz-app-nat-public-ap-northeast-1a」
- Elastic IP「quiz-app-eip-ap-northeast-1a」(NAT Gateway の削除が完了するまで待つ必要があります。)
- VPC「quiz-app-vpc」(サブネット、インターネットゲートウェイもこれと同時に削除されます。)
- IAM ロール「get-questions-role-...」「post-answer-role...」「get-ranking-role...」「quiz-instance-role」
- CloudWatch Logs「/aws/lambda/get-questions」「/aws/lambda/post-answer」「/aws/lambda/get-ranking」
🏁 おつかれさまでした!
この問題では、Application Load Balancer と Amazon API Gateway を使用して、セキュアな 3 層アーキテクチャ構造をもつ Web アプリケーションを作成しました。AWS が提供しているマネージドなサービスを有効活用することで、よりセキュアに運用コストも少なく、可用性のある Web アプリケーションを作成することができます。
AWS は AI サービスに関しても Amazon Bedrock や Amazon Rekognition と言ったさまざまなマネージドサービスを提供しており、これらをアプリケーションに統合することで、さらにインパクトのある面白いアプリケーションを作成することができます。思い思いのアイデアで、さらにアプリケーションを面白くしていきましょう。
また、API Gateway の WebSocket タイプを使用することで複数人で行うゲームを開発するなど、さらに複雑な機能の実装も可能になっていきます。AWS Managed Grafana などのサービスと統合することでログの一元管理などもできるようになります。次回の応用編では、このようなさらなる機能の開発にも挑戦してみましょう!











