仮想サーバを立てよう

このハンズオンでは、VPCとEC2を使った仮想サーバ構築について実際にハンズオン形式で手を動かしながら体験します。

  • VPCとサブネット(Public/Private)の作成
  • インターネットゲートウェイとNATゲートウェイの設定
  • ルートテーブルの設定
  • セキュリティグループによるアクセス制御
  • WebサーバとAPIサーバ用のEC2インスタンス作成
  • SSH接続とアプリケーションのデプロイ
  • Elastic IPの割り当て

1. 事前準備

この講座のハンズオンでは、以下のツールやアカウントが必要です。まだ準備できていない場合は、リンク先の手順に沿って準備をお願いします。

2. ハンズオンの概要

この講座では、VPCやEC2を用いて、簡単なWebアプリケーションが動作する仮想サーバを立てるハンズオンを実施します。

まず、仮想ネットワークであるVPCを作成し、その内部にPublic SubnetとPrivate Subnetを作成します。VPCにはインターネットゲートウェイをアタッチし、Public Subnetからインターネットへの通信経路を設定します。

Public SubnetにはWebサーバを配置します。このサーバには、Nginxを使ってシンプルなHTMLページを配信し、APIサーバへのリバースプロキシも設定します。これらの環境構築は、シェルスクリプトを作成して自動実行するため、手動での作業は不要です。

Private SubnetにはAPIサーバを配置します。これは、Webサーバからのリクエストを受け付け、結果を返すバックエンドとして機能します。こちらも同様にシェルスクリプトを用いて構築します。

また、APIサーバがアプリケーションのインストール等で一時的にインターネット接続を行う必要があるため、NATゲートウェイも併せて構築します。

3. VPCの作成

3.1 VPCを作成

最初のステップとしてVPCの構築を行います。VPC(Virtual Private Cloud)は、AWS上に作成する仮想ネットワークであり、EC2インスタンスやRDSなどのリソースを配置するための土台となります。VPCを作成することで、独自のIPアドレス範囲を持つ隔離されたネットワーク環境を構築でき、セキュリティやネットワーク構成を自由に設計できます。

AWSマネジメントコンソールを開き、検索ボックスから「VPC」と入力してVPCダッシュボードを開きます。 alt text

左側のメニューから「お使いのVPC」を選択し、画面右上の「VPCを作成」ボタンをクリックしてください。

VPCの設定項目として、以下の項目を設定します。

設定項目 設定の基準
作成するリソース VPCのみ 今回は関連リソースを自動作成せず、個別に作成したいため
名前タグ my-vpc リソースを識別しやすくするため
IPv4 CIDR ブロック 10.0.0.0/16 約65,000個のIPアドレスを確保でき、複数のサブネットを作成するのに十分な範囲のため
IPv6 CIDR ブロック IPv6 CIDR ブロックなし 今回はIPv4のみで構成するため
テナンシー デフォルト 専用ハードウェアは不要で、コストを抑えるため
VPC 暗号化コントロール ($) なし 今回は暗号化の要件が不要なため

入力内容を確認し、「VPCを作成」ボタンをクリックしてください。

なお、/16のCIDRブロックで65,536個のIPアドレスが使えるという仕様は、VPC CIDR blocks(AWS公式ドキュメント)に「a /16 netmask (65,536 IP addresses)」と明記されています。

my-vpcが作成されれば完了です。

4. サブネットの作成

4.1 パブリックサブネット(Web用)を作成

続いて、サブネットの作成を行います。サブネットはVPC内のIPアドレス範囲を論理的に分割したもので、リソースの配置場所を決定します。今回は、インターネットからアクセス可能な「パブリックサブネット」にWebサーバを配置し、外部から直接アクセスできないようにする「プライベートサブネット」にAPIサーバを配置することで、セキュリティを高めた構成を実現します。

VPCダッシュボードの左メニューから「サブネット」を選択し、画面右上の「サブネットを作成」ボタンをクリックしてください。

設定画面が表示されたら、VPC IDでmy-vpcを選択します。

以下の詳細設定を行います。

設定項目 設定の基準
サブネット名 web-subnet Webサーバ用のサブネットであることを識別するため
アベイラビリティゾーン ap-northeast-1a 東京リージョンのAZを指定。今回は単一AZ構成のため任意のAZを選択
IPv4 CIDR ブロック 10.0.1.0/24 VPCの範囲内で254個のIPアドレスを確保。Webサーバ用に十分な数

入力が完了したら「サブネットを作成」ボタンをクリックします。

なお、/24のサブネットでは256個のIPアドレスのうち先頭4つと末尾1つの合計5つがAWSによって予約されており、実際に割り当てられるのは251個になります。詳しい仕様はSubnet CIDR blocks(AWS公式ドキュメント)に記載があります。

web-subnetが作成されれば完了です。

