Let's Encrypt + EC2(Apache) + Route 53 + お名前.comで独自ドメイン環境を構築する 

こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。

前回、AWS Route53のPrivate Hosted Zoneを使ったVPC内限定のドメイン名でのサーバ管理環境を構築しました。

https://qiita.com/ohtsuka-shota/items/52acb30d36d81494a636

これだけでも充分な勉強になり、個人的には満足しているのですが、直近でLPIC 303 Securityを受験しようとしている身としては、Let's Encryptと呼ばれるWebサーバのお手軽SSL化を身に着けておきたいわけであります。

今回はPublic Hosted Zoneの環境を構築しつつ、Let's Encryptを同時に使ってSSL + 独自ドメインの環境を作っていきたいと思います。

# 環境イメージ
まず名前解決に関してのフローをイメージに起こしました。
イメージ上部のPCが一般ユーザと仮定し、イメージ左部のPCがデベロッパー（≒私）としています。
一般ユーザの通信経路をブルー、デベロッパーの通信経路をオレンジで表現しています。
![20240620から-ページ13.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/9a9cb69e-a90c-e9f4-7196-caf1812e8505.png)
### フローの詳細
1. ユーザーが「https:\//web.ohtsuka-aws.xyz」にアクセス。
2. DNSクエリが発生し、お名前.comのDNSサーバーに送信。
3. お名前.comのDNSサーバーがAWS Route 53のネームサーバー（NS）情報を返す。
4. AWS Route 53のPublic Hosted Zoneにクエリが送信され、Aレコードを参照。
5. Aレコードに記載されたIPアドレスをユーザーに返す。
6. ユーザーのブラウザが返されたIPアドレスを使ってWebサーバーに接続。

次に暗号化に関してのフローになりますが、こちらはEC2とLet’s Encryptのサーバでやり取りをして証明書を得て自動設定されているだけかと思いますので、省略します。
以下が公式サイトの解説になりそうです。

https://letsencrypt.org/ja/how-it-works/

# 手順
## EC2の設定①
まずCertbotをインストールしていきたいと思います。
通例ですと、Certbotをインストールする時はsnapdを使用するようなのですが、今回使っているAmazon Linux 2023はsnapdを使うことが出来ないようですので、pipを使ってインストールしていきたいと思います。
また、今回はApacheを使ってWebサーバを作ろうとしているので、certbot-apacheをインストールしていますが、nginxを使う場合はこの限りではありません為お気を付けください。certbot pluginsコマンドでapacheが出力されることを確認します。
```
[ec2-user@ip-192-168-3-38 ~]$ sudo su -
[root@ip-192-168-3-38 ~]# dnf update && dnf upgrade -y
[root@ip-192-168-3-38 ~]# dnf install -y python3 augeas-libs
[root@ip-192-168-3-38 ~]# python3 -V
Python 3.9.16
[root@ip-192-168-3-38 ~]# python3 -m venv /opt/certbot/
[root@ip-192-168-3-38 ~]# /opt/certbot/bin/pip install --upgrade pip
[root@ip-192-168-3-38 ~]# /opt/certbot/bin/pip install certbot certbot-apache
[root@ip-192-168-3-38 ~]# ln -s /opt/certbot/bin/certbot /usr/bin/certbot
[root@ip-192-168-3-38 ~]# certbot plugins
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* apache
Description: Apache Web Server plugin
Interfaces: Authenticator, Installer, Plugin
Entry point: EntryPoint(name='apache',
value='certbot_apache._internal.entrypoint:ENTRYPOINT', group='certbot.plugins')

* standalone
Description: Runs an HTTP server locally which serves the necessary validation
files under the /.well-known/acme-challenge/ request path. Suitable if there is
no HTTP server already running. HTTP challenge only (wildcards not supported).
Interfaces: Authenticator, Plugin
Entry point: EntryPoint(name='standalone',
value='certbot._internal.plugins.standalone:Authenticator',
group='certbot.plugins')

* webroot
Description: Saves the necessary validation files to a
.well-known/acme-challenge/ directory within the nominated webroot path. A
seperate HTTP server must be running and serving files from the webroot path.
HTTP challenge only (wildcards not supported).
Interfaces: Authenticator, Plugin
Entry point: EntryPoint(name='webroot',
value='certbot._internal.plugins.webroot:Authenticator',
group='certbot.plugins')
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[root@ip-192-168-3-38 ~]# certbot --version
certbot 2.11.0
```

