chrome firefox IE safari chain youtube-play pocket hatena facebook feedly github google-plus rss twitter search code envelope-o home pencil website works calendar drawer tag
2016/12/07

[VPS]Let’s Encryptを取得してサイトをHTTPS化にする

最近話題のLet’s Encryptを取得してサイトをhttps化にする方法をご紹介します。環境はCentos7.2でApacheを使用してSSL/TLSの証明書を取得します。またCronによる自動更新までご紹介します。

Let’s encrypt を取得してサイトをhttps化にする

昨今、Googleが公式にHTTPSサイトの順位を引き上げるという話が話題になりましたので、
このサイトもVPSに乗り換えた際にhttps化にしました。

今回は取得方法からApacheに設定してサイトをhttps化にする方法を紹介したいと思います。

設定環境
ローカル: Mac/OS: Mac Sierra
ConoHa VPS
VPS: CentOS Linux release 7.2.1511 (Core)
Apache2.4.6 (CentOS)
作業用ユーザ名: devuser
sftpユーザ名: sfuser

Let’s Encryptとは

Let’s Encrypt は、無料で利用できる自動化されていてオープンな認証局(CA)です。公共の利益を図る目的で Internet Security Research Group (ISRG) が運営しています。

Let’s Encrypt 総合ポータル より引用

SSL/TLSと呼ばれるデータを暗号化して通信するプロトコルがあるのですが、このプロトコルを使用することによりセキュアな通信を行えます。使用する為には証明書が必要となります。
今までだと、https化をする為にSSL/TLSを発行している会社などに申請と申請料を支払い、証明書をもらう必要があるのですが、値段も高く、セキュアにしなければならないサイトぐらいでしか使われていませんでしたが、もっと気軽にhttpsを使ってもらいたい、ということから生まれたのがLet’s Encryptです。ややこしいことは抜きにして本当に簡単に取得、更新が可能です。

https化にするメリットとしては、冒頭にあるGoogleのインデックスが優先されたり、http2と呼ばれるさらに早いプロトコルを使用できたりと、今後は必須になっていくと思われます。

httpsのポートを解放する

作業用ユーザでSSHでVPSにアクセスします。

まずは、httpsのポートを開けてあげる必要があります。
firewallのサービスの中にhttpsが用意されているので、サービスの登録を行います。

$ sudo firewall-cmd --add-service=https --zone=public —permanent
success

ポートを開けた後は、設定の再読み込みを行い、httpsが登録されているかチェックします。

$ sudo firewall-cmd --reload
success
$ firewall-cmd --list-all
public (default, active)
interfaces: eth0
sources:
services: dhcpv6-client http https ssh
ports:
masquerade: no
forward-ports:
icmp-blocks:
rich rules:

httpsが空いていることを確認できれば、次に進みます。

Let’s Encryptのクライアントcertbotのインストール

最近yum経由でインストールできるようになったようですが、私が調べた感じだと、Github経由で持ってくるやり方の方がまだ多いようです。何回か作っては再構築し直しをしているのですが、Github経由でも問題なく取得出来ました。

今後はyum経由での方法が一般的になると思いますので、そちらの手順で行きます!

yumを使ってLet’s Encryptのクライアントcertbotをインストールしていきます。

$ sudo yum install certbot
 Loaded plugins: fastestmirror, langpacks
 base | 3.6 kB 00:00:00
 epel/x86_64/metalink | 3.8 kB 00:00:00
 epel-debuginfo/x86_64/metalink | 4.0 kB 00:00:00
 epel-source/x86_64/metalink | 3.8 kB 00:00:00
 extras | 3.4 kB 00:00:00
 mariadb | 2.9 kB 00:00:00
 updates
 -省略-
 Installed:
 certbot.noarch 0:0.9.3-1.el7

Dependency Installed:
 dialog.x86_64 0:1.2-4.20130523.el7 pyOpenSSL.x86_64 0:0.13.1-3.el7
 python-cffi.x86_64 0:0.8.6-2.el7 python-cryptography.x86_64 0:0.8.2-1.el7
 python-enum34.noarch 0:1.0.4-1.el7 python-ndg_httpsclient.noarch 0:0.3.2-1.el7
 python-parsedatetime.noarch 0:1.5-3.el7 python-ply.noarch 0:3.4-10.el7
 python-psutil.x86_64 0:2.2.1-1.el7 python-pycparser.noarch 0:2.14-1.el7
 python-zope-component.noarch 1:4.1.0-1.el7 python-zope-event.noarch 0:4.0.3-2.el7
 python-zope-interface.x86_64 0:4.0.5-4.el7 python2-acme.noarch 0:0.9.3-1.el7
 python2-certbot.noarch 0:0.9.3-1.el7 python2-configargparse.noarch 0:0.10.0-1.el7
 python2-dialog.noarch 0:3.3.0-6.el7 python2-mock.noarch 0:1.0.1-9.el7
 python2-pyrfc3339.noarch 0:1.0-2.el7 pytz.noarch 0:2012d-5.el7