4.2 プライベートサブネット(API用)を作成

同様の手順でもう一つのサブネットを作成します。「サブネットを作成」ボタンをクリックし、VPC IDはmy-vpcを選択します。

設定項目 設定の基準
サブネット名 api-subnet APIサーバ用のサブネットであることを識別するため
アベイラビリティゾーン ap-northeast-1a Webサーバと同じAZに配置し、低遅延な通信を実現するため
IPv4 CIDR ブロック 10.0.2.0/24 VPCの範囲内でWebサブネットと重複しない範囲を指定

設定を確認し「サブネットを作成」をクリックします。 alt text

api-subnetが作成されれば完了です。 alt text

4.3 パブリックサブネットの設定変更

Webサーバをインターネットからアクセス可能にするために、パブリックサブネットに配置するEC2インスタンスに自動でパブリックIPアドレスが割り当てられるよう設定を変更します。この設定を行わないと、サブネット内のインスタンスにはプライベートIPアドレスのみが割り当てられ、インターネットから直接アクセスできません。

サブネット一覧からweb-subnetを選択し、画面上部の「アクション」メニューから「サブネットの設定を編集」を選択します。

設定画面が表示されたら、「パブリック IPv4 アドレスの自動割り当てを有効にする」にチェックを入れ、「保存」ボタンをクリックしてください。

これにより、Webサーバにインターネットからアクセス可能なIPアドレスが自動で割り当てられます。

💡 ポイント
api-subnetは外部に公開しないプライベート環境のため、この設定は行いません。

5. インターネットゲートウェイの作成

5.1 インターネットゲートウェイを作成

インターネットゲートウェイは、VPC内のリソースがインターネットと通信するための出入り口です。パブリックサブネットに配置されたEC2インスタンスが外部のユーザからのHTTPリクエストを受け付けたり、必要なソフトウェアをダウンロードしたりするために必要となります。インターネットゲートウェイがないと、VPC内のリソースはインターネットと通信できません。

VPCダッシュボードの左メニューから「インターネットゲートウェイ」を選択し、画面右上の「インターネットゲートウェイの作成」ボタンをクリックしてください。

設定画面が表示されたら、名前タグにmy-internet-gatewayと入力し、「インターネットゲートウェイの作成」ボタンをクリックします。

my-internet-gatewayが作成されれば成功です。

5.2 VPCにアタッチ

インターネットゲートウェイは作成しただけでは機能しません。VPCにアタッチ(接続)することで初めて利用可能になります。

画面上部の「アクション」メニューから「VPCにアタッチ」を選択します。

使用可能なVPCの一覧からmy-vpcを選択し、「インターネットゲートウェイのアタッチ」ボタンをクリックしてください。

無事にmy-vpcがアタッチされていればここまでは完了です。 alt text

6. NATゲートウェイの作成

NATゲートウェイは、プライベートサブネット内のリソースがインターネットにアクセスするために必要なコンポーネントです。今回のAPIサーバはプライベートサブネットに配置されるため、直接インターネットと通信できません。しかし、アプリケーションのインストールやソフトウェアのアップデートなど、外部への通信が必要な場面があります。NATゲートウェイを使うことで、プライベートサブネットからインターネットへの「発信」のみを許可し、外部からの「着信」は遮断するという、セキュアな構成を実現できます。

6.1 Elastic IPを割り当て(NAT用)

NATゲートウェイには固定のIPアドレス(Elastic IP)が必要です。まずはElastic IPを取得します。

VPCダッシュボードの左メニューから「Elastic IP」を選択し、画面右上の「Elastic IP アドレスを割り振る」ボタンをクリックしてください。

設定画面が表示されたら、タグにキーName、値my-natgateway-eipを設定し、「割り振る」ボタンをクリックします。

無事にmy-nat-gatgateway-eipが作成されていれば、ここまでは成功です。

6.2 NATゲートウェイを作成

続いて、NATゲートウェイを作成します。VPCダッシュボードの左メニューから「NATゲートウェイ」を選択し、画面右上の「NATゲートウェイを作成」ボタンをクリックしてください。

設定画面が表示されたら、以下の内容を入力します。

設定項目 設定の基準
名前 my-natgateway NATゲートウェイであることを識別するため
アベイラビリティーモード ゾーナル リージョナルはコストが高いため、単一AZで動作するゾーナルを採用
サブネット web-subnet NATゲートウェイはパブリックサブネットに配置する必要があるため
接続タイプ パブリック インターネットへの通信を可能にするため
Elastic IP 割り当て ID my-natgateway-eip 先ほど作成した固定IPアドレスを使用するため

すべての設定が完了したら、「NATゲートウェイを作成」ボタンをクリックしてください。

無事にmy-natgatewayが作成されますが、最初は状態がPendingとなっています。

時間経過により状態がAvailableになることを確認します。

