Ubuntu + nginx + LetsEncryptでSSL/TLSを設定する


Ca Tech Dojo/Challenge/JOB Advent Calender 2019の21日目は@akubi0w1が書かせていただきます!
明日は@TakumaKurosawaくんです!

HTTPS通信が使いたくて震えたのでやってみましたという記事です。
サーバサイドでインターンしておきながら...

SSL/TLSってなんぞ

SSL(SecureSocketLayer)/TLS(TransportLayerSecurity)は暗号化や認証の機能を提供するプロトコルです。
盗聴、改ざん、なりすましの防止、通信を安全に行うことができるようになります。

SSL/TLSの種類も複数あり、大きく分けてドメイン認証、企業認証、EV認証があります。
細かい説明は省略します...気合いがあれば追記します...。

Let’sEncryptとは

Let’sEncryptってなんなの、という話です。

Let’s Encrypt is a free, automated, and open Certificate Authority.

Let’sEncryptとは無料で、自動化された、オープンな認証局です!

トップページにどーんって出てきます。もう少しだけ掘り下げると、

The objective of Let’s Encrypt and the ACME protocol is to make it possible to set up an HTTPS server and have it automatically obtain a browser-trusted certificate, without any human intervention.

ドメイン認証を用いた「HTTPS サーバーのセットアップと、ブラウザが信頼する証明書の自動的な取得を、人間の仲介なしに可能にすること」を目標としたサービスになります。

Let’s Encrypt is a Certificate Authority (CA) that provides an easy way to obtain and install free TLS/SSL certificates

無料のSSL/TLS証明書を簡単にインストールできるそうです。

となれば

実際にやってみた

ここにそってやっていきます。

環境

  • Ubuntu16.04
  • nginx
  • ConoHa VPS

ドメインはexample.comを登録する体で書きます。実際に試すときは適宜置き換えてください。

HTTPS通信に443ポートを使うので開いていない場合は開けておきます。今回はConoHaのVPSを使うので、ConoHaのコントロールパネルから確認。

サーバタブ > ネームタグ > ネットワーク情報 > 接続許可ポート から確認。

sshで接続する場合はSSH(22)の方も開けておきましょう。

ロードバランサーを利用している場合はそちらの設定も。
ネットワークタブ > ロードバランサー > バランシング設定 から確認。

ここからはサーバ側での作業です。

0. 事前準備

独自のドメインで行う場合は、ドメインのAレコードがサーバのIPアドレスに割り当てられている必要があります。この辺りの設定はドメインを取得したサービスによって異なります。

dig example.comで調べることができます。

1. リポジトリの取得

最初にCertbotというソフトウェアをインストールします。Let’sEncryptでは、Certbotを使用してSSL証明書を取得します。

まずはUbuntuのリポジトリに最新のCertbotを追加します。

$ sudo add-apt-repository ppa:certbot/certbot

 This is the PPA for packages prepared by Debian Let's Encrypt Team and backported for Ubuntu.