この後にhttpdをインストールして起動等をしておきます。
このタイミングではまだhttpdがLoadedになっていますが気にしないでOKです。
```
[root@ip-192-168-3-38 ~]# dnf install -y httpd
[root@ip-192-168-3-38 ~]# systemctl start httpd
[root@ip-192-168-3-38 ~]# systemctl enable httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[root@ip-192-168-3-38 ~]# systemctl status httpd
● httpd.service - The Apache HTTP Server
     Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; preset: disabled)
     Active: active (running) since Fri 2024-06-28 05:03:14 UTC; 17s ago
```

## Route 53の設定
前回はPrivate Hosted Zoneを使ってAWS内の通信に限りドメインでのアクセスを可能とする環境を作りました。今回はPublic Hosted Zoneを使用してインターネット上においてもEC2に対してドメインでのアクセスを可能にします。
※Let’s Encryptを運営している団体からサーバ証明書等をもらうことになりますので、AWS内でしか使えないPrivateではダメということですね。（もしかしたらプライベートでも行けるのかもしれませんがそこまで確認していません。）

ここの手順は後続のお名前.comでのドメインを購入出来るか確認しながら実施していただければと思いますが、Route 53の管理画面にアクセスしてPublic Hosted Zoneを選択してホストゾーンを作成します。
Route 53で作成したホストゾーンとお名前.comで申請するドメインは同じものに揃えます。
今回はohtsuka-aws.xyzというドメインが申請できそうだということをお名前.comで確認することが出来ましたので、ホストゾーンを作成し、ohtsuka-aws.xyzとweb.ohtsuka-aws.xyzという2つのAレコードを作成しました。Aレコードに登録するIPアドレスは先ほど操作していたEC2のパブリックIPアドレスになります。

![Untitled (52).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/2c045da9-156c-d1b2-f538-15dc5b42fe1f.png)

## お名前.comで独自ドメインを取得する
独自ドメインを取得しようとすると普通だと年間数千円とかかる認識なのですが、お名前.com様ですと0円、ないし1円とかでも購入できるものがありましたので、それを使いたいと思います。

※以下のサイトを見てみますと「なぜ格安で提供できるのか？」ということが書かれています。

https://wizblog.wpx.jp/onamae-com-0yen/

https://www.domain-server-study.com/domain/onamae.html

Route 53のところでも記載していますが、今回はohtsuka-aws.xyzというドメインを使っていきます。
![Untitled (50).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/9ba2ac33-c172-5843-05de-6537584ebad4.png)
nameserverを変更します。
ドメイン詳細のネームサーバー情報という欄の右下にネームサーバの変更というものがありますので、こちらを押下します。
![Untitled (51).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/04461366-b53f-5946-8cd6-a7278bac7e21.png)
Route 53のNSレコードに記載しているサーバを記載して確認画面に進むボタンを押下します。
![screencapture-onamae-domain-navi-ns-update-input-2024-06-28-15_35_16 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/a00e75c8-22c0-28e2-9926-dfd932275282.png)
設定するを押下します。
![Untitled (53).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/7203cbee-9960-4d23-0ad9-6da2e12fe0b7.png)
レンタルサーバも利用開始します。ステータスが稼働中となっていることを確認します。
※このあたりの仕様がいまいちつかめていないのですが、レンタルサーバを使用することで名前解決が可能になりました。関係ないのかもしれませんが・・・💦
![Untitled (54).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/8fbd9fef-33c2-f584-25dc-52d0fddba82e.png)
![Untitled (55).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/31b08a03-90c7-e26f-ccd7-c2680d06a4f6.png)
少し待つと、自分のローカルPCのコマンドプロンプトからドメイン名で疎通確認が出来るようになります。
名前解決がうまくいっている証拠ですね。
![Untitled (56).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/29c9524f-1824-edef-222d-85016d350e4b.png)

