EC2にWebサーバを立て、ドメイン経由でアクセスする

# 概要
EC2にWebサーバを立て、ドメイン経由でアクセスできるように構築する手順の備忘録です。
2025年1月時点での情報となります。

想定する読者として、AWSの主要サービスの基本的な内容について理解されている方向けの内容となっております。
そのため基本的に手順のみ記載し、各設定項目の意味などは省略しております。






# 利用サービス
- AWS
  - VPC
  - EC2
  - Route 53
  - Lambda
  - EventBridge
- ドメイン取得サービス（今回はお名前.comを利用）





# 構成図
下記の構成を構築します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/5dfe8e9a-7df7-a434-c48a-6d5f3c6fd1bd.png)
- パブリックサブネットにEC2サーバを設置し、インターネットゲートウェイを通じてHTTPでアクセスする
- ドメインをお名前.comで取得し、Route 53に登録して名前解決する
- EC2インスタンス起動時にEventBridge経由でLambda Functionを呼び出し、Route53の名前解決用レコードを更新する






# 手順
## VPC作成
VPC→「VPCを作成」を押下し、VPC作成画面に遷移
「作成するリソース」で「VPCなど」を選択することにより、アベイラビリティゾーンやサブネット等を同時に作成可能

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/15634306-6b1a-31c5-ae2f-864ace23780d.png)

今回はデフォルトから以下の通り変更

|設定項目|デフォルト|設定値|
|---|---|---|
|名前タグの自動生成|自動生成ON<br>プロジェクト|自動生成ON<br><任意の値>|
|アベイラビリティゾーン (AZ) の数|2|1|
|パブリックサブネットの数|2|1|
|プライベートサブネットの数|2|0|
|VPC エンドポイント|S3ゲートウェイ|なし|

設定後、「VPCを作成」を押下し、処理が成功すればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/eb24d2d7-6a06-bba5-b469-3654b818cb34.png)





## EC2インスタンス作成
EC2→「インスタンスを起動」を押下し、インスタンス作成画面に遷移

:::note warn
Amazon マシンイメージとインスタンスタイプは種類によっては料金が発生する
今回は無料利用枠の対象の「Amazon Linux 2023 AMI」と「t2.micro」を選択
:::

「名前とタグ」に任意の値を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/b58959ed-2b2b-a42f-9108-b8935cd17c40.png)





#### キーペア設定
「キーペア (ログイン) 」の「新しいキーペアを作成」を押下し、「キーペア名」に任意の値を入力して「キーペアを作成」を押下
作成後、 `.pem` ファイルがダウンロードされるので任意の場所に保管
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/29a2cd7c-b324-50d9-2953-e381b75aa540.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/1ccb0f39-3697-7f5a-7233-4e774f7faf13.png)





#### ネットワーク設定
「ネットワーク設定」の「編集」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/5513b195-4d05-774f-b040-cc3a2fb64440.png)


デフォルトから以下の通り変更

|設定項目|デフォルト|設定値|
|---|---|---|
|VPC|<未選択>|<作成したVPC>|
|サブネット|<未選択>|<作成したサブネット>|
|パブリックIPの自動割り当て|無効化|有効化|
|セキュリティグループ名|launch-wizard-1|<任意の値>|

インバウンドセキュリティグループのルールを以下の通り変更

|ルール|タイプ|ソースタイプ|備考|
|---|---|---|---|
|1|ssh|自分のIP|最初から存在する|
|2|HTTP|自分のIP|「セキュリティグループルールを追加」押下で追加|

設定後、「インスタンスを起動」を押下し、処理が成功すればOK





## Apache導入
SSHでインスタンスに接続する（今回は Tera Term を利用）

:::note warn
EC2 Instance Connect にて接続する場合
セキュリティグループのインバウンドルールにて、
EC2 Instance Connect エンドポイントからの通信を許可する必要がある
（東京リージョンの場合は`com.amazonaws.ap-northeast-1.ec2-instance-connect`）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/f4fd6d60-a3da-748e-afba-8ee5cd629a2a.png)
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/eice-security-groups.html#resource-security-group-rules
:::

