0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWSでWebサーバーとAPIサーバーを分離したVPC構成を作ってみた

0
Posted at

はじめに

この記事は個人の学習用として作成しています。記事の内容で間違いなどあればご指摘ください。

AWSのネットワークとEC2を理解するため、WebサーバーとAPIサーバーを別サブネットに配置した構成を作成した。

単にEC2を起動するのではなく、VPC、サブネット、ルートテーブル、Internet Gateway、NAT Gateway、Security Group、Nginxまで一通り設定し、ブラウザからAPIへ到達するところまで確認した。

今回の目的は「EC2を起動できる」だけではなく、ブラウザからの通信がどのAWSリソースを通り、最終的にAPIサーバーへ届くのかを理解すること。

作成した構成

Internet
   |
Internet Gateway
   |
Public Subnet 10.0.1.0/24
   |
Web Server EC2
Nginx
   |
   |  Private IP通信
   v
Private Subnet 10.0.2.0/24
   |
API Server EC2
:8080
   |
/api/health
  • VPC:WebサーバーとAPIサーバーを配置するネットワーク領域
  • Public Subnet:インターネットからアクセスされるWebサーバーを配置
  • Private Subnet:外部から直接アクセスさせないAPIサーバーを配置
  • Web Server:Nginxで画面配信とAPIへのリバースプロキシを担当
  • API Server:8080番ポートでAPIを公開
  • NAT Gateway:Private Subnetからインターネットへ出るための経路
  • Elastic IP:NAT Gatewayが利用する固定のグローバルIP
  • Security Group:Webサーバー、APIサーバー単位で通信を制御

作業全体の流れ

  • VPCを作成する
  • Public SubnetとPrivate Subnetを作成する
  • Internet GatewayをVPCへ接続する
  • Public Subnet用ルートテーブルを設定する
  • Elastic IPとNAT Gatewayを作成する
  • Private Subnet用ルートテーブルを設定する
  • Security Groupを作成する
  • Webサーバー用EC2をPublic Subnetに作成する
  • APIサーバー用EC2をPrivate Subnetに作成する
  • SSHでWebサーバーへ接続する
  • Webサーバー経由でAPIサーバーへ接続する
  • WebサーバーにNginxを設定する
  • APIサーバーを起動する
  • Web → API → ブラウザの順番で疎通確認を行う

1. VPCを作成する

目的

  • AWS上に今回のWebシステム専用のネットワーク領域を作る
  • サブネットやルーティング、Security Groupなどのネットワーク設定をVPC内で管理する

今回の構成では 10.0.0.0/16 のようなプライベートIPアドレス範囲を利用した。

学んだこと

  • CIDRはネットワークで使用できるIPアドレス範囲を表す
  • /24 の場合は256個のIPアドレスを持つ
  • AWSのサブネットでは5個のIPアドレスが予約されるため、/24 では251個を利用できる

2. Public Subnetを作成する

目的

インターネットからアクセスされるWebサーバーを配置するために作成した。

  • CIDR:10.0.1.0/24
  • Web Server EC2を配置
  • Internet Gatewayへの経路を持たせる

サブネットを作っただけではPublic Subnetにはならない。ルートテーブルに 0.0.0.0/0 → Internet Gateway を設定することで、インターネットへの経路を持つサブネットになる。

3. Private Subnetを作成する

目的

APIサーバーをインターネットへ直接公開しないために作成した。

  • CIDR:10.0.2.0/24
  • API Server EC2を配置
  • API ServerにはPublic IPを持たせない

WebサーバーからAPIサーバーへの通信には、APIサーバーのPrivate IPを利用した。

今回のAPI Serverは、

10.0.2.217:8080

で待ち受ける構成にした。

4. Internet Gatewayを設定する

目的

VPCとインターネットを接続するために作成した。

作成したInternet GatewayをVPCへアタッチし、Public Subnetのルートテーブルに次の経路を設定した。

  • 10.0.0.0/16 → local
  • 0.0.0.0/0 → Internet Gateway

local はVPC内部の通信に使用し、0.0.0.0/0 はそれ以外の宛先をInternet Gatewayへ送る設定になる。

5. Elastic IPとNAT Gatewayを作成する

NAT Gatewayを作成する目的

Private SubnetにあるAPIサーバーから、インターネットへ通信できるようにするために作成した。

APIサーバー自身を外部公開する必要はないが、OS更新やパッケージ取得では外部通信が必要になる。

API Server
   |
Private Subnet
   |
NAT Gateway
   |
Internet Gateway
   |
Internet

Elastic IPを関連付ける目的