💡 ポイント
「リージョナル」はVPC全体に自動展開されますがコストが高いため、今回は「ゾーナル」を採用します。NATゲートウェイはパブリックサブネットに配置する必要があります。

7. ルートテーブルの作成

ルートテーブルは、サブネット内のリソースがどこに通信するかを制御するネットワークの「道案内」です。インターネットゲートウェイやNATゲートウェイを作成しただけでは、サブネット内のリソースはそれらを経由して通信できません。ルートテーブルに適切なルート(経路)を設定し、サブネットに関連付けることで初めて通信が可能になります。

7.1 パブリックサブネットのルートテーブル設定

パブリックルートテーブルを作成

まず、パブリックサブネット(Webサーバ用)のルートテーブルを作成します。このルートテーブルには、インターネットへの通信経路を設定し、Webサーバがインターネットと直接通信できるようにします。

VPCダッシュボードの左メニューから「ルートテーブル」を選択し、画面右上の「ルートテーブルを作成」ボタンをクリックしてください。

設定画面が表示されたら、名前にweb-route-tableと入力し、VPCはmy-vpcを選択して、「ルートテーブルを作成」ボタンをクリックします。

無事にweb-route-tableが作成されることを確認します。

パブリックルートテーブルにルートを追加

作成したルートテーブルに、インターネットへの通信経路を設定します。

一覧から「web-route-table」を選択した状態で、画面下部の「ルート」タブにある「ルートを編集」ボタンをクリックします。

さらに「ルートを追加」を押してください。

新しい行の「送信先」には 0.0.0.0/0 と入力し、「ターゲット」の欄では「インターネットゲートウェイ」を選択して、先ほど作成した「my-internet-gateway」を指定します。

設定ができたら、右下の「変更を保存」をクリックして完了です。

ルートにインターネットゲートウェイへの通信が追加されていれば、ここまでの操作は完了です。

💡 ポイント
ルートに指定した0.0.0.0/0は「すべての通信」を表します。

パブリックルートテーブルにサブネットを関連付け

次に、このルートテーブルをサブネットに関連付けます。

「サブネットの関連付け」というタブに切り替え、「サブネットの関連付けを編集」をクリックしてください。

サブネットの一覧が表示されますので、web-subnetを見つけてチェックボックスにチェックを入れます。

選択できたら、「関連付けを保存」をクリックして設定を完了させます。

サブネットの関連付けにweb-subnetが設定されていれば、ここまでの操作は完了です。

7.2 プライベートサブネットのルートテーブル設定

続いて、プライベートサブネット用のルートテーブルを作成し、設定していきます。先程と同様の操作の部分は、スクリーンショットを省略しています。

プライベートルートテーブルを作成

「ルートテーブルを作成」ボタンをクリックしてください。

名前にはapi-route-tableと入力し、VPCはmy-vpcを選択します。

設定できたら、「ルートテーブルを作成」をクリックします。

無事にapi-route-tableが作成されることを確認します。

プライベートルートテーブルにルートを追加

プライベートネットワークから外部への通信をNATゲートウェイ経由にする設定を行います。

一覧から「api-route-table」を選択し、「ルート」タブから「ルートを編集」をクリックします。

続いて「ルートを追加」をクリックします。

追加された行の「送信先」には 0.0.0.0/0 を入力し、「ターゲット」では「NATゲートウェイ」を選択して、先ほど作成した「my-natgateway」を指定します。

これにより、プライベートサブネットからの通信がNATゲートウェイを通るようになります。最後に「変更を保存」をクリックしてください。

無事にNATゲートウェイへのルートが追加されていることを確認します。

プライベートルートテーブルにサブネットを関連付け

最後に、このルートテーブルをAPI用のプライベートサブネットに関連付けます。「サブネットの関連付け」タブに切り替えて、「サブネットの関連付けを編集」をクリックしてください。

表示された一覧から「api-subnet」を探し、チェックボックスにチェックを入れます。

これによりAPIサーバは、NATゲートウェイを経由して安全にインターネットへアクセスできるようになります。「関連付けを保存」をクリックして設定を完了しましょう。

無事にapi-subnetへのサブネットの関連付けができていることを確認します。

8. セキュリティグループの作成

次はセキュリティグループの作成です。セキュリティグループはEC2インスタンスに関連付ける形で利用しますが、事前にリソースだけ作成していきます。

8.1 Webサーバ用セキュリティグループを作成

まずは、Webサーバ用のセキュリティグループを作成します。このセキュリティグループには、Webサイトを外部から参照するためのインターネットからのHTTP通信によるアクセスと、メンテナンスのためのSSH接続を許可します。

EC2の管理画面左側のメニューから「セキュリティグループ」を選び、右上の「セキュリティグループを作成」をクリックしてください。

セキュリティグループの設定を行います。まずは「基本的な詳細」の部分を入力します。

