CentOS8にnginxをインストールする – Webページの暗号化(HTTPS化)

最近ではWebサーバは基本的にSSLで暗号化した上で通信されています。(ここではSSLと言っていますが実際にはその後継のTLS接続となります)

URLがhttpsから始まるサイトがそれです。

暗号化しないと通信経路上に居る悪意のあるユーザに情報を引っこ抜かれる恐れがあります。

もちろん、パスワードのかかっていないような誰でも見れることが前提のWebサーバであれば理論上あまり意味は無いのですが、最近のブラウザは暗号化されていないサイトには警告を出したりするので、理由がなければ対応した方が良いかと思います。

今回は「Let’s Encrypt」という証明書を取得できるサービスを使って暗号化したいと思います。(無料で手に入ると言っても怪しいものではなく、有名どころのセキュリティ企業やWeb企業が出資しているものですのでご安心を)

※この記事では前提としてドメインを持っていること(DDNSサービスなどの無料ドメインでも可能です)、インターネットからサーバにアクセスできることが必要です。このサイトでは未だドメイン取得やサーバの公開(ルータの設定)については取り扱っていませんので、他のサイトを参考に行ってください。

この記事で行うこと

  1. ファイアウォールの設定
  2. Certbotのインストール
  3. Certbotを使って証明書を取得
  4. NginxでのSSL接続設定
    1. 自動設定の内容の確認
    2. 自動設定のロールバック
  5. 証明書の管理
    1. 自動更新の設定
    2. 証明書内のドメインの追加・削除

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

HTTPS化を行うに当たってはHTTPの80番ポートに加え、HTTPSの443番ポートの開放も必要です。

以下のコマンドを実行します

[root@localhost ~]# firewall-cmd --add-service=http --add-service=https --permanent
[root@localhost ~]# firewall-cmd --reload

※既にポートが開放されている場合はWarningが出ますが、特に問題はありません。

ポートの開放について詳しくは以下のページを参考にしてください。

2. Certbotのインストール

CertbotはLet’s Encryptの証明書を取得するためのソフトウェアです。

CertbotのインストールにはEPELリポジトリが必要となります。

EPELリポジトリは以下のコマンドで追加できます。

[root@localhost ~]# dnf install epel-release

EPELリポジトリを追加したら、Certbotをインストールします。

[root@localhost ~]# dnf install certbot

python3-certbot-nginx はWebサーバにnginxを使っている場合にWebサーバを止めないまま証明書取得を行えるようにするためのモジュールです。

自動更新を行うのに必要なのでインストールしておきましょう。(さもないと3ヶ月おきにnginxを停止して、証明書を更新して、nginxを起動し直す羽目になります)

3. Certbotを使って証明書を取得

証明書を取得するコマンドは以下の通りです。(このコマンドはnginxが起動している必要があります)

[root@localhost ~]# certbot --nginx
  • certbot : Certbotを実行するコマンドです。そのまんまです。
  • --nginx : 起動しているnginxを使って証明書を更新すると言うオプションです。

このコマンドを実行すると対話的に設定を進められます。(質問に答えていくことで証明書を取得できます)

また、自動的にnginxの設定にHTTPS化の設定を付け加えてくれます。

ただ、自動設定なので稀に不具合が出るようです。

もし、nginxの設定は自分で行いたいという場合は以下のようにコマンドに certonly を付け加える事で自動設定を無効化することもできます。

[root@localhost ~]# certbot certonly --nginx

ただ、自動設定で不具合が起きても自動で設定される前の設定に復元出来ます。

このため、今回はまず自動設定を試してみたいと思います。(設定の復元方法は4-2に記載しています)

コマンドを実行した際に出てくる質問の内容は以下の通りです<>内に質問の概要を載せています。

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): <メールアドレスを記載>

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: <規約に同意するにはaを入力(同意しない場合は証明書取得不可)>

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing 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: <Let's Encryptの情報をメールに送っても良いか(Nで入力しても証明書取得可)>

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: exsample.com
2: www.exsample.com
(nginxのserver_nameに設定されているドメインが全て羅列される)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):<どのドメインに対して証明書を取得するか(複数に対して取得する場合は半角スペース区切りで番号を羅列、全てに対して取得する場合は空欄で可)>