## EC2の設定②
/etc/systemd/resolve.confファイルを開き、★の部分を修正していきます。
DNSの部分はVPCに振っているネットワークアドレス+ 2のIPアドレスを入力します。
（これはPrivate Hosted Zoneを構成したときにも軽く記載したDHCPで自動的に設定されるRoute 53 ResolverのIPアドレスになります。）
FallbackDNSに関しては、Private Hosted Zoneではないときの問い合わせ先のDNSサーバを示すようです。今回はGoogle等が用意しているDNSサーバを指定しています。
```resolve.conf
[root@ip-192-168-3-38 ~]# vi /etc/systemd/resolved.conf
[root@ip-192-168-3-38 ~]# cat /etc/systemd/resolved.conf
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it under the
#  terms of the GNU Lesser General Public License as published by the Free
#  Software Foundation; either version 2.1 of the License, or (at your option)
#  any later version.
#
# Entries in this file show the compile time defaults. Local configuration
# should be created by either modifying this file, or by creating "drop-ins" in
# the resolved.conf.d/ subdirectory. The latter is generally recommended.
# Defaults can be restored by simply deleting this file and all drop-ins.
#
# Use 'systemd-analyze cat-config systemd/resolved.conf' to display the full config.
#
# See resolved.conf(5) for details.

[Resolve]
# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
# Cloudflare: 1.1.1.1#cloudflare-dns.com 1.0.0.1#cloudflare-dns.com 2606:4700:4700::1111#cloudflare-dns.com 2606:4700:4700::1001#cloudflare-dns.com
# Google:     8.8.8.8#dns.google 8.8.4.4#dns.google 2001:4860:4860::8888#dns.google 2001:4860:4860::8844#dns.google
# Quad9:      9.9.9.9#dns.quad9.net 149.112.112.112#dns.quad9.net 2620:fe::fe#dns.quad9.net 2620:fe::9#dns.quad9.net
DNS=192.168.0.2　★
FallbackDNS=8.8.8.8 8.8.4.4 1.1.1.1 1.0.0.1　★
Domains=ap-northeast-1.compute.internal　★
#DNSSEC=no
#DNSOverTLS=no
#MulticastDNS=no
#LLMNR=no
#Cache=yes
#CacheFromLocalhost=no
#DNSStubListener=yes
#DNSStubListenerExtra=
#ReadEtcHosts=yes
#ResolveUnicastSingleLabel=no
[root@ip-192-168-3-38 ~]# systemctl restart systemd-resolved
[root@ip-192-168-3-38 ~]# ls -l /etc/resolv.conf
lrwxrwxrwx. 1 root root 32 Jun 20 23:10 /etc/resolv.conf -> /run/systemd/resolve/resolv.conf
```
次に/etc/httpd/conf.d/配下に設定ファイルを作成して中身を作りこんでいきます。
```
[root@ip-192-168-3-38 ~]# vi /etc/httpd/conf.d/ohtsuka-aws_xyz.conf
[root@ip-192-168-3-38 ~]# cat /etc/httpd/conf.d/ohtsuka-aws_xyz.conf
<VirtualHost *:80>
    ServerName ohtsuka-aws.xyz
    ServerAlias web.ohtsuka-aws.xyz
    DocumentRoot /var/www/ohtsuka-aws_xyz

    <Directory /var/www/ohtsuka-aws_xyz>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog /var/log/httpd/ohtsuka-aws_xyz_error.log
    CustomLog /var/log/httpd/ohtsuka-aws_xyz_access.log combined

    # Exclude Let's Encrypt challenge from redirect
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
</VirtualHost>
```
次に、上記で定義したVirtualHostで使用するindex.htmlを適当に準備していきます
```
[root@ip-192-168-3-38 ~]# mkdir -p /var/www/ohtsuka-aws_xyz
[root@ip-192-168-3-38 ~]# echo "<html><h1>Hello, World! Hello, Let's Encrypt!</h1></html>" | sudo tee /var/www/ohtsuk
a-aws_xyz/index.html
<html><h1>Hello, World! Hello, Let's Encrypt!</h1></html>
```
この後、apachectlコマンドを使いコンフィグに問題がないかを確認し、問題ないことの確認が取れたらapacheにrestartを仕掛けます。
```
[root@ip-192-168-3-38 ~]# apachectl configtest
Syntax OK
[root@ip-192-168-3-38 ~]# systemctl restart httpd
```

