Let's Encrypt とは
HTTPSを有効化するためには、認証局(CA)から証明書を取得する必要があります。Let's Encryptは、そのような認証局の一つであり、ウェブサイトのドメインに対して無料のSSL/TLS証明書を発行してくれます。本記事では、Let's EncryptとNginxを組み合わせてウェブサイトをHTTPS化する方法を解説します。
Certbot とは
Certbotは、Let's Encryptの公式クライアントツールです。これを使うことで、無料のLet's Encrypt証明書を簡単に取得できます。CertbotはUnix系のオペレーティングシステムをサポートしており、本記事の例ではCentOS 7環境を想定しています。
無料証明書の取得
- Certbotクライアントのインストール
yum install certbot
- 証明書の取得
まずは--webrootモードで証明書を取得します。このモードは、ウェブサイトのドキュメントルートに一時的な認証ファイルを配置することでドメインの所有権を証明します。
certbot certonly --webroot -w /var/www/mydomain -d mydomain.com -d www.mydomain.com
このコマンドは、http://mydomain.comとhttp://www.mydomain.comの両方に対して証明書を生成します。--webrootオプションは、/var/www/mydomainディレクトリ内に.well-knownフォルダを作成し、その中に認証に必要なファイルを配置します。Certbotはhttp://mydomain.com/.well-known/acme-challengeにアクセスすることで、ドメインがこのサーバーに正しく紐づいているかを検証します。多くの場合、この方法で問題なく証明書を取得できます。
しかし、マイクロサービスのようにドキュメントルートを持たない一部のサービスでは、--webrootモードが使えません。そのような場合は、--standaloneモードが便利です。このモードはウェブサイトのルートディレクトリを指定する必要がなく、サーバーの443番ポートを一時的に使用してドメインの検証を行います。もしNginxなどの他のサービスが443番ポートを占有している場合、証明書の生成前にそのサービスを停止する必要があります。
certbot certonly --standalone -d mydomain.com -d www.mydomain.com
証明書の生成が完了すると、/etc/letsencrypt/live/ディレクトリにドメイン名のフォルダが作成され、そこに証明書へのシンボリックリンクが保存されます。
Nginx 設定による HTTPS 有効化
次に、WebサーバーであるNginxを設定してHTTPSを有効にします。以下はNginxの設定例です。
server {
server_name mydomain.com www.mydomain.com;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:4000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
server {
server_name api.mydomain.com;
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/api.mydomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.mydomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
}
}
この設定では、443番ポートをリッスンし、SSLを有効にして、証明書ファイル(公開鍵と秘密鍵)のパスを指定しています。これにより、HTTPSが正常に機能するようになります。
SSL証明書の自動更新
Let's Encryptの証明書は90日間の有効期限を持っています。そのため、期限が切れる前に証明書を更新する必要があります。Certbotはcertbot renewという便利なコマンドを提供しています。このコマンドは、システム内の証明書を自動的にチェックし、更新が必要なものを更新してくれます。
まずはテスト実行してみましょう。
certbot renew --dry-run
テスト実行中に、以下のようなエラーが発生することがあります。
Attempting to renew cert from /etc/letsencrypt/renewal/api.mydomain.com.conf produced an unexpected error: At least one of the required ports is already taken.. Skipping.
これは、--standaloneモードで証明書を生成した場合に起こり得ます。証明書の更新時にも443番ポートが必要になるため、他のサービス(ここではNginx)がポートを占有しているとエラーになります。この問題を解決するには、更新処理の前にNginxを停止し、処理完了後に再起動する必要があります。
この更新処理は、Linuxのcronジョブで自動化できます。以下は、毎月1日の午前3時に証明書を更新するcronジョブの例です。
0 3 1 * * certbot renew --pre-hook "service nginx stop" --post-hook "service nginx start"
--pre-hookは更新処理の前に実行するコマンド、--post-hookは処理完了後に実行するコマンドを指定します。ここでは、ポート競合を避けるためにNginxを停止・起動しています。
最後に、このcronジョブをシステムに登録します。
crontab renew_ssl_certs.cron