設定項目 設定の基準
セキュリティグループ名 web-sg Webサーバ用であることを識別するため
説明 Security group for web server セキュリティグループの用途を明記するため
VPC my-vpc 作成したVPC内のリソースに適用するため

続いてインバウンドルールの設定です。「ルールを追加」をクリックし、以下の2つのルールを追加します。

タイプ ポート ソース 設定の基準
HTTP 80 0.0.0.0/0 インターネットからのWebアクセスを許可するため
SSH 22 0.0.0.0/0 ローカルPCからSSH接続でサーバ管理を行うため

💡 ポイント
「送信元が 0.0.0.0/0 のルールを指定すると、すべての IP アドレスからインスタンスにアクセスすることが許可されます」という警告が表示されますが、今回はWebサーバとして世界中からのHTTPアクセスを受け付ける必要があるため、この設定で問題ありません。 なお、SSHについては本来、社内ネットワークや担当者のIPアドレスに限定することがセキュリティ上望ましいですが、今回は学習目的のため省略しています。本番環境では、SSHの送信元を特定のIPアドレスに制限するか、AWS Systems Manager セッションマネージャの利用を検討してください。

アウトバウンドルールについては、デフォルトで「すべてのトラフィック」が許可されているはずですので、そのままで構いません。

💡 ポイント
「宛先が 0.0.0.0/0 のルールでは、インスタンスは任意のIPアドレスにトラフィックを送信できます」という警告が表示されますが、今回は学習目的であり、この設定で問題ありません。なお、アウトバウンドルールは本番環境でも制限しないケースが多く、外部APIへのアクセスやソフトウェアのアップデートなど、様々な宛先への通信が必要になるためです。

設定が終わりましたら、画面下の「セキュリティグループを作成」をクリックして完了です。

無事にweb-sgが作成されれば、ここまでの操作は完了です。

8.2 APIサーバ用セキュリティグループを作成

続いて、APIサーバ用のセキュリティグループも作成します。API用のセキュリティグループでは、webサーバ(web-sg)からの8080ポート通信、およびSSH通信のみを許可し、安全性を確保します。

もう一度「セキュリティグループを作成」ボタンを押してください。

「基本的な詳細」は下記を指定します。

設定項目 設定の基準
セキュリティグループ名 api-sg APIサーバ用であることを識別するため
説明 Security group for API server セキュリティグループの用途を明記するため
VPC my-vpc 作成したVPC内のリソースに適用するため

次にインバウンドルールの設定です。

タイプ ポート ソース 設定の基準
カスタムTCP 8080 web-sg Webサーバからのみ APIリクエストを受け付け、外部からの直接アクセスを防ぐため
SSH 22 web-sg Webサーバを踏み台としたSSH接続のみを許可し、セキュリティを高めるため

アウトバウンドルールは変更せず、最後に「セキュリティグループを作成」をクリックして完了です。

無事にセキュリティグループが作成されれば、ここまでの操作は完了です。

9. EC2インスタンスの作成

それでは、EC2インスタンスを作成していきます。

9.1 Webサーバを作成

まずは、WebサーバとなるEC2インスタンスを作成していきます。

EC2インスタンスの作成

EC2のダッシュボードを開きます。

左側のメニューから「インスタンス」をクリックしたうえで、「インスタンスを起動」をクリックします。

まずは、「名前とタグ」の部分にweb-serverと名前をつけます。

「アプリケーションおよび OS イメージ」の部分で、「インスタンスタイプ」にはAmazon Linux 2023 AMIを選択します。これはAWS公式の最新Linuxで、セキュリティパッチが適用済みで安定しているものとなります。

インスタンスタイプですが、t3.microを指定します。 学習用途には十分なスペックで、無料利用枠の対象でコストを抑えらます。

キーペアですが、すでに何らかのキーペアを作成済みの場合は、そのキーペアを選択してください。キーペアを作っていない方は、ここで新しいキーペアを作って行きましょう。

💡 ポイント
キーペアを新規作成すると、秘密鍵ファイル(.pemファイル)が自動的にダウンロードされます。このファイルは必ず安全な場所に保存してください。秘密鍵はこのタイミングでしかダウンロードできず、紛失するとEC2インスタンスにSSH接続できなくなります。再発行もできないため、その場合はインスタンスを作り直す必要があります。

続いて「ネットワーク設定」の部分は、下記のように入力していきます。

設定項目 設定の基準
VPC my-vpc 作成したVPC内にインスタンスを配置するため
サブネット my-web-subnet インターネットからアクセス可能なパブリックサブネットに配置するため
パブリックIPの自動割り当て 有効化 インターネットからWebサーバにアクセスできるようにするため
セキュリティグループ web-sg HTTP/SSHアクセスを許可するWeb用のルールを適用するため