## Certbotを使って証明書や鍵などを取得する。
以下のコマンドを使って証明書などを取得していきます。

このタイミングでパブリックなドメインで名前解決出来る必要があったため、Route 53のPublic Hosted Zoneやお名前.com等を使用して準備をしていたわけですね。
以下のような出力結果となり、また/etc/letsencrypt/live配下に鍵や証明書のファイルが作成されていれば問題ありません。

certbot certonlyコマンドは「Let's Encryptを使って証明書を取得または更新するが、インストールは行わない」と意味になります。
```
[root@ip-192-168-3-38 ~]# certbot certonly --webroot -w /var/www/ohtsuka-aws_xyz -d ohtsuka-aws.xyz -d web.ohtsuka-aws.xyz
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for ohtsuka-aws.xyz and web.ohtsuka-aws.xyz

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/ohtsuka-aws.xyz/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/ohtsuka-aws.xyz/privkey.pem
This certificate expires on 2024-09-26.
These files will be updated when the certificate renews.

NEXT STEPS:
- The certificate will need to be renewed before it expires. Certbot can automatically renew the certificate in the background, but you may need to take steps to enable that functionality. See https://certbot.org/renewal-setup for instructions.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

[root@ip-192-168-3-38 ~]# ls -ltr /etc/letsencrypt/live/ohtsuka-aws.xyz/
total 4
lrwxrwxrwx. 1 root root  42 Jun 28 07:17 privkey.pem -> ../../archive/ohtsuka-aws.xyz/privkey1.pem
lrwxrwxrwx. 1 root root  44 Jun 28 07:17 fullchain.pem -> ../../archive/ohtsuka-aws.xyz/fullchain1.pem
lrwxrwxrwx. 1 root root  40 Jun 28 07:17 chain.pem -> ../../archive/ohtsuka-aws.xyz/chain1.pem
lrwxrwxrwx. 1 root root  39 Jun 28 07:17 cert.pem -> ../../archive/ohtsuka-aws.xyz/cert1.pem
-rw-r--r--. 1 root root 692 Jun 28 07:17 README
```

## SSL通信を有効化する
以下のモジュールをインストールします。
インストール後、SSLに関するコンフィグをいじります。★の部分を追記していきます。
CertificateFile系はCertbotで取得したファイルのフルパスを指定してあげます。
```
[root@ip-192-168-3-38 ~]# dnf install -y mod_ssl
[root@ip-192-168-3-38 ~]# vi /etc/httpd/conf.d/ssl.conf
[root@ip-192-168-3-38 ~]# cat /etc/httpd/conf.d/ssl.conf
#
# When we also provide SSL we have to listen to the
# standard HTTPS port in addition.
#
★LoadModule ssl_module modules/mod_ssl.so
★Listen 443 https
～中略～
★SSLCertificateFile /etc/letsencrypt/live/ohtsuka-aws.xyz/fullchain.pem
★SSLCertificateKeyFile /etc/letsencrypt/live/ohtsuka-aws.xyz/privkey.pem
```

また、先ほど作成した/etc/httpd/conf.d/ohtsuka-aws_xyz.confのファイルを修正していきます。
```
[root@ip-192-168-3-38 ~]# cat /etc/httpd/conf.d/ohtsuka-aws_xyz.conf
<VirtualHost *:80>
    ServerName ohtsuka-aws.xyz
    ServerAlias web.ohtsuka-aws.xyz
    DocumentRoot /var/www/ohtsuka-aws_xyz

    <Directory /var/www/ohtsuka-aws_xyz>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog /var/log/httpd/ohtsuka-aws_xyz_error.log
    CustomLog /var/log/httpd/ohtsuka-aws_xyz_access.log combined

    # Exclude Let's Encrypt challenge from redirect
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName ohtsuka-aws.xyz
    ServerAlias web.ohtsuka-aws.xyz
    DocumentRoot /var/www/ohtsuka-aws_xyz

    <Directory /var/www/ohtsuka-aws_xyz>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog /var/log/httpd/ohtsuka-aws_xyz_error.log
    CustomLog /var/log/httpd/ohtsuka-aws_xyz_access.log combined

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/ohtsuka-aws.xyz/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/ohtsuka-aws.xyz/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
```