- **Host**: インスタンス起動時に割り当てられた「パブリック IPv4 アドレス」の値
- **User name**: ec2-user
- **Authentication methods**:
  「Use RSA/DSA/ECDSA key to log in」→保存した `.pem` ファイルを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/3b457041-9657-3a54-9407-9dfb3acf1bb1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/2d677287-370f-6d9d-c6b4-e7426a867a90.png)

「OK」を押下し、接続に成功することを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/0a826233-e823-0f2e-6d45-f4450ad16e7c.png)

Apache をインストール
```ssh
sudo yum install httpd -y
```

Apache を起動
```ssh
sudo systemctl start httpd
```

EC2起動時に Apache が自動起動するように設定
```ssh
sudo systemctl enable httpd.service
```

ブラウザから `http://{パブリック IPv4 アドレス}` にアクセスし、ページが表示されればOK

:::note warn
**HTTPS** ではなく **HTTP** で接続する必要がある
:::



## ドメイン取得
お名前.comのアカウントを作成
https://www.onamae.com/

希望のドメインを選択し、「次へ進む」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/df6dcb35-7af5-1b34-eaf2-9ed388b30d80.png)

今回はブログ・ホームページを選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/6e018dae-c26c-ab4f-acce-707f148ba7cb.png)

レンタルサーバーの「削除」を押下し「次へ」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/327be70c-2e65-781b-271d-0787eaa01f51.png)

料金を確認し、任意の支払い方法を選択して「申込む」を押下
今回は「その他の支払い方法はこちら」→「コンビニ」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/ad37b670-4182-c25c-a3d1-2049b3de19ff.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/2e1029f9-627e-d0ae-0e0e-3943884fefe8.png)

管理画面に戻り、「ご利用中のサービス」にドメインが表示されていればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/5b4511cd-4ddb-6f1b-bf85-d8b873590137.png)





## ドメイン設定
Route 53→左側メニューの「ホストゾーン」→「ホストゾーンの作成」を押下し、ホストゾーン作成画面に遷移
「ドメイン名」に取得したドメインを入力し、「ホストゾーンの作成」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/2869c950-6354-904c-3081-570daf1a46bf.png)

ホストゾーンが正常に作成されていることを確認
このとき、NSレコードの「値/トラフィックのルーティング先」の4つの値を控えておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/ca391cf7-74d2-7cdc-6dff-d3abdc164591.png)

「レコードを作成」を押下し、以下の通り入力して「レコードを作成」を押下
- **レコード名**: 未入力
- **レコードタイプ**: A
- **値**: インスタンス起動時に割り当てられた「パブリック IPv4 アドレス」の値

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/5e924ff3-d0ac-879a-37c5-8234cb5fab7f.png)

タイプがAのレコードが登録されていればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/e708b822-eb18-eb6d-c254-d04fb3d180e0.png)

お名前.comにて取得したドメインの詳細画面を開き、「ネームサーバーの変更」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/d420e011-68d9-1275-10dd-50e9b3fe71e8.png)

「2.ネームサーバーの選択」で「その他のサービス」タブを開く
ネームサーバー1～4に、先ほど控えておいた4つの値を入力し「確認」→「OK」を押下

:::note warn
AWSでは「ns-23.awsdns-02.com.」のように末尾が「.」となっているが、
お名前.comに登録時は除去する
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/19004cc5-248f-f806-9a9f-f1c9e7c7f762.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/d318ac64-664e-8961-3986-5c959c5f76c1.png)

ブラウザから `http://{ドメイン名}` にアクセスし、ページが表示されればOK





:::note info
ここまででドメイン経由でのWebページアクセスが可能となりました。
しかし、EC2インスタンスにElastic IPアドレスを持たせない場合の課題として、インスタンス起動ごとにパブリックIPアドレスが変更されるためRoute 53にAレコードを再登録する必要があります。
ここからは上記を自動化する手順について記載します。
:::





## Lambda Function作成
Lambda→「関数の作成」を押下し、インスタンス作成画面に遷移
各種情報入力後、「関数の作成」を押下（今回はPythonで作成）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/93e374cf-fa14-3173-ce60-7691ce75727e.png)