それ以降の項目はデフォルトで構いません。

入力が完了したら、「インスタンスを起動」をクリックします。

インスタンスの起動が成功することを確認します。

インスタンスが起動されたら、パブリックIPアドレスの値を控えておいてください。後ほど必要になってきます。

EC2インスタンスへの接続

続いて、先程作成したEC2インスタンスに接続ができるか、確認しておきたいと思います。

Windowsの場合はコマンドプロンプト、Macの場合はターミナルを開きます。

まず、今回はキーペアを利用して接続を行います。そのため、キーペアが存在するフォルダにcdコマンドで移動します。下記コマンドで、<キーペアを保存したフォルダ>は、先程キーペアを保存したフォルダのパスに置き換えてください。

cd <キーペアを保存したフォルダ>

続いて、キーペアを用いてssh接続していきます。下記のコマンドで、EC2インスタンスに接続していきます。<キーペアのファイル名>は、キーペアのファイル名(例:my-key.pemなど)に置き換えてください。<WebサーバのパブリックIPアドレス>はWebサーバのEC2インスタンスのパブリックIPアドレスを確認し、それを指定してください。

Windowsの場合

ssh -i .\<キーペアのファイル名> ec2-user@<WebサーバのパブリックIPアドレス>

Macの場合

ssh -i ./<キーペアのファイル名> ec2-user@<WebサーバのパブリックIPアドレス>

以下のようなメッセージが表示される可能性があります。これは「初めて接続するサーバですが問題ないですか?」という確認のため、問題なければ「yes」と入力してください。

$ ssh -i ./my-key.pem ec2-user@54.95.195.203
The authenticity of host '54.95.195.203 (54.95.195.203)' can't be established.
ED25519 key fingerprint is SHA256:HUUODXtinQnGaCjOA8f8qd1VJhPZYu62OXtN6Gmzid8.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])?

MacやWindowsで、以下のようなエラーが発生する可能性があります。これは、キーペアのファイルの権限設定が適切でないというエラーです。

Warning: Permanently added '54.95.195.203' (ED25519) to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for './my-key.pem' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "./my-key.pem": bad permissions
ec2-user@54.95.195.203: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

この場合、下記のコマンドで適切な権限を付与する必要があります。

Macの場合

chmod 400 ./my-key.pem

Windowsの場合

PowerShellで以下のコマンドを実行してください。<キーペアのファイル名>は実際のファイル名に置き換えてください。

icacls .\<キーペアのファイル名> /inheritance:r /grant:r "$($env:USERNAME):(R)"

以下のような待受画面になれば、ここまでの操作は完了です。

$ ssh -i ./my-key.pem ec2-user@54.95.195.203
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-10-0-1-237 ~]$

exitを入力し、一度EC2からログアウトしておいてください。

exit

以下のメッセージが表示されれば、無事ログアウトされています。

logout
Connection to 54.95.195.203 closed.

9.2 APIサーバを作成

EC2インスタンスの作成

続いて、APIサーバのEC2インスタンスを起動します。「インスタンスを起動」ボタンをクリックしてください。

設定値は以下の通り入力してください。

設定項目 設定の基準
名前 api-server APIサーバであることを識別するため
AMI Amazon Linux 2023 AMI Webサーバと同じ環境で統一し、運用を簡素化するため
インスタンスタイプ t3.micro 学習用途には十分なスペック。無料利用枠の対象
キーペア Webサーバと同じもの 同一のキーペアで両サーバにアクセスできるようにするため
VPC my-vpc Webサーバと同じVPC内に配置し、内部通信を可能にするため
サブネット api-subnet インターネットから直接アクセスさせないプライベートサブネットに配置するため
パブリックIPの自動割り当て 無効 外部からの直接アクセスは不要で、セキュリティを高めるため
セキュリティグループ api-sg Webサーバからの通信のみを許可するAPI用のルールを適用するため

入力が完了したら、「インスタンスを起動」をクリックして作成を開始します。

無事にEC2インスタンスが起動することを確認します。

作成後、インスタンスの詳細画面に表示される「プライベートIPアドレス」を必ずメモしておいてください。次のWebサーバの設定で必要になります。

EC2インスタンスへの接続

続いて、APIサーバのEC2インスタンスに接続します。

APIサーバはPrivate Subnetに配置されているため、ローカル環境から直接アクセスすることはできません。そのため、WebサーバのEC2インスタンスを踏み台として経由し、接続を行います。

具体的には、Webサーバに秘密鍵(キーペアファイル)を転送し、その鍵を使用してAPIサーバへ接続します。

💡 ポイント
実際の運用ではWebサーバ上に直接キーペアファイルを配置する方法はセキュリティリスクを伴うため、AWS Systems Manager セッションマネージャなどの利用が推奨されます。今回は学習手順の一環として、この方法を採用します。

