Ruby
Heroku
Jekyll
SSL
HTTPS

PRで解説する、Jekyll + Heroku で HTTPS 対応

More than 1 year has passed since last update.

AppleのApp Transport Securityが延期になったとはいえ、SEO的にも信頼性的にも「とりあえず https にしとくか」みたいな時代になってきましたね 🤔

ということで、最近話題の Let's Encrypt を使って Jekyll + Heroku で構成されているRailsガイドを HTTPS に対応してみました。

具体的な実装は下記のプルリクエスト (以下、PR) で公開しています。

Enable SSL in Production #277

https://github.com/yasslab/railsguides.jp/pull/277

上記PRから汎用的なコミットをpickupして、1つずつ解説していこうと思います。



  • :beginner: Let's Encryptの使い方や、SSL証明書の取得手順などについては総合ポータルをご参照ください。


  • :warning: 本番環境で動作確認するのは危険なので、HerokuのFork機能などでテスト用の環境を作り、そこで動作確認しましょう。


TL;DR


1. Add acme_challenge gem to be certified

Let's EncryptでSSL証明書を取得するためには、特定のURLにアクセスしたら特定の結果を返す必要があります (ACME CHALLENGEと呼ばれています)。環境変数を使えば良さそうですが、「Jekyllで環境変数を扱うにはどうしたら良いのか?🤔」という点で結構はまっていました :sweat:

_pluginを使った実装とか色々と試してみましたが、結論としては acme_challenge gem が便利でした。

Simple rack middeware for responding to ACME challenge like LetsEncrypt uses.

https://github.com/soffes/acme_challenge

上記のREADMEに詳細がありますが、Jekyll + Heroku の場合は config.ru最初で呼び出すだけです (これだけ!)。

# config.ru

require 'acme_challenge'
use AcmeChallenge, ENV['ACME_CHALLENGE'] if ENV['ACME_CHALLENGE']

あとはローカル環境とプロダクション環境の環境変数 (ACME_CHALLENGE) に、Let's Encrypt で取得したキーを入力します。キーの取得方法は総合ポータルの「Let's Encrypt の使い方」を参照してください。

なお、環境変数に代入する値は戻り値の方です。

Make sure your web server displays the following content at

http://railsguides.jp/.well-known/acme-challenge/FOOBAR before continuing:

FOOBAR.HOGEHOGE
※👆ここに表示される値を ACME_CHALLENGE に代入

If you don't have HTTP server configured, you can run the following
command on the target server (as root):

(中略)

Press ENTER to continue

本番環境でのセットアップが終わったら、総合ポータルの手順に従ってSSL証明書を取得しましょう。


2. Enforce SSL by rack-rewrite gem

1.での手続きが無事に終わると、*.pemが入手できるはずです。まずはそのファイルを Heroku にアップロードします。

$ heroku certs:add \

/etc/letsencrypt/live/railsguides.jp/fullchain.pem \
/etc/letsencrypt/live/railsguides.jp/privkey.pem

これで http と https の両方にアクセスできるようになりますが、せっかくなので https に統一させたいです。そのための実装がこちら。

Enforce SSL by rack-rewrite gem

https://github.com/yasslab/railsguides.jp/pull/277/commits/0cc483958d33e1781d607f3649ee424058222391

上のコミットでは、rack-rewrite gem を使って config.ru に次のコードを追記しています (細かな記法は省略)。

require 'rack/rewrite'

use Rack::Rewrite do
if ENV['RACK_ENV'] == 'production'
r301 %r{.*}, 'https://railsguides.jp$&', :scheme => 'http'
end
end

これをデプロイすれば、ブックマークなどから http://railsguides.jp/ に来る人も https に切り替わるようになります。ただし、後述の問題がまだ残っているので、この時点ではまだ本番環境にデプロイしない方が良いです (テスト用の環境だけにデプロイする) :warning:


3. Implement custom headers with rack-contrib gem

2. で https でも表示できるようになりましたが、実際に https でアクセスしてみると、Facebook の Like ボタンや Twitter の Tweet ボタンなど、他サイトのドメインから埋め込んだコードに対してエラーまたは警告が表示されてしまいます。



エラー例 (Chromeなら Option + Cmd + i で確認)

ここで表示されるエラーおよび警告は、そのサイトでどんなコードを使っているかによって変わります。したがって解決方法もその内容によるところが大きいですが、1つの汎用的な解決策としては、Content-Security-Policy (CSP) に許容するドメインを適宜追加していく方法があります。

例えばRailsガイドの場合は、はてなブックマークやGoogleアナリティクスなどをサイト内で使っているため、次のようなコードを config.ru に追記しています。

require 'rack/contrib/try_static'

use Rack::TryStatic,
urls: %w[/],
root: '_site',
try: ['.html', 'index.html', '/index.html'],
header_rules: [
[:all, {
'Strict-Transport-Security' => 'max-age=31536000; preload',
'X-Xss-Protection' => '1; mode=block',
'X-Content-Type-Options' => 'nosniff',
'X-Frame-Options' => 'DENY',
'Content-Security-Policy' => "default-src 'self' 'unsafe-inline' 'unsafe-eval' *.dropboxusercontent.com *.google-analytics.com *.facebook.net *.facebook.com *.twitter.com ghbtns.com *.hatena.ne.jp *.st-hatena.com *.google.com;"
}],

# (後略)

コミットの詳細: Implement custom headers with rack-contrib gem

(rack/jekyllrun Rake::Jekyll.new置き換えるようにして追記している点に注意してください :warning: )

CSPをどのように対応するかはサイトごとに異なると思うので、必要に応じて適宜コードを修正してください。目安としては、(Chromeの場合) アイコンが鍵マーク🔒に変わったかどうか、Console上にエラーや警告が出ないかどうかなどがあります。

railsguidesjp_SSL-Check.png

他の目安としては、SSL Server Testなどの外部サービスを使ったチェックもあります。どこまで対応するかはケースバイケースだと思うので、その塩梅については各ケースに応じて判断してもらえればと思います :bow:



railsguides.jpのSSL Reportの結果


まとめ (再掲)

https 対応のご参考になれば幸いです 😆


参考記事


宣伝 :loudspeaker:

Railsガイドのソースコードはオープンソースとして yasslab/railsguides.jp から公開され、YassLab社によって運営されています。

コンテンツ内の誤字・脱字はもとより、コードとして改善できそうなところがあれば、お気軽に Issue または PR を送っていただけると嬉しいです! :smile_cat:

yasslab_logo_copy.png