Let's Encrypt で SSL証明書を自動更新

# やりたいこと
WebページのHTTPS化を実装し、HTTPからHTTPSへのリダイレクトも設定
無料でSSL証明書の更新を行うため、Let's Encryptを使用

# 実行環境 / 前提条件
+ Oracle Linux Server release 9.4
※Oracle Linux は RedHat 互換のディストリビューションであるため、他のRHEL系でも代用が可能。
+ ミドルウェアはApacheを使用
+ 既にドメインはDNSに登録済み(今回は`example.cloudii.jp`というドメインを使用)
+ 今回は **HTTPチャレンジ** でSSL証明書を作成予定
※HTTPチャレンジでワイルドカード証明書の自動更新は不可
　代わりにDNSチャレンジでの作成を推奨

# 本作業
## snapのインストール
Let's Encryptが発行するSSL証明書を取得する場合、<b>Certbot</b>と呼ばれるサービスを使用して取得します。
ただし、Certbotはデフォルトではサーバにインストールされていないため、自身でインストールする必要があります。
また、Certbotをインストールする際には、異なるLinuxディストリビューション間の依存関係を解決する<b>Snap</b>をインストールする必要があります。
ここではSnapをインストールする手順を紹介します。

最初に以下のコマンドで**ol9_developer_EPEL**リポジトリを有効化します。
```shell
sudo dnf config-manager --set-enable ol9_developer_EPEL
```

実行後、以下ののコマンドでリポジトリが有効化されている確認します。
```shell
sudo dnf repolist all | grep ol9_developer_EPEL
```
```shell:実行例
ol9_developer_EPEL           Oracle Linux 9 EPEL Packages for Development 有効化
```

確認後、Snapのデーモンである<b>snapd</b>をインストールします。
```shell
sudo dnf install -y snapd
```

```shell:実行例
Extra Packages for Enterprise Linux 9 - x86_64                                                                    22 MB/s |  22 MB     00:01    
Extra Packages for Enterprise Linux 9 openh264 (From Cisco) - x86_64                                             1.4 kB/s | 2.5 kB     00:01    
依存関係が解決しました。
=================================================================================================================================================
 パッケージ                            アーキテクチャー               バージョン                              リポジトリー                 サイズ
=================================================================================================================================================
インストール:
 snapd                                 x86_64                         2.63-0.el9                              epel                          17 M
依存関係のインストール:
 snap-confine                          x86_64                         2.63-0.el9                              epel                         2.8 M
 snapd-selinux                         noarch                         2.63-0.el9                              epel                         102 k
 xdelta                                x86_64                         3.1.0-17.el9                            epel                          87 k

トランザクションの概要
=================================================================================================================================================
インストール  4 パッケージ

ダウンロードサイズの合計: 20 M
インストール後のサイズ: 65 M
パッケージのダウンロード:
(1/4): snapd-selinux-2.63-0.el9.noarch.rpm                                                                       1.3 MB/s | 102 kB     00:00    
(2/4): snap-confine-2.63-0.el9.x86_64.rpm                                                                         23 MB/s | 2.8 MB     00:00    
(3/4): xdelta-3.1.0-17.el9.x86_64.rpm                                                                            2.0 MB/s |  87 kB     00:00    
(4/4): snapd-2.63-0.el9.x86_64.rpm                                                                                53 MB/s |  17 MB     00:00    
-------------------------------------------------------------------------------------------------------------------------------------------------
合計                                                                                                              30 MB/s |  20 MB     00:00     
Extra Packages for Enterprise Linux 9 - x86_64                                                                   1.6 MB/s | 1.6 kB     00:00    
GPG 鍵 0x3228467C をインポート中:
 Userid     : "Fedora (epel9) <epel@fedoraproject.org>"
 Fingerprint: FF8A D134 4597 106E CE81 3B91 8A38 72BF 3228 467C
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-9
鍵のインポートに成功しました
トランザクションを確認しています
トランザクションの確認に成功しました。
トランザクションをテストしています
トランザクションのテストに成功しました。
トランザクションを実行しています
  準備中           :                                                                                                                         1/1 
  インストール中   : xdelta-3.1.0-17.el9.x86_64                                                                                              1/4 
  scriptletの実行中: snapd-selinux-2.63-0.el9.noarch                                                                                         2/4 
  インストール中   : snapd-selinux-2.63-0.el9.noarch                                                                                         2/4 
  scriptletの実行中: snapd-selinux-2.63-0.el9.noarch                                                                                         2/4 
  インストール中   : snap-confine-2.63-0.el9.x86_64                                                                                          3/4 
  インストール中   : snapd-2.63-0.el9.x86_64                                                                                                 4/4 
  scriptletの実行中: snapd-2.63-0.el9.x86_64                                                                                                 4/4 
  scriptletの実行中: snapd-selinux-2.63-0.el9.noarch                                                                                         4/4 
  scriptletの実行中: snapd-2.63-0.el9.x86_64                                                                                                 4/4 
  検証中           : snap-confine-2.63-0.el9.x86_64                                                                                          1/4 
  検証中           : snapd-2.63-0.el9.x86_64                                                                                                 2/4 
  検証中           : snapd-selinux-2.63-0.el9.noarch                                                                                         3/4 
  検証中           : xdelta-3.1.0-17.el9.x86_64                                                                                              4/4 

インストール済み:
  snap-confine-2.63-0.el9.x86_64        snapd-2.63-0.el9.x86_64        snapd-selinux-2.63-0.el9.noarch        xdelta-3.1.0-17.el9.x86_64       

完了しました!
```