NAT Gatewayがインターネットへ通信するときの固定グローバルIPとして利用する。

  • Elastic IPを取得する
  • Public SubnetにNAT Gatewayを作成する
  • NAT GatewayへElastic IPを割り当てる

NAT Gatewayは作成しているだけでも料金が発生する。学習終了後は削除漏れがないか確認する。

6. Private Subnetのルートを設定する

目的

Private Subnetから直接Internet Gatewayへ出さず、NAT Gateway経由で外部通信させる。

Private Subnetのルートテーブルでは次のように設定した。

  • 10.0.0.0/16 → local
  • 0.0.0.0/0 → NAT Gateway

これによりAPIサーバーからインターネットへの通信はできるが、インターネットからAPIサーバーへ直接接続する構成にはならない。

7. Security Groupを設定する

Web Server

Web Serverはブラウザからアクセスするため、HTTPと管理用SSHを許可した。

  • TCP 80:Webアクセス用
  • TCP 22:SSH接続用
  • SSHは可能な限り自分の接続元IPに限定する

API Server

API Serverの8080番ポートはWeb Serverからのみアクセス可能にする。

  • TCP 8080
  • 接続元:Web ServerのSecurity Group

API Serverの8080番を 0.0.0.0/0 に公開するのではなく、Web Serverからの通信だけを許可することで、サーバー間通信を必要な範囲に限定する。

8. EC2インスタンスを作成する

Web Server

Public SubnetにAmazon Linux 2023のEC2を作成した。

目的は次の2つ。

  • ブラウザへHTMLを返す
  • /api/ へのアクセスをPrivate SubnetのAPI Serverへ転送する

API Server

Private SubnetにEC2を作成した。

  • Public IPは持たせない
  • Web ServerからPrivate IPで接続する
  • 8080番ポートでAPIを起動する

これにより、インターネット利用者がAPI Serverへ直接アクセスせず、Web Serverを経由する構成にした。

9. SSHとSCPでサーバーへ接続する

SSH

MacからWeb Serverへ接続した。

ssh -i ./my-key.pem ec2-user@<Web ServerのPublic IP>
  • ssh:別サーバーへログインする
  • -i:認証に利用する秘密鍵を指定する
  • ec2-user:Amazon Linuxのログインユーザー

SCP

セットアップシェルをMacからWeb Serverへ転送した。

scp -i ./my-key.pem ./web-setup.sh ec2-user@<Web ServerのPublic IP>:/home/ec2-user/
  • scp:SSHを利用してファイルを転送する
  • 最初のパス:転送元
  • user@host:path:転送先

scp の転送元ファイルは、コマンドを実行している端末上に存在する必要がある。Mac上のファイルを送りたい場合は、EC2へログインした後ではなくMac側から実行する。

10. Web ServerにNginxを構築する

web-setup.sh をWeb Serverへ転送して実行した。

sudo bash ./web-setup.sh

sudo を利用した理由は、Nginxのインストール、/etc/nginx の編集、systemdによるサービス操作に管理者権限が必要になるため。

セットアップでは主に次の処理を行った。

  • dnf update -y:Amazon Linuxのパッケージを更新
  • dnf install -y nginx:Nginxをインストール
  • systemctl start nginx:Nginxを起動
  • systemctl enable nginx:OS起動時にNginxを自動起動
  • HTMLファイルを /usr/share/nginx/html に配置
  • Nginxのリバースプロキシを設定
  • Nginxを再起動

11. NginxからAPI Serverへ転送する

ブラウザから /api/ にアクセスされた場合、NginxからPrivate SubnetのAPI Serverへ転送する。

location /api/ {
    proxy_pass http://10.0.2.217:8080/api/;
}

通信の流れは次のようになる。

Browser
  |
HTTP :80
  v
Web Server / Nginx
  |
Private IP :8080
  v
API Server

フロント側では /api/health を呼び出し、API Serverが返したJSONを画面へ表示する構成にした。

12. 疎通確認を行う

障害箇所を切り分けるため、通信経路を一気に確認せず段階的に確認した。

API Server単体

API Server上で確認した。

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

結果:

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

API Server自身は正常に動作していることを確認できた。

Web ServerからAPI Server

Web ServerからPrivate IPへ直接アクセスして確認する。

curl http://10.0.2.217:8080/api/health

ここが成功すれば、Security GroupやVPC内通信まで正常と判断できる。

Nginx経由

Web Server上で次を確認する。

curl http://localhost/api/health

ここが成功すれば、Nginxのリバースプロキシ設定まで正常と判断できる。

ブラウザ

最後にWeb ServerのPublic IPへアクセスする。

http://<Web ServerのPublic IP>

API接続テストを実行し、ブラウザ → Nginx → API Serverまでの一連の通信を確認した。

