無料でSSLドメイン認証書が利用できるLet’s Encryptを使ってec2にインストールしたwordpress + nginxにSSLの設定してみたので手順を残しておきます。ついでに、SSL証明書の期限が90日なので期限が20日以下になった時点でCronから自動で証明書を更新する設定も追加しました。

Let’s Encryptについては無料SSLサーバ証明書のLet’s Encryptを使ってCloudFrontをSSL化する方法に記述しているのでそちらを参考にしてください。

WordpressはEC2のAmazon Linuxで動作しています。

SSL証明書の取得

Let’s EncryptのSSL証明書は会員登録も不要です。certbotコマンド実行のみで取得することができます。

certbotのインストールと設定

インストールは簡単にできた。

ec2-user $ sudo su -
root$ curl -s -L -O https://dl.eff.org/certbot-auto
root$ chmod +x ./certbot-auto

証明書の取得

証明書の取得方法はいくつかあるが、nginxのwebrootに認証用のファイルを自動で設置して認証から証明書取得までやってくれる方法を使ってみる。

certbot-autoコマンドは初回実行時に勝手に必要なファイルをインストールしてくれるので特に何もしなくても良い。

root$ ./certbot-auto certonly --webroot -w /var/www/wordpress \
-d ********.com --agree-tos -m ********.com@gmail.com --debug

コマンドの各オプションの詳細は./certbot-auto --help allで確認することができます。
簡単に説明すると、certonlyで証明書の取得のみを行うモードを指定し、--webroot -w /var/www/wordpressでwordpressのパスに認証用のファイルを設置し、-d ********.comで指定したドメインのSSL証明書を取得し、--agree-tosで利用規約に同意し、-m ********.com@gmail.comでメールアドレスを指定すると言った形です。

コマンドが成功すると以下の様に表示されます。

IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/********.com/fullchain.pem. Your cert will
expire on 2016-10-04. To obtain a new or tweaked version of this
certificate in the future, simply run certbot-auto again. To
non-interactively renew *all* of your certificates, run
"certbot-auto renew"

次のように証明書が作成されていることが確認できます。

root$ ls /etc/letsencrypt/live/********.com/
cert.pem chain.pem fullchain.pem privkey.pem

sslの強化のためDH鍵交換に使うdhparam.pemを生成しておきます。後ほどnginxの設定で使います。必須ではありませんが、設定しておくことをオススメします。

root$ openssl dhparam 2048 -out /etc/letsencrypt/live/********.com/dhparam.pem

nginxの設定

ssl関連で設定した項目だけピックアップしておきます。詳細の説明は長くなるので割愛します。

設定を適用する前にwordpress側でhttpsの設定をしておくといいかもしれません。

server {
listen 443 ssl;
listen [::]:443 ssl;
(...)
ssl_stapling_verify on;
ssl_certificate "/etc/letsencrypt/live/********.com/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/********.com/privkey.pem";
ssl_dhparam "/etc/letsencrypt/live/********.com/dhparam.pem";
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:SEED:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!RSAPSK:!aDH:!aECDH:!EDH-DSS-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!SRP;
ssl_prefer_server_ciphers on;
(...)

といった感じです。設定ファイル全体はGistにあげておきます。

nginxを再起動してwordpressがhttps化されていればOKです。

root$ /etc/init.d/nginx restart

証明書の更新

証明書は90日の期限が設定されているため、有効期限が切れる前に更新する必要があります。

以下のコマンドで更新することができます。

root$ mv ./certbot-auto /usr/local/bin
root$ /usr/local/bin/certbot-auto renew --force-renew

成功すると以下の様に表示されます。

Congratulations, all renewals succeeded. The following certs have been renewed:
/etc/letsencrypt/live/********.com/fullchain.pem (success)

nginxを再起動して画面を確認すると証明書の有効期限が更新されていることが確認できます。

Cronで自動更新

更新忘れを防ぐために次のようにCronでスクリプトを自動実行します。

証明書をチェックして有効期限が20日以下だと更新コマンドを実行します。コマンドに失敗した場合はメールで更新失敗を通知します。

root$ vi /etc/cron.daily/cert_check.sh
#!/bin/bash

CERT_PATH=/etc/letsencrypt/live/********.com/cert.pem
VERIFY_DAYS=20
MAIL_ADR="ishii.tech@gmail.com"

END_DATE=`openssl x509 -in $CERT_PATH -noout -enddate | sed 's/^notAfter=//'`
END_DATE_UNIX=`date +%s --date="$END_DATE"`
NOW_UNIX=`date +%s`

REMAINING_DAYS=`expr \( $END_DATE_UNIX - $NOW_UNIX \) / 86400`

if [ $REMAINING_DAYS -le $VERIFY_DAYS ] ; then
/usr/local/bin/certbot-auto renew --force-renew
if [ $? -eq 1 ] ; then
echo "証明書更新失敗(********.com)" | /usr/sbin/sendmail -oem -t $MAIL_ADR
echo "${date}: Certificate update failure." >> /var/log/cert_check.log
else
echo "${date}: Certificate update success." >> /var/log/cert_check.log
else
/etc/init.d/nginx restart
fi
fi

実行権限付与もお忘れなく。

$ chmod +x /etc/cron.daily/cert_check.sh

めんどくさい人はこちら。毎月1日の00:00に更新コマンドを実行しnginxを再起動します。

$ vi /etc/crontab
0 0 1 * * /usr/local/bin/certbot-auto renew --force-renew && /etc/init.d nginx restart

まとめ

更新スクリプトを作りこめば完全放置ができそうですね。一応念の為に証明書が切れていないか確認する処理をlambdaから実行するとおしゃれかもしれない。

おわり。