Let’s Encrypt でサイトの SSL 化

Let’s Entrypt という素晴らしいサービスが無料のSSL証明書が提供していると同僚に教えてもらったので、試しにこのサイトに導入することにしました。
このエントリーは導入過程のメモです。

Let’s Encrypt は Certbot というコマンドラインインターフェースを持っていて、証明書の取得とインストール、更新までコマンドでできるようになっているとのこと。なんとまあ便利ですね。

証明書の有効期限は90日間しかないので、crontab などで有効期限前に自動で更新していく運用が望ましいみたいです。ではそうしていきましょう。

事前に以下の準備をしておきます。

  • Really Simple SSL プラグインを WordPress にインストールしておく
  • ファイヤーウォールがあるならインバウンド 443 ポートを開けておく

また、環境としてはさくらのVPS(CentOS 6)で Nginx + WordPress を動かしている状態です。

証明書のインストールとWebサーバーの設定

サーバーに SSH でログインして、作業開始。
certbot-auto スクリプトをダウンロードして、 /usr/bin に移動、実行権限をつけて、実行。ウェブサーバーは Nginx なので、--nginx オプションをつける。

$ wget https://dl.eff.org/certbot-auto
$ sudo mv ./certbot-auto /usr/bin/certbot-auto
$ sudo chmod a+x /usr/bin/certbot-auto
$ sudo certbot-auto --nginx

これでインストールウィザードが始まる。 以下のくだりでは「2」と答えておくと、Nginx 設定ファイルにリダイレクトの設定を勝手に書き込んでくれる。

Please choose whether HTTPS access is required or optional.
-------------------------------------------------------------------------------
1: Easy - Allow both HTTP and HTTPS access to these sites
2: Secure - Make all requests redirect to secure HTTPS access
-------------------------------------------------------------------------------

設定を反映させる。

$ sudo service nginx reload

この状態でもうすでにSSL化はできていた。https でサイトにアクセスしてみると以下のような状況。

SSL証明書を表示確認しているところ

http 接続を https 接続に強制リダイレクトをかける。
certbot-auto が /etc/nginx/conf.d/default.conf に設定を書き込んでいるが、コメントアウトされているのでそれを外して有効にする。

     # Redirect non-https traffic to https
-    # if ($scheme != "https") {
-    #     return 301 https://$host$request_uri;
-    # } # managed by Certbot
+    if ($scheme != "https") {
+        return 301 https://$host$request_uri;
+    } # managed by Certbot

設定を反映させる。

$ sudo service nginx reload

最後に自動更新の設定。
毎週日曜日の5時に更新処理が走るように設定した例。

$ sudo crontab -e

0 5 * * 0 certbot-auto renew --post-hook "service nginx reload" >/dev/null 2>&1

Really Simple SSL プラグインを使う

インストールしてアクティベートすると以下のようなメッセージが表示される。

Relly Simple SSL Plugin

「Go ahead, activate SSL!」ボタンを押す。すると以下のようなメッセージが表示される。

SSL activated!  Don't forget to change your settings in Google Analytics en Webmaster tools.  More info.

えっと…、本当に簡単だな…。
Google Analytics と Webmaster tools の面倒も見ろとな。あとでね。

以上です。


P.S.

URLが変わるので、はてブ数などはリセットされてしまいます。まぁそれはそうだわな。
本文「likealunatic.jp」を検索 - はてなブックマーク


References

webpack にまつわるぐだぐだ。キャッシュ対策と CommonsChunkPlugin

webpack (version 2) の公式ドキュメントではバンドルファイルのブラウザキャッシュ対策として、ファイル名にハッシュ値を埋め込む方法が提案されている

こうするとアプリのコードを変更する度に、バンドルファイル名に埋め込まれたハッシュ値も更新され、ブラウザキャッシュ対策ができる、という寸法だが…。
当然ファイル名が変わるわけだから、<sript> タグも更新しなくてはならない。それを解決するには、HTML ファイルも動的に扱わなければならない。chunk-manifest-webpack-pluginhtml-webpack-plugin を導入し、HTML のテンプレーティングを行い…、となると今使っている Pug はどうなる…、となってさらにさらに掘り下げないといけなくなり、はっきり言ってソリューションとして無理がある。

閑話休題。

webpack をヘビーに使っていると、サードパーティーフレームワークやライブラリのコード(npm install でインストールしたようなモジュール)を出力ファイル(バンドルファイル)から切り離したくなる。 バンドルファイルにライブラリが直接含まれるが故に、以下のような事象に直面したことがある開発者は多いのではないだろうか。

  • 複数人で開発していて各自のライブラリのバージョンが微妙に異なり、Git経由でやり取りされるバンドルファイルに環境の差分までが含まれてしまう
  • 使っているライブラリが増えて、コンパイルがとても遅くなる

解決策として、フレームワークやライブラリはまとめて別のバンドルファイルにする、もしくは単独で配布されたものを <script> タグを読み込む、という解決方法を取ることもできる。 これを可能にするのが externals オプションで、ここで宣言された名前については、依存関係がグローバルスコープから参照されるようになる。

externals: {
  jquery: 'jQuery'
}

webpack.config.js に設定しておくと、 import jQuery from 'jquery'; というコードはグローバルスコープの jQuery を参照するようになり、バンドルファイルに jQuery のコードは含まれないようになる。 もちろんこの場合には jQuery は新たに別の <script> タグで読み込む必要ある。

よりスマートな解決策としての CommonsChunkPlugin

CommonsChunkPlugin を使うと、複数のバンドルファイルから共通の依存モジュールを切り出してくれる。 サードパーティーライブラリをアプリのコードと分割する、という使い方ももちろんできる。 公式で示されている設定は以下のようなものだ。

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: "vendor",
    minChunks: function(module){
      // node_modules のディレクトリ下に含まれるものだけに絞る
      return module.context && module.context.indexOf("node_modules") !== -1;
    }
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: "manifest", // 名前は "manifest" でないとダメ
    minChunks: Infinity // entryがいくつあろうと生成。省略可
  }),
]

サードパーティーコードを別にしたいだけなら vendor だけでも目的は果たせるが、manifest を入れると、webpack バンドル共通部分(ソースには webpackBootstrap とコメントが書かれている部分)が manifest.js として別ファイルに書き出される。こうするとビルドするたびに vendor のハッシュ値が変更されることを防げるとのこと。
でもこれ、先述のハッシュ値をファイル名に含めるキャッシュ対策をやっていないと、意味はなさそう。なぜならハッシュ値はバンドルファイルのコード内には現れないから。

manifest を定義した場合、以下のように manifest.js も読み込まないとコードは動かないので注意。

<script src="/js/manifest.js"></script>
<script src="/js/vendor.js"></script>
<script src="/js/bundle.js"></script>

References