CentOS 6.x に無料SSL Let's Encrypt を導入する

/






条件


* Apacheのバージョンは2.2.15以上とする
* オレオレ証明書を既に使っている
* 443ポートは解放済み
* バーチャルホストで運営している
* CentOS 6.x

この条件で以下作業を行なっていく。
rootになって/rootディレクトリで操作した。


手順


1. certbotをダウンロード
2. Apacheを停止
3. certbotを使って鍵を作成
4. Apacheに鍵のパスを記述
5. Apacheを再起動
6. 自動更新の設定


python3.6のインストール


$ yum install -y https://centos6.iuscommunity.org/ius-release.rpm

$ yum install -y python36*

$ ln -s /usr/bin/python3.6 /usr/bin/python3

$ ln -s /usr/bin/pip3.6 /usr/bin/pip3


参考:
CentOS6にPython3入れる


curlのアップデート


curlが古いとうまくいかないので事前にアップデートしておく。
yum update curl


certbotをインストール


git clone https://github.com/letsencrypt/letsencrypt


Apacheを停止


Apacheを止めないと証明書を作れないので止めておく。
/etc/rc.d/init.d/httpd stop


certbotを使って鍵を作成


いくつか質問されるが難しいことはない。

cd letsencrypt

./letsencrypt-auto certonly -a standalone -d hogedomain.com


/etc/letsencrypt/live/hogedomain.com/ 内に鍵が作られた

ls /etc/letsencrypt/live/hogedomain.com/
README  cert.pem  chain.pem  fullchain.pem  privkey.pem


Apacheに鍵のパスを記述


Apacheにこの鍵のパスを設定する。

vi /etc/httpd/conf.d/ssl.conf

##以下を書き換える
SSLCertificateFile /etc/letsencrypt/live/hogedomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/hogedomain.com/privkey.pem



Apache 再起動


停止していたApacheを起動する。
/etc/rc.d/init.d/httpd start

これでルートドメインにSSL付きでアクセスできる。


サブドメインでもLet's Encryptを使えるようにする


サブドメイン毎に設定してやらなければならない。
やり方はルートドメインの時と同じ。
./letsencrypt-auto certonly -a standalone -d sub.hogedomain.com

vi /etc/httpd/conf.d/virtualhost.conf

##以下を追加
<VirtualHost *:443>
    ServerName sub.hogedomain.com
    DocumentRoot /somewhere/hogedomain/sub

    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/sub.hogedomain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/sub.hogedomain.com/privkey.pem

    ErrorLog logs/sslvirtual_error_log
    CustomLog logs/sslvirtual_access_log combined env=!no_log
   NameVirtualhost *:443
</VirtualHost>



自動更新の設定


Let's Encryptは3ヶ月しか有効期限がないので、自動更新するとよい。更新のためのコマンドをcronする。
まず、下記のコマンドが正常に動作し、証明書が更新されるかをテスト。
renewは、すべての証明書を更新するコマンド。--post-hookオプションで指定したコマンドは、renew後に実行される。ただし、renewは期限が迫らないうちは、実行がスキップされ、その場合はpost-hookも実行されない。
Let's Encryptを使ってSSL証明書を自動更新する(AWS/Amazon Linux/Apache)

上の記事のように自動更新の設定をしていたのだが、なぜかその後に更新をしてくださいという内容のメールが来てしまった。

Hello,

Your certificate (or certificates) for the names listed below will expire in 20 days (on 18 Aug 18 07:08 +0000). Please make sure to renew your certificate before then, or visitors to your website will encounter errors.

We recommend renewing certificates automatically when they have a third of their
total lifetime left. For Let's Encrypt's current 90-day certificates, that means
renewing 30 days before expiration. See
https://letsencrypt.org/docs/integration-guide/ for details.

hogehoge.com

For any questions or support, please visit https://community.letsencrypt.org/. Unfortunately, we can't provide support by email.

If you are receiving this email in error, unsubscribe at http://mandrillapp.com/track/unsub.php?u=30850198&id=e6af6ce87eeb49cab9f7c4584c8d49da.Xdoz7jXx662gLBduhGy%2FwZtnakk%3D&r=https%3A%2F%2Fmandrillapp.com%2Funsub%3Fmd_email%3Daraemonz%2540gmail.com