これで証明書の取得及びnginxの設定は完了です。

nginxを再起動してから、ブラウザでサーバに接続してみてください。

[root@localhost ~]# systemctl restart nginx

ブラウザに表示されるアドレスの先頭が http:// から https:// になっていれば成功です。

なおこの時、ローカルIPアドレス(192.168.で始まるIPアドレス)で接続するとエラーが出るようになります。

証明書を取得したドメインからアクセスするようにしましょう。

また、同じLAN内からは特別に設定しない限りドメインでアクセスすることは出来ません。

接続確認はWifiに繋いでいないスマートフォンなどで行うようにしましょう。

4. NginxでのSSL接続設定

4-1. 自動設定の内容の確認

自動更新によってnginxの設定ファイル conf.d/default.conf の設定が以下のように変わっていました。

※変わる前の設定は以下ページを参照してください。

localhost とあった部分が example.com に変わっているのは手動です。これはそもそもlocalhostでは証明書を取れないためです。

server {
    server_name  example.com;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    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
}

まず、serverコンテキストが1つ増えています。

上のserverコンテキストは listen 443 ssl 、下は listen 80 となっています。

先に下の listen 80 とあるコンテキストから確認してみましょう。

自動設定で追加された設定は # managed by Certbot と記載があるのでその設定だけを追っていきます。

    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

この設定はもしアクセスしてきたURLのドメインが正しいドメインの場合、httpsの同じアドレスに転送するというものになります。HTTPではアクセス出来なくさせるわけですね。

また、最下部の return 404; # managed by Certbot は正しくない場合は404エラーを返すという事を表しています。

次に上のコンテキストですね。

ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot

これは証明書の場所を指定する項目です。実際に ls コマンドを使って確認すると、そういったファイルが存在していることが確認できます。

正確にはこのファイルはエイリアス(Windowsでいうショートカット)で実在のファイルではありません。

これは証明書を更新する度に証明書のファイル名が変わるので、その度に設定修正をする手間を省く為になります。

ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot

これは証明書と対になる秘密鍵を指定する項目です。こちらも証明書同様にエイリアスとなります。

include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

これはSSLに関する設定を読み込ませる部分です。後で中身を確認します。

ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

これは証明書の共有を行う為の鍵を指定するものとイメージしてください。

続いて、先程の /etc/letsencrypt/options-ssl-nginx.conf の中身を確認してみましょう。

ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

では以下に解説します。

ssl_session_cache shared:le_nginx_SSL:10m
  • ssl_session_cache : SSLセッションのキャッシュ(接続の履歴)を記憶するか。記憶する場合は同じセッションがあった際に使い回せて処理効率が上がる。
  • shared : 記憶して、かつnginx内で共有をする設定。
  • le_nginx_SSL : shared の場合のみ設定。任意の名前を付ける。同じ名前が付いている場合は別のserverコンテキストで設定されたものともキャッシュが共有される。
  • 10m : shared の場合は設定。キャッシュのサイズを指定する。1メガバイトで4000セッションほど保存できるので、10mだと40000キャッシュ程度。個人サーバではそんなに要らない気も……
ssl_session_timeout 1440m;
  • セッションをどれほど記憶しておくか。今回は1440mと指定されているので1440分=24時間。
ssl_session_tickets off;
  • これに関しては詳細不明ですが、どうやらセッションのキャッシュをサーバ側ではなくクライアント側に持たせるという機能が存在するようです。今回はこの機能はoffになっています。
