ウェブサイトは常時 SSL(TLS) 化!と言われるようになって久しいですが、古い環境を Let's Encrypt で常時 SSL 化する際にハマりやすいポイントとその解決策を、備忘録も兼ねて書いておきます。
片手間でサーバーも多少かじっているだけ…といった感じの、初心者向けの内容です。
想定している環境
- しばらく update していない CentOS 6 系
- Apache 2.2 系
等、大人の事情により古い環境のまま運用する場合や、古い環境からアップデートする場合を想定しています。
常時 SSL 化テンプレート
それなりに新しい環境なら、以下のような流れで、無料で簡単に常時 SSL 化できます。慣れれば 5 分とかかりません。良い時代になったものです。
1. certbot-auto で webroot プラグインを使用する
webroot プラグインは、ドキュメントルートの下に一時的に .well-known/acme-challenge
というディレクトリを作成し、そこを使って認証作業をしてくれるものです。certbot-auto が全部勝手にやってくれます。
# -- certbot-auto最新版のインストール
$ cd /usr/bin/
$ wget https://dl.eff.org/certbot-auto
$ chmod 700 ./certbot-auto
# -- certbot-autoのバージョン(2019年4月17日時点:0.32.1)
# -- 最近のバージョンでは、certbot-autoを動作させるのに必要なPython等がインストールされていなかった場合、
# -- このタイミングで自動的にインストールされるようになっています。
$ certbot-auto --version
# -- 証明書の発行
$ certbot-auto certonly \
--agree-tos \
--webroot \
-w /path/to/document/root \
-d example.com \
-d www.example.com \
-m info@example.com --no-eff-email
2. Apache の VirtualHost を設定
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /path/to/document/root
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
</VirtualHost>
<Virtualhost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /path/to/document/root
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
</VirtualHost>
# -- IPアドレス制限等をかけている場合は、webrootプラグインが利用するディレクトリの制限を外す
# <Directory "/path/to/document/root/.well-known/acme-challenge">
# Require all granted
# </Directory>
3. 証明書を自動更新するように設定
# -- とりあえず dry run してみて…
$ certbot-auto renew --dry-run
# -- 問題がなければ、cron に証明書を更新する処理を登録
$ certbot-auto renew --post-hook "Apache を再起動させるコマンド"
dry-run でこける時は、以下も参考にしてみてください。
4. Qualys SSL Labs で判定してもらう
SSL 化した結果を判定してくれるサービスは幾つかありますが、Qualys SSL Labs が有名だと思います。
古い環境でのトラブル
…と、たった 5 分程度で終わる作業の筈が…
wget(あるいは curl)で怒られる
$ wget https://dl.eff.org/certbot-auto
で ERROR: cannot verify dl.eff.org's certificate
と怒られるような環境は、その後の作業や構築した環境で色々と問題が出る可能性が非常に高いため、特に支障がないのであれば、update
した方が良いです。(いきなり乱暴)
$ yum clean all && yum upgrade -y
古い環境では、ここで以下のようなエラーが出る場合もあります。
Error: Cannot retrieve repository metadata (repomd.xml) for repository: XXXXX
その場合は、該当リポジトリを無効化した上で実行します。
$ yum upgrade -y --disablerepo=XXXXX
# -- 複数ある場合は
$ yum upgrade -y --disablerepo=XXXXX,YYYYY,ZZZZZ
もしくは、yum の設定を変更してから実行します。
$ cd /etc/yum.repos.d
# -- enabled=1 を enabled=0 に変更します
$ cp XXXXX.repo XXXXX.repo.org && /
vi XXXXX.repo
certbot-auto が動かない - 1
certbot-auto 初回利用時には…
$ certbot-auto --version
…としてバージョンを確認する癖を付けておくと、最近のバージョンでは、certbot-auto の動作に必要な環境を自動的に整えてくれるので、非常に楽です。
しかし、ここで以下のようなエラーが出てしまった場合は…
To use Certbot, packages from the EPEL repository need to be installed.
Enable the EPEL repository and try running Certbot again.
EPEL リポジトリを有効化してね!という事ですので…
# -- enabled=0 を enabled=1 に変更します
$ yum install -y epel-release && /
cd /etc/yum.repos.d && /
cp epel.repo epel.repo.org && /
vi epel.repo
certbot-auto が動かない - 2
IP 制限やベーシック認証等をかけている場合、webroot プラグインの仕様上、.well-known/acme-challenge
の制限を外してやる必要がある事は、テンプレにも書いた通りです。
ところが、きちんと制限を外したにも関わらず…
- The following errors were reported by the server:
Domain: example.com
Type: unauthorized
Detail: Invalid response from http://example.com/.well-known/acme-challenge/....
…のように怒られてしまった場合、Apache2.4 系 と 2.2 系 との書き方の違いが原因かもしれません。Apache2.2 系では、Require all granted
ではなく Allow from all
と書きます。
<Directory "/path/to/document/root/.well-known/acme-challenge">
Allow from all
</Directory>
また、Apache2.2 系では、NameVirtualHost
ディレクティブを書く必要がある点にも注意です。
NameVirtualHost *:80
NameVirtualHost *:443
<VirtualHost *:80>
#略#
</VirtualHost>
<Virtualhost *:443>
#略#
</VirtualHost>
http ⇒ https の自動リダイレクトがおかしい
http ⇒ https と自動的にリダイレクトさせたい時は、以下のように書くとよく紹介されていますが、これには罠があるので注意が必要です。
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
この書き方の場合、Apache のバージョンとクライアントの組み合わせによっては、問題が発生します。
例えば、http://example.com/?%E9%AF%96
にアクセスした場合…
HTTP/1.1 301 Moved Permanently
Location: https://example.com/?%E9%AF%96
…と、http:// が https:// に置換された結果を期待しますよね? ところが、この設定の場合は…
HTTP/1.1 301 Moved Permanently
Location: https://example.com/?%25E9%25AF%2596
…と、URL エンコードされた部分がおかしくなる('%' が更に二重で URL エンコードされている)ケースがあります。
これは、RewriteRule
で指定したリダイレクト先の URL を、自動的にエスケープするという機能があるためです。これを無効化するためには [NE] = No Escape
を指定します。
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
ちなみに、^(.*)$
ではなく ^.*$
と ( )
を省いて書いているのは、正規表現でキャプチャする必要がないからです。
mod_rewrite で「全てにマッチ」を表現するには、他にも以下のような書き方がありますが、正規表現の意味を理解しないまま、安易に ( )
を使うべきではないのではないでしょうか。
.*
^
$
Qualys SSL Labs の判定で怒られる
様々な苦労を経てやっと SSL 化に成功!
仕上げに Qualys SSL Labs で判定してもらって、最低でも A 判定をもらいたいところですが、結果は B や C…酷いと F 判定なんて事もあります。
Apache2.2 系では、証明書の指定方法が違う
Apache2.4 系(正確には 2.4.8 以降)では、以下のように 2 行で指定します。
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
しかし Apache2.2 系では、以下のように 3 行で指定します。
SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
ここを間違っていても、Apache2.2 系では問題なく動いているように見えてしまうので、注意が必要です。
参考:https://httpd.apache.org/docs/2.4/ja/mod/mod_ssl.html#sslcertificatechainfile
Apache の SSL 周りの設定がおかしい
Qualys SSL Labs で A 判定が取れる、Apache のデフォルト設定に近い最低限の設定は、以下の通りです。
- Apache2.2 系では、デフォルトで RC4 が無効化されていないので注意です。
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:MEDIUM:!RC4:!aNULL:!MD5
- Apache2.4 系
SSLProtocol all -SSLv3
SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
TLS1.2 に限定したい、A+ 判定を狙いたい等、よりセキュアな設定については、「apache SSLCipherSuite」辺りで適当にググってみてください。
Apache が TLS1.2 に対応していない
レアケースだと思いますが、Apache をソースコードからビルド(configure ⇒ make)している場合、その時の環境があまりにも古く、ビルド時の OpenSSL 等のバージョンが低いと(?)、Apache が TLS 1.2 に対応していない場合があります。
その場合、Apache をビルドし直すのが無難です。前回の configure の内容は、configure した際のディレクトリ内の、config.nice
というファイルに書いてありますので…
$ cat source/to/httpd-2.2.x/config.nice
その内容を参考に、2.2 系の最新最終バージョンである 2.2.34 をビルドし直します。
# -- md5sum というところが泣けます(笑)
$ cd /path/to/work/dir && \
wget http://archive.apache.org/dist/httpd/httpd-2.2.34.tar.gz && \
wget http://archive.apache.org/dist/httpd/httpd-2.2.34.tar.gz.md5 && \
md5sum --check httpd-2.2.34.tar.gz.md5
$ tar -zxvf httpd-2.2.34.tar.gz && \
cd ./httpd-2.2.34
# -- configureの内容は環境に応じて…
$ ./configure \
--prefix=/path/to/apache \
--enable-so \
--enable-ssl \
--enable-rewrite
$ make clean all
$ make install
もちろん、2.4 系で問題ないなら、この際 2.4 系にします。流れ的には以下のような感じです。最新バージョンのダウンロード先は、↓で確認してください。
$ cd /path/to/work/dir && \
wget http://ftp.riken.jp/net/apache//httpd/httpd-2.4.39.tar.gz && \
tar -zxvf httpd-2.4.39.tar.gz && \
wget http://ftp.riken.jp/net/apache//apr/apr-1.7.0.tar.gz && \
tar -zxvf apr-1.7.0.tar.gz && \
wget http://ftp.riken.jp/net/apache//apr/apr-util-1.6.1.tar.gz && \
tar -zxvf apr-util-1.6.1.tar.gz
# -- APRとAPR-utilをsrclibディレクトリ内へ移動
$ mv apr-1.7.0 httpd-2.4.39/srclib/apr && \
mv apr-util-1.6.1 httpd-2.4.39/srclib/apr-util && \
cd ./httpd-2.4.39
# -- configureの内容は環境に応じて…
$ ./configure \
--prefix=/path/to/apache \
--with-included-apr \
--enable-so \
--enable-ssl \
--enable-rewrite
$ make && make install
PHP 等もソースコードからビルドしていた場合は、同様の流れで、config.nice
で前回の configure を確認してからビルドし直すという事になります。