snapdのインストール後、snapdソケットの自動起動を有効化します。
自動起動を有効化することで、snapd.socketが即座に起動され、snapdが必要に応じて通信を処理できる状態になります。
```shell
sudo systemctl enable --now snapd.socket
```

```shell:実行例
Created symlink /etc/systemd/system/sockets.target.wants/snapd.socket → /usr/lib/systemd/system/snapd.socket.
```

同様に`/var/lib/snapd/snap`と`/snap`にシンボリックリンクを作成します。
シンボリックリンクを作成することで、システムやユーザーが簡単にSnapパッケージにアクセスできるようになります。

```shell
sudo ln -s /var/lib/snapd/snap /snap
```

最新のsnapdのバージョンを取得するため、以下のコマンドでsnapdを更新します。
```shell
sudo snap install core; sudo snap refresh core
```

```shell:実行例
2024-08-13T09:09:50+09:00 INFO Waiting for automatic snapd restart...
core 16-2.61.4-20240607 from Canonical✓ installed
snap "core" has no updates available
```

更新後、サーバの再起動を行います。
```shell
sudo reboot
```

再起動後、snapdの起動と自動起動の有効化を行います。
```shell
sudo systemctl start snapd
sudo systemctl enable snapd
```

`systemctl status`コマンドでsnapdの状態を確認すると、<b>active</b>の状態となっています。
```shell
sudo systemctl status snapd
```

```shell:実行例
● snapd.service - Snap Daemon
     Loaded: loaded (/usr/lib/systemd/system/snapd.service; enabled; preset: disabled)
     Active: active (running) since Tue 2024-08-13 09:13:21 JST; 24s ago
TriggeredBy: ● snapd.socket
   Main PID: 4638 (snapd)
      Tasks: 9 (limit: 73025)
     Memory: 39.9M
        CPU: 257ms
     CGroup: /system.slice/snapd.service
             └─4638 /usr/libexec/snapd/snapd

 8月 13 09:13:21 ssl-sv systemd[1]: Starting Snap Daemon...
 8月 13 09:13:21 ssl-sv snapd[4638]: overlord.go:271: Acquiring state lock file
 8月 13 09:13:21 ssl-sv snapd[4638]: overlord.go:276: Acquired state lock file
 8月 13 09:13:21 ssl-sv snapd[4638]: daemon.go:247: started snapd/2.63-0.el9 (series 16; classic; devmode) ol/9.4 (amd64) linux/5.15.0-208.159.3>
 8月 13 09:13:21 ssl-sv snapd[4638]: daemon.go:340: adjusting startup timeout by 35s (pessimistic estimate of 30s plus 5s per snap)
 8月 13 09:13:21 ssl-sv snapd[4638]: backends.go:58: AppArmor status: apparmor not enabled
 8月 13 09:13:21 ssl-sv systemd[1]: Started Snap Daemon.
```

## Certbotのインストール
snapdのインストール後、以下のコマンドでCertbotのインストールを行います。
```shell
sudo snap install --classic certbot
```

