Node.jsでhttpsサーバー
を実行させる方法と、Let’s Encryptによるサーバー証明書を無料で発行する方法に関するメモ
Let’s Encryptについて
最近は、正式リリースされてCertbotとも言われている
Let’s Encryptは、個人が保持しているドメインに対し、サーバー証明書を、無料で発行してくれる認証局(CA)で、ちゃんとした団体が運営している。
通常ベリサインなどにお願いして、お金を払って自分のドメインに対し証明書を発行してもらうか、いわゆる”オレオレ証明書”をopensslツールを使って証明書を自分で作成するしかない。しかも、オレオレ証明書の場合、実際に設定したHTTPSサイトにアクセスすると、Chromeなどでは、
のような画面が表示されたり、URLバーにもhttpsの所にバツ印が表示されてとても印象が悪い。
オレオレ証明書の詳細を見ると、不明な機関によって署名されているという文言が不安を助長させる。
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に×印が表示されていたが、そいういったエラーも発生しない。
(セキュリティ高めの社内ネットワークからだと、×印出ることもある)
証明書の詳細をブラウザから確認した時のキャプチャが以下になる
ちゃんと発行元のLet’s Encryptの名称や設定したドメイン名が記されている。