Regards,
The Let's Encrypt Team


どうも、Apacheを停止してから更新処理をしていなかったのが原因のようだ。

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

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/hogehoge.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert is due for renewal, auto-renewing...
Plugins selected: Authenticator standalone, Installer None
Renewing an existing certificate
Performing the following challenges:
tls-sni-01 challenge for hogehoge.com
Cleaning up challenges
Attempting to renew cert (hogehoge.com) from /etc/letsencrypt/renewal/hogehoge.com.conf produced an unexpected error: Problem binding to port 443: Could not bind to IPv4 or IPv6.. Skipping.


ということで以下のようにcronに登録してみた。
毎月の7日、04時00分に実行する。

vi /etc/cron.d/letsencrypt

00 04 01 * * root /etc/rc.d/init.d/httpd stop && /usr/bin/certbot-auto renew && /etc/rc.d/init.d/httpd start


分 時 日 月 曜日 <実行コマンド>


faviconでエラー


ブラウザーが小さい警告表示を出していた。
原因はfaviconだった。
ブラウザーがfaviconを勝手にリクエストするようで、faviconを設置していなかったためにhttpでリダイレクトエラーが出たということ。
faviconを設置して無事エラーはなくなった。


.htaccessでhttpsへリダイレクト


httpでアクセスしても自動でhttpsへリダイレクトするように.htaccessを編集。

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]



Let's Encrypt自動更新ができなかったときの解決法 (2019-03-11 追記)


Let's Encryptの自動更新がうまくできず、次のようなメールが届いてしまった。

Hello,

Your certificate (or certificates) for the names listed below will expire in 19 days (on 31 Mar 19 18:05 +0000). Please make sure to renew your certificate before then, or visitors to your website will encounter errors.

We recommend renewing certificates automatically when they have a third of their
total lifetime left. For Let's Encrypt's current 90-day certificates, that means
renewing 30 days before expiration. See
https://letsencrypt.org/docs/integration-guide/ for details.


Let's Encryptの自動更新が無事に解決できたのでメモを残しておくことにした。


エラーログの確認をする


まずはLet's Encryptのログを確認してみる。

cat /var/log/letsencrypt/letsencrypt.log

すると次のような更新失敗のエラーがログに残っていた。

2019-03-01 14:00:09,322:DEBUG:certbot.plugins.selection:Requested authenticator standalone and installer None
2019-03-01 14:00:09,323:DEBUG:certbot.renewal:no renewal failures


cronの問題なのかなんなのか。まずは手動で実行して更新できるか確認してみる。

/usr/bin/certbot-auto renew

やっぱりSSL証明期限の更新が出来ない。次のようなエラーが吐かれた。

Upgrading certbot-auto 0.31.0 to 0.32.0...
Replacing certbot-auto...
Creating virtual environment...
Error: Command '['/opt/eff.org/certbot/venv/bin/python3', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1


よくわからないけれど、Python関係でエラーになっている感じだ。


解決への糸口


先程のエラーを元にいろいろと調べてみた。すると次の記事にたどり着くことができた。
CentOS6でletsencript更新に失敗した時の解決策

こちらの記事によれば scl enable python27 './certbot-auto renew' というコマンドで実行すれば良いとのことである。しかし scl ってなに? python27 って python2.7 の間違いじゃないの?などと最初は思ったが、この方法で最終的に解決することができたのだ。これら謎のコマンドはこれから順を追って説明していく。



SCLをインストールする


まずはSCLってなんぞや?調べてみたら次の記事が参考になった。
Software Collections (SCL) を CentOS に入れてみた

ようするにSCLとは、本来ふるいCentOSでは使えないはずの最新アプリケーションを実行可能なようにしてくれるものらしい。例えばyumでインストールできないパッケージとか。


つぎのコマンドで有無を言わさずsclをインストールしてみる。

$ yum install centos-release-scl-rh


Python27のなぞ


ここまで来ると勘が働くようになる。最初に紹介されていたコマンド scl enable python27 './certbot-auto renew'certbot-autoPython2.7.x で実行すると言うことではなかろうか。調べてみるとやはり Python27 というのはSCLで提供されている Python2.7.x のパッケージ名のことのようだ。