Complete!

Completeと表示されたらインストール完了です。証明書発行のコマンドは以下となります。

$ sudo certbot certonly --webroot --email メールアドレス -w /home/sfuser/public_html/ドメイン名/ -d ドメイン名

certonly : 証明書発行のみ
–webroot : Apache/Nginxのサーバを利用する(サーバを止めることなく取得可能)
–email : 証明書の期限近くになると更新通知を送ってくれます
-w : ウェブルートパス,サイトのドキュメントルートを指定します
-d : 証明するドメイン名(-d またはカンマ複数ドメイン指定可能)

私の場合はドメインが全く別のものを二つ持っていたので、それぞれ別々にコマンドを実行して、2枚証明書は発行しました。無事に発行出来たら、以下の文言が出るかと思います。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
 /etc/letsencrypt/live/example.com/fullchain.pem. Your cert will
 expire on 2017-02-18. To obtain a new or tweaked version of this
 certificate in the future, simply run certbot again. 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

無事に発行された証明書は /etc/letsencrypt/live/ 以下にドメイン名として保存されます。

また、一つのドメインにサブドメインを持たせていた(ex. example.com と test.example.com)ので、example.comのエイリアス(SAN)として証明書を発行しました。その際は以下のようなコマンドで実行します。

$ sudo certbot certonly --webroot --email test@gmail.com -w /home/sfuser/public_html/example.com/ -d example.com -d www.example.com -d test.example.com -d aaa.example.com

一番最初に指定したドメインがメインとして設定され、そのあとに記述したサブドメインはメインのエイリアス(SAN)が設定されて行きます。-d ドメイン名で複数指定が可能です。

認証に失敗した場合のケース

サブドメインも一緒にSANとして登録した際に何故か404エラーになってしまいました。
色々調べた所や原因となりそうな部分を列挙します。

  • httpsのポートを開けていない(ポートに関するメッセージが出ます)
  • サブドメインをDNSに設定していない
  • サブドメインをCNAMEで登録している(Aレコードで設定というメッセージが出る)
  • Apacheのバーチャルホストに設定していない
  • .htaccessによるリダイレクト設定を行なっている
  • .htaccessによる非表示ファイルへのアクセス制御をしている
  • パーミッションやディレクトリの所有権

その他にこれは私が遭遇したケースですが、上記の条件は全てクリアしているのに何故か404エラーで証明書が発行されなかった事がありました。
以下失敗したケースの場合の表示です。

IMPORTANT NOTES:
 - The following errors were reported by the server:

Domain: test.example.com
 Type: unauthorized
 Detail: Invalid response from
 http://test.example.com/.well-known/acme-challenge/LbTK2vUNnkwq0cshIMnee05fy-pABps6IbtHA1D7dgk:
 "<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
 <html><head>
 <title>404 Not Found</title>
 </head><body>
 <h1>Not Found</h1>
 <p"

To fix these errors, please make sure that your domain name was
 entered correctly and the DNS A record(s) for that domain
 contain(s) the right IP address.

最後に書かれている文には、エラーを直すには、ドメイン名が正しいか、またDNSはAレコードに設定にしているかを確認してください。とありましたので、DNSもAレコードで設定し、httpでそのサブドメインにアクセスも可能でさらにパーミッションやディレクトリの所有権なども変えてみましたが変わらず。。

 

その他にしたこと

http://test.example.com/.well-known/acme-challenge/test.html などを作成し、ブラウザからアクセスが可能かどうかもチェックしましたが問題なくアクセスが可能でした。また.well-known以下はrootが所有者になっています。
コマンドの指定方法がダメなのかと思い、以下のようにも変更してみました。

$ sudo certbot certonly --webroot --email test@example.com -w /home/sfuser/public_html/example.com/ -d example.com,www.example.com,test.example.com,other.example.com

※複数ドメインは -dオプションでもカンマ区切りのどちらでも指定可能です。

example.comやother.example.comは認証されていましたが、test.example.comのみ404エラーになって証明書が取得出来ませんでした。
解決策は正直不明ですが、

$ sudo certbot certonly --webroot --email test@example.com -w /home/sfuser/public_html/test.example.com/ -d test.example.com

上記のコマンドのようにtest.example.comに対してだけ証明書を出させてみると認証されたので、そのあとに一番目にしたコマンドを再度実行すると取得出来ました。

 

追記

この記事を書いている時にcronでの更新に失敗しました。以前と同じ404エラーでした。
前回と同じように単体で取得してみると、404エラーになりました。
今回は.well-known/acme-challenge/以下にhtmlファイルではなく、適当なテキストファイル(拡張子無し)を置いてみました。httpでは、アクセス可能でした。