修正を行いましたら修正内容をapacheに読み込ませるため、再度apachectlコマンドを使ってコンフィグに問題が無いことを確認して、restartを実施していきます。
```
[root@ip-192-168-3-38 ~]# apachectl configtest
[Fri Jun 28 07:29:30.951341 2024] [so:warn] [pid 9283:tid 9283] AH01574: module ssl_module is already loaded, skipping
Syntax OK
[root@ip-192-168-3-38 ~]# systemctl restart httpd
```

# 接続テスト
ローカルPCでWebブラウザを開きます。今回はEdgeを使用しました。
Route 53及びお名前.comで取得・定義したドメイン名を使ってWebブラウジングが出来ることと、SSLを使って通信がセキュアであることを確認していきます。

まずはドメイン名を使って通信が出来ていることが以下より確認できました。
![Untitled (57).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/4d18af84-8f1e-67b3-cbe5-b8ed237d474c.png)
また、Let’s Encryptによって発行された証明書によって、セキュアな通信が出来ていることがわかりますね。
![Untitled (58).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/b7429bb8-dc97-d865-ce09-9c9aab810df1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3219385/99ae231b-5af1-3342-5362-175cf99d9e36.png)

# 【余談】certbotコマンドのオプション
certbot --helpで出力される内容をChatGPTを使って日本語に翻訳したものを参考に（ないし自分の勉強用に）おいておきます。
```
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  certbot [サブコマンド] [オプション] [-d ドメイン] [-d ドメイン] ...

CertbotはHTTPS/TLS/SSL証明書を取得してインストールすることができます。デフォルトでは、証明書の取得とインストールの両方にウェブサーバーを使用しようとします。最も一般的なサブコマンドとフラグは以下の通りです：

証明書の取得、インストール、および更新:
    (デフォルト) run   現在のウェブサーバーに証明書を取得してインストールします
    certonly        証明書を取得または更新しますが、インストールは行いません
    renew           有効期限が近いすべての既存の証明書を更新します
    enhance         既存の設定にセキュリティ強化を追加します
   -d ドメイン       証明書を取得するためのドメインのカンマ区切りリスト

  --apache          認証とインストールにApacheプラグインを使用します
  --standalone      認証のためにスタンドアロンウェブサーバーを実行します
  (certbot nginx プラグインはインストールされていません)
  --webroot         認証のためにサーバーのwebrootフォルダーにファイルを配置します
  --manual          対話的またはシェルスクリプトフックを使用して証明書を取得します

   -n               非対話的に実行します
  --test-cert       ステージングサーバーからテスト証明書を取得します
  --dry-run         証明書をディスクに保存せずに「renew」または「certonly」をテストします

証明書の管理:
    certificates    Certbotから取得した証明書の情報を表示します
    revoke          証明書を失効させます（--cert-nameまたは--cert-pathを指定）
    delete          証明書を削除します（--cert-nameを指定）
    reconfigure     証明書の設定を更新します（--cert-nameを指定）

アカウントの管理:
    register        ACMEアカウントを作成します
    unregister      ACMEアカウントを無効化します
    update_account  ACMEアカウントを更新します
    show_account    アカウントの詳細を表示します
  --agree-tos       ACMEサーバーの加入者契約に同意します
   -m EMAIL         重要なアカウント通知用のメールアドレス

より詳細なヘルプ:

  -h, --help [トピック]    このメッセージ、またはトピックに関する詳細なヘルプを表示します；
                           利用可能なトピックは以下の通りです：

   all, automation, commands, paths, security, testing, またはサブコマンドやプラグインのいずれか（certonly, renew, install, register, nginx, apache, standalone, webrootなど）
  -h all                すべてのトピックを含む詳細なヘルプページを表示します
  --version             バージョン番号を表示します
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

# 【余談】この環境でEC2を停止しても大丈夫か？
結論、Route 53のAレコードを編集すれば大丈夫です。
遠慮なく停止して、無駄なお金が発生しないようにしましょう。

https://qiita.com/ohtsuka-shota/items/65b148a0da736cc6bab5