```shell:実行例
certbot 2.11.0 from Certbot Project (certbot-eff✓) installed
```

その後、簡単に利用できるようにシンボリックリンクを作成します。
```shell
sudo ln -s /snap/bin/certbot /usr/bin/certbot
```

## SSL証明書の作成
Certbotのインストール後、以下のコマンドでSSL証明書を作成します。
ここでは`example.cloudii.jp`を例にしています。
複数のドメインを指定する場合は、`ドメイン1,ドメイン2`のようにカンマで区切って指定します。
```shell
sudo certbot certonly --webroot -w /var/www/html -d example.cloudii.jp
```

SSL証明書の作成に使用したオプションは以下の通りです。
ここでは、必要最低限のオプションのみを指定しています。
+ `--webroot`...証明書を取得する際に、Web認証を使用します。この方式では、指定されたディレクトリに証明書の認証用ファイルを一時的に配置し、Let's Encryptがそのファイルにアクセスすることでドメインの所有権を確認します。
+ `-w /var/www/html`...ウェブルートのパスを指定します。`/var/www/html`は、Webサーバーが公開しているディレクトリであり、ここに認証用ファイルが置かれます。
+ `-d example.cloudii.jp`...証明書を発行するドメイン名を指定します。この例では、`example.cloudii.jp`というドメインに対してSSL証明書を取得します。複数のドメインがある場合は、このオプションを複数回使用できます。

SSL証明書の作成コマンドを実行すると、最初にメールアドレスの入力を求められます。
ここには、SSL証明書の更新情報などを受け取っても問題のないメールアドレスを入力してください。
```shell:実行例
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel):
```

Let's Encryptの規約に同意するかのメッセージが表示されるので、問題ない場合`Y`を入力します。
```shell:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.4-April-3-2024.pdf. You must agree in
order to register with the ACME server. Do you agree?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:
```

同様にLet's Encryptの支援団体についてのお知らせについてのメッセージが表示されるので、問題がない場合は`Y`を入力します。
```shell:実行例
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:
```

上記の項目を全て入力後、SSL証明書が作成されます。
```shell:実行例
Account registered.
Requesting a certificate for example.cloudii.jp

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.cloudii.jp/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.cloudii.jp/privkey.pem
This certificate expires on 2024-11-10.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

これでLet's Encryptを使用したSSL証明書の作成は完了です。
以下のコマンドで作成したSSL証明書を確認できます。
```shell
sudo certbot certificates
```

```shell:実行例
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: example.cloudii.jp
    Serial Number: 32b5c61733617aa040118d162b9ea8bd83e
    Key Type: ECDSA
    Domains: example.cloudii.jp
    Expiry Date: 2024-11-10 23:34:57+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/example.cloudii.jp/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/example.cloudii.jp/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

SSL証明書の設定ファイルを確認する場合は`/etc/letsencrypt/renewal/example.cloudii.jp.conf`に記載されています。
```shell:実行例
# renew_before_expiry = 30 days
version = 2.11.0
archive_dir = /etc/letsencrypt/archive/example.cloudii.jp
cert = /etc/letsencrypt/live/example.cloudii.jp/cert.pem
privkey = /etc/letsencrypt/live/example.cloudii.jp/privkey.pem
chain = /etc/letsencrypt/live/example.cloudii.jp/chain.pem
fullchain = /etc/letsencrypt/live/example.cloudii.jp/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = 513a8fb554ff3229320936ce3289c9f7
authenticator = webroot
webroot_path = /var/www/html,
server = https://acme-v02.api.letsencrypt.org/directory
key_type = ecdsa
[[webroot_map]]
example.cloudii.jp = /var/www/html
```

設定ファイル内の以下の項目は、HTTPS化を行う際に使用するため、それぞれのパスを控えておきます。
```shell
privkey = /etc/letsencrypt/live/example.cloudii.jp/privkey.pem
chain = /etc/letsencrypt/live/example.cloudii.jp/chain.pem
```

