Node.jsにおけるhttpsサーバの設定とLet's Encryptによる無料のサーバー証明書取得

Node.jsでhttpsサーバーを実行させる方法と、Let’s Encryptによるサーバー証明書を無料で発行する方法に関するメモ

Let’s Encryptについて

最近は、正式リリースされてCertbotとも言われている

Let’s Encryptは、個人が保持しているドメインに対し、サーバー証明書を、無料で発行してくれる認証局(CA)で、ちゃんとした団体が運営している。

通常ベリサインなどにお願いして、お金を払って自分のドメインに対し証明書を発行してもらうか、いわゆる”オレオレ証明書”をopensslツールを使って証明書を自分で作成するしかない。しかも、オレオレ証明書の場合、実際に設定したHTTPSサイトにアクセスすると、Chromeなどでは、

20160229002037.png

のような画面が表示されたり、URLバーにもhttpsの所にバツ印が表示されてとても印象が悪い。

20160228224236

オレオレ証明書の詳細を見ると、不明な機関によって署名されているという文言が不安を助長させる。

20160228223010

Let’s Encryptを使えば、高額な料金を課金しなくても、公式にドメイン認証を取得し、セキュアなサイトが気軽に作成できるようになる。
※あくまでドメイン/サーバー認証であって、企業認証、EV認証を無料で取得できるわけではない。それらの認証を受けるためには従来の認証局から証明書を有償で発行してもらう必要がある。

証明書の作成

--webrootを指定することによって、現在稼働中のHTTPサーバーで認証処理が可能になる。
ほかにも--standaloneオプションがあるが、これはツールがHTTPサーバーを自動起動して
処理するので、稼働中サイトを一時的に停止しないといけない。

ツールは、-wで指示する場所に一時ファイルを作成し、外部からそのURLにアクセスする。
httpアクセスのステータスが正常の場合に存在するドメインと見なされて認証される。

letsencryptコマンドが作成する一時ファイルについて

証明書作成の成功のポイントは、

  • -wで指示したサーバールート直下に以下のファイルが作成できること。
.well-known/acme-challenge/xxx_txt
  • http://<指定したドメイン>/.well-known/acme-challenge/xxx_txtにアクセスできること。

    ちなみにブログツールのghostだと、favicon.icoが存在する[install path]/ghost/core/shared/
    がパブリックルートのようだ。

    また、プロキシやポートフォワードなどを使っていると、認証に失敗するので(方法はありそうだが、わからなかった)、自分の場合は、素直に一時的に80ポートで直接参照できるHTTPサーバーを起動させて認証させた。

-wにつづけて-dでドメイン名を指定する。複数指定することも可能。
あと-mオプションでメールアドレスを指定すると、証明書の期限が迫るとメールでお知らせしてくれる。

> sudo letsencrypt certonly --webroot -w /home/web/appsrv/public -d usagi1975.com -m hoge@hoge.com

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.usagi1975.com/fullchain.pem. Your cert
   will expire on 2017-05-09. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.
 - If you 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

ファイルの作成場所

証明書は/etc/letsencrypt以下にドメイン名のフォルダが作成されて、
実ファイルとシンボリックリンクが作成される。証明書の期限は90日間である。

  • cert.pem
    サーバ証明書(公開鍵)
  • chain.pem
    中間証明書
  • fullchain.pem
    サーバ証明書(公開鍵)+ 中間証明書
  • privkey.pem
    秘密鍵

証明書の作成の実行ごとにcert1.pem, cert2.pem..と作成されて上書きされることはない。
そのため、作成更新が異なることに注意する。更新を延長するのであれば、必ず更新
する必要がある。

sudo ls -l /etc/letsencrypt/live/[domain name]
合計 0
lrwxrwxrwx 1 root root 41  2月  9 09:30 cert.pem -> ../../archive/[domain name]/cert[n].pem
lrwxrwxrwx 1 root root 42  2月  9 09:30 chain.pem -> ../../archive/[domain name]/chain[n].pem
lrwxrwxrwx 1 root root 46  2月  9 09:30 fullchain.pem -> ../../archive/[domain name]/fullchain[n].pem
lrwxrwxrwx 1 root root 44  2月  9 09:30 privkey.pem -> ../../archive/[domain name]/privkey[n].pem

ちなみに再作成は、1日あたり5回?程度なので、試行時に注意すること。

証明書の更新

コマンド引数にrenewを指定することによって、期限が残り30日未満の証明書のみが更新される。また、ポートフォワーディングやプロキシを使っていると作成に失敗すると記載したが、更新に関しては、上記が正式稼働している状態でも、停止や一時的なサイトを稼働させることなく更新が成功する

> sudo letsencrypt renew
Processing /etc/letsencrypt/renewal/[domain].conf
The following certs are not due for renewal yet:
  /etc/letsencrypt/live/[domain]/fullchain.pem (skipped)
No renewals were attempted.

期限が迫ってない証明書も強制的に更新する場合は、--force-renewをつけると全てのファイルが更新される。また、--dry-runオプションをつけると、実際には更新せずにテストだけ実施できる。

> sudo letsencrypt renew --force-renew
Processing /etc/letsencrypt/renewal/[domain].conf
new certificate deployed without reload, fullchain is /etc/letsencrypt/live/[domain]/fullchain.pem

Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/[domain]/fullchain.pem (success)

nodeによるHTTPSサーバーの構築

Nodeのhttpsモジュールをダウンロードし、以下のように公開鍵、秘密鍵をロードしてcreateServerのオプションとして渡すことによってhttpsサーバーが起動する。

var https = require('https');
var fs = require('fs');
var options = {
  key: fs.readFileSync('/etc/letsencrypt/live/usagi1975.com/privkey.pem')
  ,cert: fs.readFileSync('/etc/letsencrypt/live/usagi1975.com/cert.pem')  
};
var server = https.createServer(
    options
    ,app
);

サーバーが起動したら、早速ブラウザからアクセスしてみる。オレオレ認証だと、警告画面の表示や、URLに×印が表示されていたが、そいういったエラーも発生しない。
(セキュリティ高めの社内ネットワークからだと、×印出ることもある)

20160228224041.png

証明書の詳細をブラウザから確認した時のキャプチャが以下になる

20160228223150.png

ちゃんと発行元のLet’s Encryptの名称や設定したドメイン名が記されている。