読者です 読者をやめる 読者になる 読者になる
pixiv insideは移転しました! ≫ http://inside.pixiv.blog/

Let's EncryptとnginxでHTTP/2サーバを立てる

この記事は ピクシブ株式会社 Advent Calendar 2015 10日目の記事です。

qiita.com


こんにちは。Androidアプリエンジニアのいとおちゃんです。

高校生の頃からアルバイトとしてピクシブに入社してから4年目になりました。昨年は若手アルバイトと名乗っていましたが、気づいたらもう大学生です。最近はpixivマンガアプリの開発をしています。

今回はAndroidアプリ開発の話ではなく、個人的に最もアツいと感じているLet's Encryptを使ってnginxでHTTP/2サーバを立てる話をします。

Let’s Encryptを使おう

Let's Encryptを利用すると、無料で認証されたSSL証明書を簡単に発行することができ、ここ最近話題を集めています。今月、Let's EncryptはようやくPublic Betaになりました。そこで、まさに今が旬ともいえるLet's Encryptを使って、HTTP/2サーバを立ててみました。 以下の手順はUbuntu 14.04 LTS上でサーバにnginxを使ったときのものです。

HTTP/2は実質HTTPSが必要

HTTP/2はその仕様上、暗号化が必須ではありません。しかし、ChromeやFirefoxではHTTPSでのみHTTP/2に対応しています。そのため、HTTP/2に対応するにはHTTPSにする必要があるのです*1

そこでLet's Encryptを使えば、コマンドをたった4回くらい叩くだけで恐ろしく便利かつ簡単に自己証明書を使うことなくブラウザのエラーが出ないHTTPS通信を実現することができます。最高のHTTPS通信はもう目の前です!

Let's Encryptで証明書を発行する

letsencrypt-auto のインストール

今回はこちらを参考にしました。
無料SSL証明書の Let’s Encrypt が公開されたので実際に試してみた | Webセキュリティの小部屋

まず、Let's Encryptで証明書を発行してみましょう。以下の手順はLet's Encryptで証明書を使いたいサーバ上で実行します。 letsencrypt-auto コマンドを使うため、GitHubのリポジトリから適当なディレクトリにcloneしてきます。

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

リポジトリの中に移動すると、 letsencrypt-auto というコマンドがあります。このコマンドの恐ろしいのは、なんと実行するだけで勝手にディストリビューションのパッケージをインストールしてしまいます。Debian系なら apt-get が実行されます。怖すぎ!

./letsencrypt-auto --help

HTTPサーバにApacheを使っているとApacheプラグインがあり、自動でconfの設定をしてくれるようです。しかしnginxは実験的なサポートに限られるため、今回は証明書の発行のみ行います*2。Let's Encryptの証明書は有効期間が3か月なので、その頃には便利になっていると信じましょう。

証明書今すぐ取得

いよいよ証明書を取得します。--webroot オプションを使いHTTPサーバを動かしたままACMEプロトコルの通信します。

${DOMAIN} の部分は証明書を取得したいドメインに変更してください。 -d オプションを複数つけるとマルチドメイン証明書となり、1枚の証明書で無限に複数のドメインに対応できます(例: example.com と www.example.com など)。${WEBROOT} はnginxで設定しているドメインのルートディレクトリに設定します。

./letsencrypt-auto certonly --webroot -d ${DOMAIN} --webroot-path ${WEBROOT}

すると Enter email address という画面が表示されるので、メールアドレスを入力します。 私の環境ではTUIが若干崩れた状態で表示されましたが、気にせずさくさく進めていきます。 f:id:itochan315:20151209181458p:plain

次に、規約に同意します。 f:id:itochan315:20151209181551p:plain

うまくいくと、以下のような表示になります。

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/itochan.jp/fullchain.pem. Your cert
   will expire on 2016-03-08. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - If like Let's Encrypt, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

最新のnginxをインストール

nginxはmainlineとstableがありますが、HTTP/2に対応しているのはmainlineで提供されている1.9.5以降のものです。よって、nginxでHTTP/2を使うにはnginx 1.9.5以降をインストールしましょう。

UbuntuならPPAでインストールするのがお手軽です。その他の環境ではnginxのドキュメントを参照してください。たとえば、RHEL/CentOSであればパッケージが提供されています。

sudo add-apt-repository ppa:nginx/development
sudo apt-get update
sudo apt-get install nginx

nginxのHTTPSとHTTP/2を使う設定

今回Let's Encryptの証明書を発行したドメインでHTTPSとHTTP/2を使える設定をします。以下は設定例です。

server {
  listen 80;
  listen [::]:80;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  server_name itochan.jp;

  ssl_certificate /etc/letsencrypt/live/itochan.jp/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/itochan.jp/privkey.pem;
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA;

  root /var/www/itochan.jp;
}

nginxの設定を service nginx reload などで再読み込みすると、HTTPSが使えるようになっているはずです。

HTTPSとHTTP/2通信を確認してみる

やっとHTTPSとHTTP/2が使えるようになりました。手元のブラウザから確認してみると、HTTPSになっていればChromeではアドレスバーから接続に関する情報が見れます。 f:id:itochan315:20151209202000p:plain:w300

ChromeであればデベロッパーツールのNetworkタブでProtocolの項目を入れると、プロトコルがh2かどうかわかります。

f:id:itochan315:20151209221857p:plain f:id:itochan315:20151209222125p:plain

また、HTTP/2 and SPDY indicatorというエクステンションをインストールすることによりHTTP/2であればアドレスバーにイケてる青いイナズマのアイコンを表示させることができ、HTTP/2であるかどうか確認するのに便利です。ビリビリ。

f:id:itochan315:20151209202504p:plain

もっとセキュアにしたい

今回nginxのデフォルト設定でHTTPSを提供しましたが、この状態でサーバを公開すると脆弱な部分があります。この記事では、安全なHTTPS通信を提供する手順を省略しています。安全にHTTPSを使うにはさまざまな対策を行います。具体的には2048bit以上のDH鍵を使用するなどの対策が必要です。

実際にサーバを外部に公開する場合、安全にHTTPS通信を提供するには弊社の id:harukasan によるQiitaがわかりやすくまとめられているのでおすすめです。 qiita.com

すでにお気づきの方もいらっしゃるかもしれませんが、上記のスクリーンショットでは 証明書の透明性に関する有効な情報がサーバーから提供されました。 と表示されています。これはSSL/TLSのCertificate Transparency(透かし入り証明書)、略してCTの設定をするとブラウザに表示されるものです。

nginxでCTを使うには現状 nginx-ct というモジュールをインストールする必要があるため手間がかかります。でも、 証明書の透明性に関する情報がサーバーから提供されませんでした。 より 提供されました。 のほうがかっこいいじゃないですか。

証明書の透明性に関する情報を提供したい!私はそう思うのですが、余力がある人はnginxをビルドしてnginx-ctを組み込むとよいでしょう。

まとめ

いかがでしょうか。Let's Encryptを使えば手軽にHTTPS通信を実現できます。nginxのHTTP/2サポートも実用的なものになっています。

ピクシブではエンジニアを募集しています!

一発エントリーボタン


次回は @uchienneo による素敵な作品に出会えるメディア、pixiv Spotlightのお話です。楽しみですね!

*1:参考: HTTP/2 Frequently Asked Questions | HTTP/2 Japan Local Activity

*2:letsencrypt-auto なのに全然autoじゃないと思われるかもしれませんが、GitHubを見る限り活発に開発されているようなので対応を待ちましょう。