## HTTPSの有効化
SSL証明書を作成後、サイトのHTTPS化を行います。
最初に、SSL化に必要であるApacheモジュールの<b>mod_ssl</b>をインストールします。
```shell
sudo dnf install -y mod_ssl
```
```shell:実行例
メタデータの期限切れの最終確認: 0:01:08 前の 2024年08月13日 09時27分08秒 に実施しました。
依存関係が解決しました。
=================================================================================================================================================
 パッケージ                   アーキテクチャー            バージョン                                    リポジトリー                       サイズ
=================================================================================================================================================
インストール:
 mod_ssl                      x86_64                      1:2.4.57-11.0.1.el9_4.1                       ol9_appstream                      117 k

トランザクションの概要
=================================================================================================================================================
インストール  1 パッケージ

ダウンロードサイズの合計: 117 k
インストール後のサイズ: 268 k
パッケージのダウンロード:
mod_ssl-2.4.57-11.0.1.el9_4.1.x86_64.rpm                                                                         1.0 MB/s | 117 kB     00:00    
-------------------------------------------------------------------------------------------------------------------------------------------------
合計                                                                                                             1.0 MB/s | 117 kB     00:00     
トランザクションを確認しています
トランザクションの確認に成功しました。
トランザクションをテストしています
トランザクションのテストに成功しました。
トランザクションを実行しています
  準備中           :                                                                                                                         1/1 
  インストール中   : mod_ssl-1:2.4.57-11.0.1.el9_4.1.x86_64                                                                                  1/1 
  scriptletの実行中: mod_ssl-1:2.4.57-11.0.1.el9_4.1.x86_64                                                                                  1/1 
  検証中           : mod_ssl-1:2.4.57-11.0.1.el9_4.1.x86_64                                                                                  1/1 

インストール済み:
  mod_ssl-1:2.4.57-11.0.1.el9_4.1.x86_64                                                                                                         

完了しました!
```

mod_sslのインストール後、`/etc/httpd/conf.d/ssl.conf`が自動作成されますので、以下の内容に変更を行います。
```diff_shell:/etc/httpd/conf.d/ssl.conf
#
# When we also provide SSL we have to listen to the 
# standard HTTPS port in addition.
#
Listen 443 https

##
##  SSL Global Context
##
##  All SSL configuration in this context applies both to
##  the main server and all SSL-enabled virtual hosts.
##

#   Pass Phrase Dialog:
#   Configure the pass phrase gathering process.
#   The filtering dialog program (`builtin' is a internal
#   terminal dialog) has to provide the pass phrase on stdout.
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog

#   Inter-Process Session Cache:
#   Configure the SSL Session Cache: First the mechanism 
#   to use and second the expiring timeout (in seconds).
SSLSessionCache         shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout  300

#
# Use "SSLCryptoDevice" to enable any supported hardware
# accelerators. Use "openssl engine -v" to list supported
# engine names.  NOTE: If you enable an accelerator and the
# server does not start, consult the error logs and ensure
# your accelerator is functioning properly. 
#
SSLCryptoDevice builtin
#SSLCryptoDevice ubsec

##
## SSL Virtual Host Context
##

<VirtualHost _default_:443>

# General setup for the virtual host, inherited from global configuration
- #DocumentRoot "/var/www/html"
+ DocumentRoot "/var/www/html"
- #ServerName www.example.com:443
+ ServerName example.cloudii.jp:443

# Use separate log files for the SSL virtual host; note that LogLevel
# is not inherited from httpd.conf.
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn

#   SSL Engine Switch:
#   Enable/Disable SSL for this virtual host.
SSLEngine on

#   List the protocol versions which clients are allowed to connect with.
#   The OpenSSL system profile is used by default.  See
#   update-crypto-policies(8) for more details.
#SSLProtocol all -SSLv3
#SSLProxyProtocol all -SSLv3

#   User agents such as web browsers are not configured for the user's
#   own preference of either security or performance, therefore this
#   must be the prerogative of the web server administrator who manages
#   cpu load versus confidentiality, so enforce the server's cipher order.
SSLHonorCipherOrder on

#   SSL Cipher Suite:
#   List the ciphers that the client is permitted to negotiate.
#   See the mod_ssl documentation for a complete list.
#   The OpenSSL system profile is configured by default.  See
#   update-crypto-policies(8) for more details.
SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM

#   Point SSLCertificateFile at a PEM encoded certificate.  If
#   the certificate is encrypted, then you will be prompted for a
#   pass phrase.  Note that restarting httpd will prompt again.  Keep
#   in mind that if you have both an RSA and a DSA certificate you
#   can configure both in parallel (to also allow the use of DSA
#   ciphers, etc.)
#   Some ECC cipher suites (http://www.ietf.org/rfc/rfc4492.txt)
#   require an ECC certificate which can also be configured in
#   parallel.
- SSLCertificateFile /etc/pki/tls/certs/localhost.crt
+ # SSLCertificateFile /etc/pki/tls/certs/localhost.crt