まずは、キーペアファイルをWebサーバに転送します。サーバへの転送は、scpコマンドを用いて行います。以下のコマンドを実行し、キーペアファイルの転送を実施してください。

Windowsの場合

scp -i .\<キーペアのファイル名> .\<キーペアのファイル名> ec2-user@<WebサーバのパブリックIPアドレス>:/home/ec2-user/

Macの場合

scp -i ./<キーペアのファイル名> ./<キーペアのファイル名> ec2-user@<WebサーバのパブリックIPアドレス>:/home/ec2-user/

続いて、以下のコマンドでWebサーバへのログインを行います。

Windowsの場合

ssh -i .\<キーペアのファイル名> ec2-user@<WebサーバのパブリックIPアドレス>

Macの場合

ssh -i ./<キーペアのファイル名> ec2-user@<WebサーバのパブリックIPアドレス>

続いて、APIサーバへの接続を行います。以下のコマンドで、APIサーバにアクセスします。

ssh -i ./my-key.pem ec2-user@<APIサーバのプライベートIPアドレス>

以下のような待受画面になれば、接続成功です。

The authenticity of host '10.0.2.211 (10.0.2.211)' can't be established.
ED25519 key fingerprint is SHA256:9TTjGRLoG6My/EJYCDSy0YZIkXr67K2ZAb4cPJkd46s.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.0.2.211' (ED25519) to the list of known hosts.
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-10-0-2-211 ~]$

確認が終わったら、exitコマンドでログアウトしてください。

10. Webサーバの環境構築

10.1 シェルの作成と実行

続いて、Webサーバの環境構築として、必要なアプリケーションのインストールを行います。

今回は、環境構築用のシェルスクリプトを作成し、それをEC2インスタンスに転送・実行する手順をとります。

スクリプトの詳細は省略しますが、WebサーバソフトウェアであるNginxのインストール、HTMLファイルの配置、そしてAPIサーバへのリバースプロキシの設定を自動で行います。

キーペアを保存したフォルダに、web-setup.shというファイルを作成します。なお、<api_server_private_ip>については、APIサーバのプライベートIPアドレスに置き換えてください。

web-setup.sh  ← このファイルを作成

作成したファイルに以下の内容を記述して保存します。

#!/bin/bash
set -e

#############################################
# 設定項目 (ここを書き換えてください)
#############################################
# 例: API_SERVER_IP="10.0.2.100"
API_SERVER_IP="<api_server_private_ip>"
#############################################

# 1. System Update
echo "Start: System Update..."
dnf update -y

# 2. Install Nginx
echo "Start: Install Nginx..."
dnf install -y nginx

# 3. Start Nginx
systemctl start nginx
systemctl enable nginx

# 4. Create HTML
echo "Start: Create HTML..."
cat > /usr/share/nginx/html/index.html << 'HTMLEOF'
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>API Connection Test</title>
</head>
<body>
    <h1>API接続テスト</h1>
    <button onclick="testApi()">API接続テスト</button>
    <p id="result"></p>
    <script>
    function testApi() {
        fetch('/api/health')
            .then(res => res.json())
            .then(data => {
                document.getElementById('result').textContent = data.message;
            })
            .catch(err => {
                document.getElementById('result').textContent = 'エラー: ' + err.message;
            });
    }
    </script>
</body>
</html>
HTMLEOF

# 5. Configure Nginx (Reverse Proxy)
echo "Start: Configure Nginx..."
cat > /etc/nginx/conf.d/default.conf << EOF
server {
    listen 80;
    server_name _;

    # Frontend
    location / {
        root /usr/share/nginx/html;
        index index.html;
    }

    # Backend Proxy
    location /api/ {
        proxy_pass http://$API_SERVER_IP:8080/api/;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
    }
}
EOF

# 6. Set Permissions & Restart
echo "Start: Restart Nginx..."
chown -R nginx:nginx /usr/share/nginx/html
chmod -R 755 /usr/share/nginx/html
systemctl restart nginx

echo "Success: Web Server Setup Completed!"

続いて、このシェルをWebサーバに転送します。下記コマンドを実行してください。

<キーペアのファイル名>と<WebサーバのパブリックIP>は適切なものに置き換えてください。

Windowsの場合

scp -i .\<キーペアのファイル名> .\web-setup.sh ec2-user@<WebサーバのパブリックIP>:~/

Macの場合

scp -i ./<キーペアのファイル名> ./web-setup.sh ec2-user@<WebサーバのパブリックIP>:~/

続いて、WebサーバにSSH接続します。

Windowsの場合

ssh -i .\<キーペアのファイル名> ec2-user@<WebサーバのパブリックIP>

Macの場合

ssh -i ./<キーペアのファイル名> ec2-user@<WebサーバのパブリックIP>

転送したシェルを実行します。

sudo bash web-setup.sh