Note: Packages are only provided for currently supported Ubuntu releases.
 More info: https://launchpad.net/~certbot/+archive/ubuntu/certbot
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmp1wxvucvl/secring.gpg' created
gpg: keyring `/tmp/tmp1wxvucvl/pubring.gpg' created
gpg: requesting key 75BCA694 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmp1wxvucvl/trustdb.gpg: trustdb created
gpg: key 75BCA694: public key "Launchpad PPA for certbot" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

2. certbotのインストール

次にUbuntuのパッケージリストを更新します。

$ sudo apt-get update

Hit:1 http://jp.archive.ubuntu.com/ubuntu xenial InRelease
Hit:2 http://jp.archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:3 http://jp.archive.ubuntu.com/ubuntu xenial-backports InRelease
Get:4 http://ppa.launchpad.net/certbot/certbot/ubuntu xenial InRelease [24.3 kB]
Hit:5 http://security.ubuntu.com/ubuntu xenial-security InRelease
Hit:6 http://ppa.launchpad.net/jonathonf/python-3.6/ubuntu xenial InRelease
Get:7 http://ppa.launchpad.net/certbot/certbot/ubuntu xenial/main amd64 Packages [18.6 kB]
Get:8 http://ppa.launchpad.net/certbot/certbot/ubuntu xenial/main i386 Packages [18.6 kB]
Get:9 http://ppa.launchpad.net/certbot/certbot/ubuntu xenial/main Translation-en [10.9 kB]
Fetched 72.5 kB in 3s (23.4 kB/s)
Reading package lists... Done

最後にCertbotのインストール!

$ sudo apt-get install python-certbot-nginx

3. nginxのconfigを書きます

そのまんまですね。Certbotは自動でSSLの設定を行なってくれるので、編集は一瞬。

/etc/nginx/sites-available/defaultを編集します。
独自の設定ファイルがある場合は、そちらの方を編集します。
以下は独自の設定ファイルの例になります。

$ sudo vi /etc/nginx/sites-available/example.conf

server{
    ...
    server_name example.com;
    ...
}

nginxの設定にミスがないか確認します。
以下のコマンドでconfigにエラーが見つかったら適宜直しましょうー。

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

最後にnginxを再起動させて、設定ファイルの編集は終わりです。

$ sudo service nginx restart

4. ファイアウォールの設定

ufw(UncomplicatedFireWall)を利用します。使い方がありえないほど簡単。

まずファイアウォールが有効になっているか確認します。

$ sudo ufw status

Status: inactive

こうなる場合は、$ sudo ufw enableでファイアウォールを有効にしておきます。
sshで繋いでいる場合、有効化した状態でsshを切断するとsshが使えなくなる可能性があります。
以下のコマンドでポートを開けておきましょう。ポートを変更している場合は適宜読み替えてください。

$ sudo ufw allow 22 // sshポートが22の場合

プラスで80も開けておきます。httpすら遮断されてしまうので...

$ sudo ufw allow 80

以上のことをやり切るとこうなります。

$ sudo ufw status

Status: active

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

次に、HTTPSで利用するポートを開けます。デフォルトで443です。

$ sudo ufw allow 443

Rule added
Rule added (v6)

$ 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を走らせる環境ができました。

5. 証明書の取得

ドメイン認証を使用して証明書を取得します。

今回はnginxプラグインを使います。

$ sudo certbot --nginx -d example.com

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges
Deploying Certificate to VirtualHost /etc/nginx/sites-enabled/example.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/example.conf

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://example.com

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

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/example.com/privkey.pem
   Your cert will expire on 2020-03-02. 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

IMPORTANT NOTESにCongratulations!と出れば成功です。errorがあれば修正。
ポートが開いているかとかnginxの設定に誤りがないかとか、見直してみると割と...

成功しているとnginxの設定ファイルに少し設定が追加されています。
# managed by Certbotと付いている部分は自動で追加されたものです。

$ cat /etc/nginx/sites-available/example.conf
    ...
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/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 = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name example.com;
    return 404; # managed by Certbot
}

ここまでできたら、https://example.com で繋がるようになります。
アドレスバーに鍵がつきましたー!

6. 自動更新してくれるように

証明書の有効期限を自動で更新してくれるよう設定します。

$ sudo certbot renew --dry-run

Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/example.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator nginx, Installer nginx
Starting new HTTPS connection (1): acme-staging-v02.api.letsencrypt.org
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for example.com
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
new certificate deployed with reload of nginx server; fullchain is
/etc/letsencrypt/live/example.com/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/example.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

うまくいくとこんな感じ。successって出してくれます。

以上で設定終了です!お疲れ様でしたー!

終わりに

インフラに寄っていくにつれて闇が深まっている気がします。かつトラブルシュートが難しくなっていく気がします。めちゃめちゃ楽しいです。
何をするにも基盤って結局とても大切なので、最低限は知っとかないといけないなあと思います。...頑張ろ。
「繋がるってすごい」って思いを味わってほしいです!

参考

SSL/TLSの解説と選び方まとめ
Let's Encrypt
How To Secure Nginx with Let's Encrypt on Ubuntu 16.04