ssl_protocols TLSv1.2 TLSv1.3;
  • 利用するSSLのプロトコルです。SSLの、と言いながらSSLは含まれていません。SSLの全てのバージョンと、TLSの1.0, 1.1はもう破られうるので使わないのが普通です。たぶん、将来はTLSv1.2も消して、TLSv1.4を加えたり或いはTLS自体が消えてもっと別のプロトコルに書き換えたりする必要があると思います。
ssl_prefer_server_ciphers off;

最終的にどの暗号を選択するかの優先選択権をサーバが持つという設定です。そもそも危ない暗号は使えない設定にしているので、クライアントに好きな暗号を選ばれても問題ないということでoffになっているようです。

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

利用可能にする暗号の種類をコロン区切りで列挙しています。一定以上の強度を持つ暗号のみ列挙されています。

4-2. 自動設定のロールバック

自動設定のロールバックは以下のコマンドで行うことが出来ます。

[root@localhost ~]# certbot --nginx rollback

ファイルの変更毎に復元のチェックポイントを設けているようなので、上記のコマンドを以下のエラーが出るまで繰り返し実行しましょう。

Certbot hasn't modified your configuration, so rollback isn't available.

設定が復元されたら4-1の内容を参考に、自分で設定を行ってみましょう。

5. 証明書の管理

5-1. 自動更新の設定

Let’s Encryptの自動更新は以下のコマンドで設定できます。

[root@localhost ~]# systemctl enable --now certbot-renew.timer
Created symlink /etc/systemd/system/timers.target.wants/certbot-renew.timer → /usr/lib/systemd/system/certbot-renew.timer.
  • --now : enable コマンドを使うときに設定することで、 start も同時に実行されるというオプションです。

ちゃんと設定されているか確認する際には以下のコマンドを実行してください。

[root@localhost ~]# systemctl list-timers | grep certbot
Sun 2020-07-12 01:04:24 JST  7h left       n/a                          n/a       certbot-renew.timer          certbot-renew.service
  • list-timers : 自動実行されるタスクの一覧を表示します。
  • | : パイプと呼ばれ、この記号の前のコマンドで出力された内容をこの記号の後のコマンドで処理します。今回の場合は systemctl list-timers で出力されたリストを grep certbot で処理すると言った具合です。
  • grep certbot : grep は引数の文字列を含む行だけを出力します。今回はcertbotを含む行だけを抜き出す事になります。

また、自動更新で失敗しないように事前に更新に問題が無いか以下のコマンドで確認しましょう。

[root@localhost ~]# certbot renew --dry-run
  • renew : 証明書の更新を行うコマンドです。前回と同じ方法証明書を再取得し、更新してくれます。
  • --dry-run : 実際に証明書を取得せず証明書が取れそうかを確認するためのオプションです。証明書の取得は週に5回までしか行えないという制約があるので、このオプションでテストだけを行います。

ここで、エラーが出なければ問題なく証明書が更新できるはずです。

5-2. ドメインの追加・削除

新しいドメインでサーバにアクセスできるようにしたとき、またはもう使わないドメインが出たとき、わざわざ証明書を作り直すのは面倒です。

以下のコマンドを使うことで、証明書で使えるドメインを追加・削除することが出来ます。

[root@localhost ~]# certbot certonly --cert-name [証明書名] -d [証明所に含みたいドメイン名] --nginx
  • --cert-name [証明書名] : ドメインを追加・削除したい証明書の名前を入力します。証明書の名前は certbot certificates で表示される証明書一覧の Certificate Name の項目となります。
  • -d [証明書に含みたいドメイン名] : 証明書に含みたいドメイン名を半角スペースかカンマ区切りで羅列します。新たに記載されたドメインは追加され、記載されていないドメインは削除されます。

まとめ

今回はnginxでWebサイトをHTTPS化する方法を説明しました。

実際の設定はソフトウェアを1つインストールしてコマンドを1つ実行して聞かれたことに答えるだけで良かったりするのですが、問題があったときのためにもちゃんと設定を理解して必要に応じて変更できるようにしておきましょう。

次回はnginxでPHPを使うための設定に触れたいと思います。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です