以下のような成功メッセージが表示されれば、ここまでの操作は完了です。

Success: Web Server Setup Completed!

exitをクリックして、WebサーバのEC2インスタンスからログアウトしておきます。

exit

10.2 動作確認

続いて、動作確認をします。

Webブラウザを開き http://<WebサーバのパブリックIPアドレス> にアクセスしてみてください。

「API接続テスト」ボタンが表示されたページが表示されればここまでの操作は完了です。なお、まだAPIサーバを構築していないため、ボタンをクリックするとエラーとなります。

11. APIサーバの環境構築

続いて、APIサーバの環境構築を行っていきます。こちらもWebサーバと同様、シェルを用意してそれを実行することで環境構築していきます。

ローカル環境で、キーペアを保存したフォルダに、api-setup.shというファイルを作成します。

web-setup.sh
api-setup.sh  ← このファイルを作成

作成したファイルに以下の内容を記述して保存します。

#!/bin/bash
set -e

# 1. Update system
echo "Start: System Update..."
dnf update -y

# 2. Install Go
echo "Start: Install Go..."
dnf install -y golang

# 3. Set Environment Variables
export HOME=/root
export GOPATH=/root/go
export GOMODCACHE=/root/go/pkg/mod
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

# 4. Create Application
echo "Start: Create Application..."
mkdir -p /opt/api
cd /opt/api

cat > main.go << 'GOEOF'
package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)

type Response struct {
    Message string `json:"message"`
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
    result := Response{Message: "API接続に成功しました"}
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(result)
}