とりあえず、テストで動作を確認します。

$ sudo certbot renew --dry-run

–dry-runを付けることでテストが可能です。
今回は、これで通す事が出来ました。

かなり検索しましたが同じようなケースはApacheではヒットしませんでした。

そもそも、テストで作成したacme-challenge以下のファイルにアクセスが可能である事と、Root権限で動作しているので変なことをしていない限りはディレクトリやファイルの作成は可能であること。
また、同じようなテスト用htmlしか置いていない他のサブドメインでは認証が通っており、何故そのサブドメインのみ認証が通らなかったのか、色々ロジック的に辻褄が合わないのが多いです。。
他のトップドメインレベルが違うものは特に問題なく、認証、更新が通っています。

 

もし、同じような方がいらっしゃれば、単体で一度認証、もしくは適当なファイルを.well-known/acme-challenge/以下に置いてみてアクセスを確認してから、証明書発行コマンドを通してみてはいかがでしょうか。
また原因がわかる方がいれば、教えていただけると幸いです。

SSLの設定

証明書を取得した後は、それぞれのドメインに証明書をセットして行きます。

/etc/httpd/conf.d/vhost.conf や /etc/httpd/conf.d/ドメイン名.conf にそれぞれ設定して行きます。

$ sudo vi /etc/httpd/conf.d/vhost.conf

<VirtualHost *:443>
ServerName example.com
DocumentRoot /home/sfuser/public_html/example.com
SSLEngine on
SSLHonorCipherOrder on
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains"
SSLProtocol -All +TLSv1 +TLSv1.1 +TLSv1.2
SSLCipherSuite HIGH:MEDIUM:!aNULL:!MD5

SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

<Directory /home/sfuser/public_html/example.com/>
Options +FollowSymlinks
AllowOverride All
</Directory>

SetEnvIf Request_URI "\.(gif|jpg|png|css|js)$" nolog
ErrorLog /var/www/example.com/logs/ssl-error_log
CustomLog /var/www/example.com/logs/ssl-access_log combined
</VirtualHost>

<VirtualHost *:80>
ServerName example.com
DocumentRoot /home/sfuser/public_html/example.com
ServerAdmin postmaster@localhost
ErrorLog /var/www/example.com/logs/error_log
CustomLog /var/www/example.com/logs/access_log combined
</VirtualHost>

サブドメインも一緒に取っている場合は使い回しが可能です。
ServerNameとDocumentRootの変更とLogのパスを変更するだけでOKです。
編集が終わったらconfigtestを念のため実行し、apacheの再起動を行います。

$ apachectl configtest
Syntax OK

$ sudo systemctl restart httpd.service

問題なければ、https://example.com/ でhttpsアクセスが可能だと思います。

Cronを設定して自動更新させる

取得した証明書は90日間しか有効ではありません、更新はコマンドで行えます。
まずは、コマンドが通るかテストしてみてください。上の方でも書いていましたが、

$ sudo certbot renew --dry-run

このコマンドで証明書が無事に取れることを確認したら、Cronと呼ばれる
設定した時刻にコマンドなどを自動で実行するものです。
以前の記事でWordPressのバックアッププラグインのBackWPupについて書いたのですが、
それもWordPressのCronで動作しています。
rootで動作させるので、まずはrootに変えてコマンドを実行します。

$ su
# crontab -u root -e
ここでviの編集に移るので、
0 4 1 * * certbot renew && systemctl restart httpd.service

と書いて保存します。

crontabでcronの設定
-u で実行ユーザ
-e で新規cronの作成

-r でユーザの同意なしに消去してしまうオプションがあるらしく、crontabを推奨しない意見もあるそうです。
初めての設定で、他に設定しない、かつ今後あまり触る部分ではなさそうなので私はcrontabで設定しました。

crontab -e は「絶対に」使ってはいけない – ろば電子が詰まっている

0 4 1 * * はそれぞれ左から分、時、月、日、曜日となっております。
この場合だと毎月1日の朝4時0分に実行するという感じです。

これで一応毎月実行されるはずなので、ログ等を確認してください。

以上でLet’s Encryptの設定は完了です!

 

 

このサイトもhttpsにはしているのですが、広告やjQueryなどがあり、完全https化に移行はまだ終わっていません。
ついでに、デザインも変えたいなーと思っているので近々デザインの更新と共に完全https化にしたいと思います。

参考サイト

Let’s Encrypt 総合ポータル

let’s encrypt で複数ホスト名対応な証明書を作る – 日記

Let’s Encrypt サーバー証明書の取得と自動更新設定メモ | あぱーブログ

CentOS 7 + Apache 2.4 で Let’s Encrypt の証明書を導入する手順 | WEB ARCH LABO

今後の励みになりますので、良かったらシェアをお願いします。

このエントリーをはてなブックマークに追加