## EventBridge設定
Lambda→左側メニューの「ルール」→「ルールを作成」を押下し、ホストゾーン作成画面に遷移
以下の通り入力する
#### ルールの詳細を定義
- **ルールタイプ**: イベントパターンを持つルール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/42324b86-3cc9-860c-6cca-2b385836599b.png)

#### イベントパターンを構築
- **イベントソース**: AWS イベントまたは EventBridge パートナーイベント
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/eb4e2b35-1c83-4d8c-5dc5-b1dad96de0de.png)

- **作成のメソッド**: パターンフォームを使用する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/d9eb3542-e878-4e1b-a8e6-eb6072256778.png)

- **イベントソース**: AWS のサービス
- **AWS のサービス**: EC2
- **イベントタイプ**: EC2 Instance State-change Notification
- **イベントタイプの仕様 1**: 特定の状態
- **特定の状態**: running
- **イベントタイプの仕様 2**: 個別のインスタンス ID
- **個別のインスタンス ID**: 作成したEC2インスタンスのインスタンスID
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/923afee7-fe3a-ac33-9ebf-49110aceed2c.png)

#### ターゲットを選択
- **ターゲットタイプ**: AWS のサービス
- **ターゲットを選択**: Lambda 関数
- **関数**: 作成したLambda関数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/9292c707-2d4e-0c2a-4025-66d7d1a77475.png)

#### レビューと作成
入力内容を確認し、「ルールの作成」を押下





## Lambda Function設定
作成したLambda Functionの詳細画面を開く
「設定」タブにて以下の通り設定する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/93e374cf-fa14-3173-ce60-7691ce75727e.png)
#### 一般設定
- **タイムアウト**: 5分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/4ceb39a7-4530-ff72-c63c-77cddfb33e41.png)

#### アクセス制限
「ロール名」のリンクを押下→「許可を追加」から以下のポリシーをアタッチ
- AmazonEC2FullAccess
- AmazonRoute53FullAccess

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/42e28ee8-2c65-f632-8e7c-f0e020419c0c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/0403ae2d-59f6-115f-43d0-862b482a4dd8.png)

#### 環境変数
以下の環境変数を登録
- **DomainName**: 取得したドメイン名
- **HostedZoneId**: 作成したホストゾーンのホストゾーンID
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1532684/fc5b12a1-555b-7f00-8057-eb1df7858dca.png)





## Lambda Functionコーディング
作成したLambda Functionの詳細画面を開く
コードソースを以下の内容に変更してデプロイする

```python: lambda_function.py
import json
import os
import boto3
from datetime import datetime


def datetime_isoformat(o):
    if isinstance(o, datetime):
        return o.isoformat()


def lambda_handler(event, context):
    print("event:")
    print(json.dumps(event, default=datetime_isoformat))

    instance_id = event["detail"]["instance-id"]
    if event["detail"]["state"] == "running":
        action = "UPSERT"
    else:
        action = ""

    ec2 = boto3.client("ec2")
    ec2_data = ec2.describe_instances()

    reservations = ec2_data["Reservations"]
    for reservation in reservations:
        instances = reservation["Instances"]
        for instance in instances:
            if instance_id == instance["InstanceId"]:
                public_ip_address = instance["PublicIpAddress"]

    route53 = boto3.client("route53")
    change_batch = {
        "Changes": [
            {
                "Action": action,
                "ResourceRecordSet": {
                    "Name": os.environ.get("DomainName"),
                    "Type": "A",
                    "TTL": 300,
                    "ResourceRecords": [{"Value": public_ip_address}],
                },
            }
        ]
    }
    response = route53.change_resource_record_sets(
        HostedZoneId=os.environ.get("HostedZoneId"), ChangeBatch=change_batch
    )
    print("response:")
    print(json.dumps(response, default=datetime_isoformat))

    return "Success"
```

EC2インスタンスを起動し、以下を確認できればOK
- 作成したホストゾーンのAレコードの値が、インスタンス起動時に割り当てられた「パブリック IPv4 アドレス」の値で更新されていること
- ブラウザから `http://{ドメイン名}` にアクセスし、ページが表示されること