なるほどですね! CentOS 6.x のyumでは Python2.6.x までしかインストールできないが、SCLを使えば Python2.7.x を使えるようにしてくれるということだ!


さっそくSCLで使用するための Python27 パッケージをインストールする。

$ yum -y install python27


インストールできたところで、現在のpythonのバージョンを確認してみよう。

$ python --version
Python 2.6.6


あれれ? Python 2.6.6 のままである。

しかしあわてることはない。✋
先程インストールした Python27 パッケージをSCLで実行すればPython2.7.x を使うことができるのだ!

$ scl enable python27 bash
$ python --version
Python 2.7.13


みごと Python 2.7.13 へ切り替わった!

しかしシェルをログアウトすると Python 2.6.6 に戻ってしまうね。つまりSCLは一時的にパッケージを指定してプログラムを実行するものということでさぁーね。



SSL証明書の更新


ここまで来てようやく本題のSSL証明書の更新を行ってみることにしよう。次のように SCLPython27 を使って certbot-auto を実行してみる。

$ scl enable python27 '/usr/bin/certbot-auto renew'

するとSSL証明書の更新が無事に開始された。ほっ♨、としたところで確認する。あれれ?サイトにアクセスできない。非常に焦る💦。よく見ると次のようなエラーが出ていた。

httpd を起動中: [Tue Mar 12 11:51:51 2019] [warn] module ssl_module is already loaded, skipping
(98)Address already in use: make_sock: could not bind to address [::]:443
                                                           [  OK  ]



Apache起動でエラー


先程のApache起動時のエラーは「ssl_moduleが既に読み込まれてるからスキップしますよ」という内容のようだった。さらに調べてみると、SSLの設定が重複していることが原因でエラーが発生していることがわかった。

このことでピンときた!思い当たるフシがあるのだ。

すぐに cd /etc/httpd/conf.d/ で移動して ll コマンドを実行する。

思ったとおりだ。ディレクトリ内にSSL設定のファイルが2つ存在している。 末尾が ssl.conf で終わるファイルが2つある。

この原因は大昔のことだ。もともと私がApache設定のときに、デフォルトの ssl.conf をコピペして本番用の設定を書き込んだからである。

それによって未設定の ssl.conf ファイルをApacheが読み込んでしまい、本番用の設定ファイルが読み込まれないという自体になっていたのだった。しかし今までは問題にならなかったぞ?なんか怖くて不思議だ。

その問題は横においておき👀、使っていない ssl.conf をどうにかした後、Apacheを再起動させてみた。

無事にエラー無くApacheを起動することができた。ここでようやくサイトへ接続でき、SSL証明書の期限の更新も確認することができた。

以上ですべての修正を終えることができた。今までで、Let's Encryptの自動更新がスムーズにできたためしがない。今後またこのようなトラブルが起こるかもしれないと思うと、若干の不安は残っている。まぁ無料SSLという選択をしてしまったのだからそこはDo it yorselfってなことですね、分かります。それでもたくさんの失敗のおかげで、Linuxやサーバー管理の勉強になっているので良しとしましょうか。



cronの設定


おっと!最後にcronの設定も忘れずに書き換えておかなければならない。

今度こそ「自動更新がうまくいきますように!」と、強い思いを込めて!

00 14 01 * * /etc/rc.d/init.d/httpd stop && scl enable python27 '/usr/bin/certbot-auto renew' && /etc/rc.d/init.d/httpd start


記述方法 分 時 日 月 曜日 <実行コマンド>


5/21 追記


3ヶ月後また自動更新エラーのメールが来てしまった。手動では更新できる。もしかしたらと思い、cron登録を少し修正した。次のようにrootで実行するようにオプションをつけてみた。これで様子をみてみたいと思う。

00 14 01 * * -u root /etc/rc.d/init.d/httpd stop && scl enable python27 '/usr/bin/certbot-auto renew' && /etc/rc.d/init.d/httpd start



参考


* CentOS6でletsencript更新に失敗した時の解決策
* Python 2.7 インストール(yum)(CentOS 6.8)
* Software Collections (SCL) を CentOS に入れてみた
* Cent OS 6で手軽にPython 2.7を使う方法
* Cent OS 6で手軽にPython 2.7を使う方法