【Ubuntu+Nginx】Let's EncryptでSSL証明書を発行してhttps通信を行う

# この記事について
Ubuntu+Nginxの環境（サーバはさくらVPSを使用）でLet's Encryptを使用して、コストをかけずにSSL証明書を発行してhttps通信を行いましたので、設定手順を記録として残したいと思います。

# 対象読者
* 独自ドメインに対してSSL通信を可能としたい方
* コストをかけずにSSL証明書を発行したい方
（サーバの用意・OSのインストールは完了しているものとします。）

# 環境
```
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.1 LTS (Focal Fossa)"
PRETTY_NAME="Ubuntu 20.04.1 LTS"
VERSION_ID="20.04"

$ certbot --version
certbot 0.40.0

$ nginx -v
nginx version: nginx/1.18.0 (Ubuntu)
```

# SSL証明書とは
SSL証明書（サーバ証明書）とは、以下2つの役割がありHttps通信によって安全な通信を行うための電子証明書です。
* 公正な第三者機関である認証局（CA）が、SSL証明書発行先のサーバが実在することを証明して、信頼できるものであることを証明するもの（なりすましを防ぐ）
* SSL証明書発行時に作成される公開鍵と秘密鍵によって、クライアント-サーバ間の通信内容の暗号化を行うもの（盗聴や改ざんを防ぐ）
参考：[SSL証明書とは？仕組みや種類についてわかりやすく解説](https://www.rworks.jp/system/system-column/sys-entry/21283/)

# Let's Encryptとは
上記で記載した `公正な第三者機関である認証局（CA）` の1つであり、その中でも特に無料でSSL証明書の発行が可能な認証局です。
[Let’s Encrypt はフリーで自動化されたオープンな認証局です。](https://letsencrypt.org/ja/)

# インストール
Nginxとcertbot（Let's encrypt）をインストールします。
```
sudo apt update
sudo apt install nginx
sudo apt install certbot python3-certbot-nginx
```
certbotによって作成したSSL証明書の署名と発行は、Let’s Encryptと呼ばれる認証局によって行われます。

# certbotがサーバにアクセスできるように設定
certbotはHTTPS通信を使用してSSL証明書を発行することから、HTTPSトラフィックを許可するために、443ポートを開放します。
```
$ sudo ufw allow 443
```
ポートの開放状況を見てみます。
```
$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22                         ALLOW       Anywhere
80                         ALLOW       Anywhere
443                        ALLOW       Anywhere
22 (v6)                    ALLOW       Anywhere (v6)
80 (v6)                    ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)
```

# certbotによってSSL証明書を発行
SSL証明書の発行前に、SSL証明書の発行対象であるドメインのNginx設定ファイルは以下のように記載しております。
（`sample.conf` は `nginx.conf` 内でincludeされております。）
```/etc/nginx/sites-enabled/sample.conf
server {
    server_name f1c.jp.net;

    location / {
        root /home/sample;
        index index.html;
    }
}
```

以下の例では、 `f1c.jp.net` というドメインに対してSSL証明書を発行しております。
複数のドメインに一度にSSL証明書を発行するには `sudo certbot --nginx -d f1c.jp.net -d www.f1c.jp.net` のように `-d` を複数記載します。
このコマンドを実行することで、暗号化された通信内容を復号するための秘密鍵も同時に作成されます。
```
$ sudo certbot --nginx -d f1c.jp.net
```
実行結果
```
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for f1c.jp.net
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/no1CompanyShare.conf

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/no1CompanyShare.conf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://f1c.jp.net

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=f1c.jp.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/f1c.jp.net/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/f1c.jp.net/privkey.pem
   Your cert will expire on 2022-08-18. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - 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
```

# SSL証明書の自動更新
先ほど発行したSSL証明書は3か月のみ有効です。
3か月ごとにサーバ上で更新するのは手間であるため、自動更新できるように設定します。
サーバ上でcertbotによって作成されたすべてのSSL証明書に対して設定します。

```
$ sudo certbot renew --dry-run
```
実行結果
```
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/baseballgames.jp.net.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator nginx, Installer nginx
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for baseballgames.jp.net
http-01 challenge for www.baseballgames.jp.net
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of nginx server; fullchain is
/etc/letsencrypt/live/baseballgames.jp.net/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/f1c.jp.net.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator nginx, Installer nginx
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for f1c.jp.net
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of nginx server; fullchain is
/etc/letsencrypt/live/f1c.jp.net/fullchain.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/baseballgames.jp.net/fullchain.pem (success)
  /etc/letsencrypt/live/f1c.jp.net/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
```

`(success)` と表示されていれば完了です。

Nginxの設定ファイルが以下のように自動で更新されます。
`# managed by Certbot` と記載のある行がcertbotによって自動追加された行です。
`ssl_certificate` の箇所に指定されているパスが、**SSL証明書**の存在するファイルパス、
`ssl_certificate_key`  の箇所に指定されているパスが、**SSL証明書作成時に発行された秘密鍵**の存在するファイルパスが記載されています。
```/etc/nginx/sites-enabled/sample.conf
server {
    server_name f1c.jp.net;

    location / {
        root /home/sample;
        index index.html;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/f1c.jp.net/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/f1c.jp.net/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
    if ($host = f1c.jp.net) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name f1c.jp.net;
    return 404; # managed by Certbot


}
```

以下コマンドでNginxの設定ファイルの構文チェックを行い、 `successful` と表示されればOKです。
```
$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

ブラウザから、SSL証明書を発行したドメインを指定してHTTPS通信によって通信が暗号化されていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/234275/baf883d3-09a2-3d51-b6fc-2475d62e4f2a.png)

# 参考
[Ubuntu 20.04でLet’s Encryptを使用してNginxを保護する方法](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04-ja)
[Certbotを使ってSSL証明書を発行し、HTTP通信を暗号化しよう](https://avinton.com/academy/creating-ssl-certificate-by-certbot/)