#   Server Private Key:
#   If the key is not combined with the certificate, use this
#   directive to point at the key file.  Keep in mind that if
#   you've both a RSA and a DSA private key you can configure
#   both in parallel (to also allow the use of DSA ciphers, etc.)
#   ECC keys, when in use, can also be configured in parallel
- SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
+ # SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

#   Server Certificate Chain:
#   Point SSLCertificateChainFile at a file containing the
#   concatenation of PEM encoded CA certificates which form the
#   certificate chain for the server certificate. Alternatively
#   the referenced file can be the same as SSLCertificateFile
#   when the CA certificates are directly appended to the server
#   certificate for convenience.
#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt

#   Certificate Authority (CA):
#   Set the CA certificate verification path where to find CA
#   certificates for client authentication or alternatively one
#   huge file containing all of them (file must be PEM encoded)
#SSLCACertificateFile /etc/pki/tls/certs/ca-bundle.crt

#   Client Authentication (Type):
#   Client certificate verification type and depth.  Types are
#   none, optional, require and optional_no_ca.  Depth is a
#   number which specifies how deeply to verify the certificate
#   issuer chain before deciding the certificate is not valid.
#SSLVerifyClient require
#SSLVerifyDepth  10

#   Access Control:
#   With SSLRequire you can do per-directory access control based
#   on arbitrary complex boolean expressions containing server
#   variable checks and other lookup directives.  The syntax is a
#   mixture between C and Perl.  See the mod_ssl documentation
#   for more details.
#<Location />
#SSLRequire (    %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
#            and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
#            and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
#            and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
#            and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20       ) \
#           or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
#</Location>

#   SSL Engine Options:
#   Set various options for the SSL engine.
#   o FakeBasicAuth:
#     Translate the client X.509 into a Basic Authorisation.  This means that
#     the standard Auth/DBMAuth methods can be used for access control.  The
#     user name is the `one line' version of the client's X.509 certificate.
#     Note that no password is obtained from the user. Every entry in the user
#     file needs this password: `xxj31ZMTZzkVA'.
#   o ExportCertData:
#     This exports two additional environment variables: SSL_CLIENT_CERT and
#     SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
#     server (always existing) and the client (only existing when client
#     authentication is used). This can be used to import the certificates
#     into CGI scripts.
#   o StdEnvVars:
#     This exports the standard SSL/TLS related `SSL_*' environment variables.
#     Per default this exportation is switched off for performance reasons,
#     because the extraction step is an expensive operation and is usually
#     useless for serving static content. So one usually enables the
#     exportation for CGI and SSI requests only.
#   o StrictRequire:
#     This denies access when "SSLRequireSSL" or "SSLRequire" applied even
#     under a "Satisfy any" situation, i.e. when it applies access is denied
#     and no other module can change it.
#   o OptRenegotiate:
#     This enables optimized SSL connection renegotiation handling when SSL
#     directives are used in per-directory context. 
#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/var/www/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>

#   SSL Protocol Adjustments:
#   The safe and default but still SSL/TLS standard compliant shutdown
#   approach is that mod_ssl sends the close notify alert but doesn't wait for
#   the close notify alert from client. When you need a different shutdown
#   approach you can use one of the following variables:
#   o ssl-unclean-shutdown:
#     This forces an unclean shutdown when the connection is closed, i.e. no
#     SSL close notify alert is sent or allowed to be received.  This violates
#     the SSL/TLS standard but is needed for some brain-dead browsers. Use
#     this when you receive I/O errors because of the standard approach where
#     mod_ssl sends the close notify alert.
#   o ssl-accurate-shutdown:
#     This forces an accurate shutdown when the connection is closed, i.e. a
#     SSL close notify alert is sent and mod_ssl waits for the close notify
#     alert of the client. This is 100% SSL/TLS standard compliant, but in
#     practice often causes hanging connections with brain-dead browsers. Use
#     this only for browsers where you know that their SSL implementation
#     works correctly. 
#   Notice: Most problems of broken clients are also related to the HTTP
#   keep-alive facility, so you usually additionally want to disable
#   keep-alive for those clients, too. Use variable "nokeepalive" for this.
#   Similarly, one has to force some clients to use HTTP/1.0 to workaround
#   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
#   "force-response-1.0" for this.
BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0