func main() {
    http.HandleFunc("/api/health", healthHandler)

    fmt.Println("Starting API server on port 8080...")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
GOEOF

# 5. Build Application
echo "Start: Go Mod Init & Build..."
go mod init api-server
go mod tidy
go build -o api-server main.go

# 6. Create Service
echo "Start: Create Systemd Service..."
cat > /etc/systemd/system/api-server.service << SERVICEEOF
[Unit]
Description=API Server
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/opt/api
ExecStart=/opt/api/api-server
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
SERVICEEOF

# 7. Start Service
echo "Start: Enable & Start Service..."
systemctl daemon-reload
systemctl enable api-server
systemctl start api-server

echo "Success: API Server Setup Completed!"

続いて、コマンド操作によりシェルの転送やログインを行っていきます。ここで使用するコマンドはこちらに記載しています。

api-setup.shをEC2インスタンスに転送していきます。まずは、踏み台となるWebサーバに転送します。

Windowsの場合

scp -i .\<キーペアのファイル名> .\api-setup.sh ec2-user@<WebサーバのパブリックIP>:~/

Macの場合

scp -i ./<キーペアのファイル名> ./api-setup.sh ec2-user@<WebサーバのパブリックIP>:~/

続いて、Webサーバにログインします。

Windowsの場合

ssh -i .\<キーペアのファイル名> ec2-user@<WebサーバのパブリックIP>

Macの場合

ssh -i ./<キーペアのファイル名> ec2-user@<WebサーバのパブリックIP>
💡 ポイント
ここから先のコマンドは、EC2インスタンス(Linux環境)にログインした状態で実行するため、お使いのPCがWindowsでもMacでも同じコマンドになります。

続いて、Webサーバにあるapi-setup.shを、APIサーバに転送します。

scp -i ./my-key.pem ./api-setup.sh ec2-user@<APIサーバのプライベートIP>:~/

続いて、APIサーバにログインします。

ssh -i ./my-key.pem ec2-user@<APIサーバのプライベートIP>

最後に、api-setup.shを実行し、APIサーバのセットアップを行っていきます。

sudo bash api-setup.sh

無事に実行が完了すれば、ここまでの操作はOKです。

Success: API Server Setup Completed!

11.1 動作確認

続いて、動作確認を行います。まず、EC2でAPIサーバにログインしている状態で、以下のコマンドにより、EC2の中でAPIが起動できるかを試してみます。

curl http://localhost:8080/api/health

以下のような結果が返ってくれば、成功です。

{"message":"API接続に成功しました"}

続いて、一度exitコマンドでAPIサーバから抜けて、Webサーバにログインされている状態にします。

その状態で、以下のcurlコマンドで、WebサーバからAPIサーバへの疎通がうまくいっているかを確認します。<APIサーバのプライベートIP>の部分は、実際のものに置き換えてください。

curl http://<APIサーバのプライベートIP>:8080/api/health

こちらも、以下のような結果が返ってくれば、無事にAPIが呼び出せています。

{"message":"API接続に成功しました"}

最後に、Webブラウザから http://<WebサーバのパブリックIPアドレス> にアクセスし、「API接続テスト」ボタンをクリックしてください。「API接続に成功しました」と表示されれば、画面からNginxのリバースプロキシを経由してAPIが呼び出せています。

12. Elastic IPの割り当て(Webサーバ用)

現在のWebサーバのパブリックIPアドレスは、サーバの再起動などを行うと変動してしまいます。これを固定化するために、Elastic IPアドレスを取得し、Webサーバに割り当てしてみます。

12.1 Elastic IPを作成

Webサーバに固定のIPアドレスを割り当てるための準備を行います。

VPCのダッシュボード左メニューから「Elastic IP」を選択し、右上にある「Elastic IP アドレスを割り振る」ボタンをクリックしてください。

💡 ポイント
Elastic IPのメニューはVPCとEC2の両方のダッシュボードに存在しますが、どちらも同じ機能です。

設定画面が表示されたら、どのリソース用か判別しやすくするためにタグを設定します。

「タグ」セクションで新しいタグを追加し、キーには「Name」、値には「web-eip」と入力してください。

入力が終わりましたら、右下の「割り振る」をクリックしてIPアドレスを取得します。

無事にweb-eipが作成されれば、ここまでの操作は完了です。

12.2 Webサーバに関連付け

取得した固定IPアドレスをWebサーバに紐付ける作業を行います。

一覧画面で、先ほど作成した「web-eip」を選択した状態で、「アクション」メニューから「Elastic IP アドレスの関連付け」をクリックしてください。

関連付けの設定画面に移りますので、リソースタイプは「インスタンス」が選択されていることを確認します。

インスタンスの検索欄をクリックし、候補の中から「web-server」を選択してください。

設定に間違いがないことを確認し、最後に右下の「関連付ける」ボタンをクリックして固定IP化の手順は完了です。

無事に関連付けが完了したら、ここまでの操作は完了です。

12.3 動作確認

Elastic IPでWebサーバにアクセスできるか、確認してみます。web-eipのIPアドレスを用いて http://<web-eipのIPアドレス> をブラウザにて実行してください。

「API接続テスト」ボタンが表示されたページが無事に表示されます。

念の為、「API接続テスト」ボタンをクリックし、「API接続に成功しました」と表示されることを確認してみましょう。

これで、Elastic IPを利用して無事にWebサーバにアクセスできていることが確認できました。

13. リソースの削除手順(完了後)

動作確認がすべて完了しましたら、不要なコストが発生しないよう、作成したリソースを削除していきましょう。削除には依存関係による正しい順序がありますので、手順通りに進めてください。

まずは「EC2インスタンス」です。作成した2台のインスタンスを選択し、両方とも「インスタンスを終了」させてください。

続いて「NATゲートウェイ」を削除します。これが残っていると高額な料金がかかりやすいため、忘れずに削除しましょう。

インスタンスが終了したら、次は「Elastic IP」です。Webサーバ用とNATゲートウェイ用の2つがありますが、両方とも「アドレスの解放」を行います。

⚠️ Elastic IPが解放できない場合
関連付けられているEC2インスタンスまたはNATゲートウェイの削除(終了)が完了しているか確認してください。リソースが関連付けられた状態ではElastic IPを解放できません。

最後に「VPC」自体を削除して、クリーンアップ作業は終了です。

💡 ポイント
VPCを削除すると、サブネット、ルートテーブル、セキュリティグループ、インターネットゲートウェイも一緒に削除されます。

14. まとめ

このハンズオンでは、VPCとEC2を使った仮想サーバの構築を体験しました。

  • VPCを作成し、仮想ネットワーク環境を構築した
  • パブリックサブネットプライベートサブネットを作成し、ネットワークを分離した
  • インターネットゲートウェイでVPCをインターネットに接続した
  • NATゲートウェイでプライベートサブネットからの外部通信を可能にした
  • ルートテーブルで通信経路を設定した
  • セキュリティグループでインバウンド・アウトバウンドのトラフィックを制御した
  • EC2インスタンスを作成し、WebサーバとAPIサーバを構築した
  • SSH接続でEC2インスタンスにアクセスし、環境構築を行った
  • Elastic IPでWebサーバに固定IPアドレスを割り当てた

15. 次のステップ

🎉 おめでとうございます!VPCとEC2を使って仮想サーバを立て、Webサーバを公開するところまで体験できました。

ここまでで学んだ内容は、AWSを使ううえでの基本中の基本です。ここから先は、より実践的な内容に進みます。

講座名 学べること
ELB講座 ロードバランサーで複数のEC2に負荷分散する方法
オートスケーリング講座 アクセス数に応じてEC2を自動増減する方法
冗長化構成を組み立てよう ELBとAuto Scalingを組み合わせた本格的なWebシステム構築
RDS講座 マネージドなMySQLデータベースの使い方
コンテンツ配信をしよう S3・CloudFront・Route53・ACMでHTTPS対応のWebサイトを公開

実務で通用するクラウドエンジニアを目指す方は、ぜひ次のステップに進んでみてください。