Elastic IPでWebサーバにアクセスできるか確認してAPIの接続テストも完了した

elastic_ip_web_server_check_light.gif

ハンズオンでつまずいたところ

1. SCPの接続先を書き間違えた

誤ってユーザー名とIPアドレスを連結して入力した。

ec2-user52.xxx.xxx.xxx

正しくは @ が必要だった。

ec2-user@52.xxx.xxx.xxx

Could not resolve hostname が出た場合、まず接続先の書式を確認する。

2. SCPを実行する場所を間違えた

Web ServerへSSHした後に、

scp ./web-setup.sh ...

を実行したため、

No such file or directory

になった。

web-setup.sh はMacに存在していたため、一度Web Serverからログアウトし、Mac側からSCPを実行して解決した。

コマンド実行時に「今どのサーバーにいるのか」を意識する必要がある。プロンプト、pwd、hostname、ls を利用すると現在位置を確認しやすい。

3. Macで修正したシェルがEC2へ反映されていなかった

Mac上の web-setup.sh を修正したが、一度転送済みのEC2上のファイルは自動更新されなかった。

再度SCPを行い、

grep API_SERVER_IP ~/web-setup.sh

でEC2上のファイルが更新されていることを確認した。

4. API ServerのPrivate IPを設定していなかった

Nginxの設定に次のプレースホルダーが残っていた。

<api_server_private_ip>

そのため、

host not found in upstream

が発生し、Nginxが起動できなかった。

10.0.2.217 に変更してから、

sudo nginx -t

を実行し、設定ファイルの構文チェックが成功することを確認した。

5. ブラウザでJSON解析エラーが発生した

ブラウザでは、

Unexpected token '<'

というエラーが発生した。

フロント側はJSONを期待している一方、NginxなどがHTMLのエラーページを返している場合、HTMLの先頭文字 < をJSONとして解析してこのエラーになる。

原因調査では、ブラウザだけを見るのではなく、

  • API Server自身
  • Web Server → API Server
  • Nginx → API Server
  • Browser → Web Server

の順番で curl を利用して切り分けた。

6. Nginxの設定警告

nginx -t で次の警告が出た。

conflicting server name "_" on 0.0.0.0:80

構文チェック自体は成功しており起動できたが、同じ server_name _ を持つserverブロックが複数存在する可能性がある。

動作していることと設定が整理されていることは別なので、警告が残っている場合は /etc/nginx 配下の設定重複も確認する。

今回学んだこと

  • VPCはAWS上のネットワーク領域として利用する
  • Public / Private Subnetはルートテーブルの構成によって役割が変わる
  • Internet GatewayはVPCとインターネットを接続する
  • NAT GatewayはPrivate Subnetから外へ出る通信に利用する
  • Elastic IPはNAT Gatewayの固定グローバルIPとして利用できる
  • Web ServerとAPI Serverを別サブネットに分けることで直接公開する範囲を限定できる
  • Security Groupでは必要な通信だけを許可する
  • EC2間の通信ではPrivate IPを利用できる
  • Nginxをリバースプロキシとして利用し、WebとAPIを分離できる
  • SSHとSCPでは現在操作している端末と接続先を意識する
  • 障害調査では通信経路を段階的に切り分ける

考えたこと

今回の構成はネットワークとサーバー間通信を理解するための最小構成。実務では可用性、運用性、セキュリティを考えて構成を追加する必要がある。

  • Web Serverを直接公開する代わりにALBを入口にする
  • EC2を複数AZへ配置して単一障害点を減らす
  • API ServerをPrivate Subnetに維持し、外部から直接アクセスさせない
  • SSH用の秘密鍵をWeb Serverへ置く方法は学習用途に留める
  • 実務ではAWS Systems Manager Session Managerなどを利用し、秘密鍵をサーバーへ配布しない構成を検討する
  • NAT Gatewayはコストが発生するため、本当に必要な外部通信かを確認する
  • 学習後はEC2、NAT Gateway、Elastic IPなどの不要なリソースを削除する

まとめ

今回のハンズオンでは、EC2を起動するだけでなく、VPC内にPublic SubnetとPrivate Subnetを作成し、Web ServerとAPI Serverを分離した。

最も大きかった学びは、AWSの各サービスを単独で覚えるのではなく、

通信元
↓
ルート
↓
Security Group
↓
Web Server
↓
Nginx
↓
API Server

という通信経路として考えることだった。

設定ミスが発生した際も、エラーメッセージ、ls、grep、nginx -t、systemctl、curl を利用して一つずつ原因を切り分け、最終的にブラウザからPrivate SubnetのAPI Serverまで接続できることを確認した。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?