ExpressでもLet's Encryptでhttps通信をしたい
対象
httpsで公開するために無料でサーバー証明書を発行してくれるLet's Encryptを利用する際、公式ページを含めapacheやnginxの設定事例は数多く発見できます。
ですが、お手軽サイトはわざわざnginxをたてるまでの必要もない、Expressでサクッと公開してサクッとhttps化できればいい、という方が対象です。
実は、単なるletsencrypt-expressの紹介で、なにも目新しいものはありません・・・
環境
CentOS 7.2
Node v5.9.1
Express v4.13.4
ですが、それほど環境は選ばないと思います。
導入
letsencrypt-expressとは?
公式ではcertbotを導入して・・・というのが本筋ですが、node.jsでexpressを使用するのであれば、letsencrypt-expressという素晴らしいツールが公開されているので、それを利用します。
このletsencrypt-express、以下の利点があります。
- 自動でLet's Encryptへの登録をしてくれます
- Let's Encryptは90日で期限が切れるため、cron等で自動再認証のプロセスをしてくれますが、この更新作業も自動でしてくれます
- vhost / virtual hostingを自動でしてくれます
といった特徴があります。特に、自動更新をしてくれるならラクチンです。
letsencrypt-expressのインストール
npm install --save letsencrypt-express
で一発です。
インストール後、expressコードへの埋め込み
下記のごく単純なexpress用のコードをサンプルとしていじっていきます。
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(80);
ここに、letsencrypt-expressの初期化コードを挿入します。
var express = require('express');
// letsencrypt-express用の初期化コード開始
// 次の行の.testing()は本番環境では外して下さい
var LEX = require('letsencrypt-express').testing();
// 以下の2行は環境に合わせて変更して下さい!
var DOMAIN = 'myservice.example.com';
var EMAIL = 'user@example.com';
var lex = LEX.create({
configDir: require('os').homedir() + '/letsencrypt/etc'
, approveRegistration: function (hostname, approve) { // leave `null` to disable automatic registration
if (hostname === DOMAIN) { // Or check a database or list of allowed domains
approve(null, {
domains: [DOMAIN]
, email: EMAIL
, agreeTos: true
});
}
}
});
// ここまで初期化用コード
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.listen(80);
更に、letsencrypt-expressの実行部を挿入します。
var express = require('express');
// letsencrypt-express用の初期化コード開始
// 次の行の.testing()は本番環境では外して下さい
var LEX = require('letsencrypt-express').testing();
// 以下の2行は環境に合わせて変更して下さい!
var DOMAIN = 'myservice.example.com';
var EMAIL = 'user@example.com';
var lex = LEX.create({
configDir: require('os').homedir() + '/letsencrypt/etc'
, approveRegistration: function (hostname, approve) { // leave `null` to disable automatic registration
if (hostname === DOMAIN) { // Or check a database or list of allowed domains
approve(null, {
domains: [DOMAIN]
, email: EMAIL
, agreeTos: true
});
}
}
});
// ここまで初期化用コード
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
// ここからlets用の実行部コード
lex.onRequest = app;
lex.listen([80], [443, 5001], function () {
var protocol = ('requestCert' in this) ? 'https': 'http';
console.log("Listening at " + protocol + '://localhost:' + this.address().port);
});
通常は上のコードで動くはずです。以下は別サンプルで、80番ポートでアクセスしてきたら、443にリダイレクトさせたい場合です。http、spdyモジュールを利用します。npm install --save spdy
でspdyモジュールをインストールしたあと、
var express = require('express');
var http = require('http');
var https = require('spdy');
// letsencrypt-express用の初期化コード開始
// 次の行の.testing()は本番環境では外して下さい
var LEX = require('letsencrypt-express').testing();
// 以下の2行は環境に合わせて変更して下さい!
var DOMAIN = 'myservice.example.com';
var EMAIL = 'user@example.com';
var lex = LEX.create({
configDir: require('os').homedir() + '/letsencrypt/etc'
, approveRegistration: function (hostname, approve) { // leave `null` to disable automatic registration
if (hostname === DOMAIN) { // Or check a database or list of allowed domains
approve(null, {
domains: [DOMAIN]
, email: EMAIL
, agreeTos: true
});
}
}
});
// ここまで初期化用コード
// リダイレクト用
function redirectHttp() {
http.createServer(LEX.createAcmeResponder(lex, function redirectHttps(req, res) {
res.setHeader('Location', 'https://' + req.headers.host + req.url);
res.statusCode = 302;
res.end('<!-- Hello Developer Person! Please use HTTPS instead -->');
})).listen(80);
}
// 通常の443接続
function serveHttps() {
var app = express();
app.use('/', function (req, res) {
res.end('Hello World!');
});
https.createServer(lex.httpsOptions, LEX.createAcmeResponder(lex, app)).listen(443);
}
redirectHttp();
serveHttps();
・・・サンプルそのまんまです・・・
実行
あとはnode app.js
等で実行すれば、自動でサーバー証明書をダウンロードの上、サーバーを立ち上げてくれます。
CentOS7の場合はfirewallを使用していると思うので、httpsを許可していなければ、事前に
$ firewall-cmd --permanent --zone=public --add-service=https
$ firewall-cmd --reload
をお忘れなく。
まとめ
やっぱり素直にnginx等を利用したほうがセットアップは簡単ですが(設定ファイル書き換えで完了)、なにかの参考になれば。