#   Per-Server Logging:
#   The home of a custom SSL log file. Use this when you want a
#   compact non-error SSL logfile on a virtual host basis.
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

+ SSLCertificateFile /etc/letsencrypt/live/example.cloudii.jp/fullchain.pem
+ SSLCertificateKeyFile /etc/letsencrypt/live/example.cloudii.jp/privkey.pem
</VirtualHost>
```

念の為、以下のコマンドを実行して、ssl.confの構文に異常がないか確認します。
```shell
sudo apachectl configtest
```

```shell:実行例
Syntax OK
```

設定後、httpdを再起動します。
```shell
sudo systemctl restart httpd
```

再起動後、ブラウザ上でアクセスしてみると、問題なくHTTPS化されていることがわかります。
![スクリーンショット 2024-08-13 10.14.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/b5fa01e1-4a94-bb4b-1514-b4e571dfc76b.png)

念の為、証明書の詳細を確認すると、発行元が`Let's Encrypt`と表示されているため、問題ない挙動となっております。
![スクリーンショット 2024-08-13 10.15.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1430519/8f54e89a-773e-997c-1f28-9e01faef047d.png)

現在、HTTPからHTTPSへのリダイレクト設定は行っておりません。
リダイレクト設定を行う際は、ssl.confに以下の内容を追記します。
```shell:/etc/httpd/conf.d/ssl.conf
<VirtualHost *:80>
    ServerName example.cloudii.jp

    # httpからhttpsへのリダイレクト
    Redirect permanent / https://example.cloudii.jp/
</VirtualHost>
```

設定後、こちらもhttpdを再起動します。
```shell
sudo systemctl restart httpd
```

再起動後に以下のコマンドを実行、`301 Moved Permanently`と表示されればリダイレクト設定は完了です。
```shell
curl -IL example.cloudii.jp
```

```shell:実行例
[opc@ssl-sv ~]$ curl -IL example.cloudii.jp
HTTP/1.1 301 Moved Permanently
Date: Tue, 13 Aug 2024 01:29:16 GMT
Server: Apache/2.4.57 (Oracle Linux Server) OpenSSL/3.0.7
Location: https://example.cloudii.jp/
Content-Type: text/html; charset=iso-8859-1

HTTP/1.1 200 OK
Date: Tue, 13 Aug 2024 01:29:16 GMT
Server: Apache/2.4.57 (Oracle Linux Server) OpenSSL/3.0.7
Last-Modified: Tue, 13 Aug 2024 00:30:00 GMT
ETag: "15-61f85b5baf73a"
Accept-Ranges: bytes
Content-Length: 21
Content-Type: text/html; charset=UTF-8
```

## 自動更新
最後に、Let's Encryptで作成したSSL証明書の自動更新の設定を行います。
Let's EncryptのSSL証明書は有効期限が90日間のため、cronを使用して自動更新を設定します。
まず、以下のコマンドを実行して、SSL証明書の更新が正常に行われるかをテストします。
```shell
sudo certbot renew --dry-run
```

実行後、出力に`「Congratulations」`と表示されれば、正常に動作したことが確認できます。
```shell:実行例
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.cloudii.jp.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Account registered.
Simulating renewal of an existing certificate for example.cloudii.jp

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations, all simulated renewals succeeded: 
  /etc/letsencrypt/live/example.cloudii.jp/fullchain.pem (success)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

続いて、cronを使用して自動更新の設定を行います。

```shell
sudo crontab -e
```
以下の実行文は毎月1日に実行されますが、Let's Encryptの仕様上、証明書の有効期限が30日未満になって初めて更新が行われます。
```shell:毎月1日の深夜4時に更新を試みる場合
00 04 01 * * certbot renew && systemctl restart httpd
```

以上で全ての設定は完了となります。

# 参考サイト
https://gihyo.jp/book/2023/978-4-297-13354-2

https://qiita.com/three_mouth_ago/items/06f14f326b9116359ed3#3-ssl%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E8%87%AA%E5%8B%95%E6%9B%B4%E6%96%B0%E8%A8%AD%E5%AE%9A