HTTPSサーバー
| 対応: | Express 4(2014) |
|---|
『Express』では、Node.js 標準の https モジュールと SSL/TLS 証明書を組み合わせることで、HTTPSでサーバーを起動できます。開発環境では自己署名証明書を、本番環境では認証局(CA)が発行した証明書を使うことが一般的です。
構文
app.js(構文例)
var https = require('https');
var fs = require('fs');
var express = require('express');
var app = express();
var options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
https.createServer(options, app).listen(443);
証明書ファイルの種類
| ファイル | 概要 |
|---|---|
| server.key | 秘密鍵ファイルです。外部に漏洩しないよう厳重に管理します。 |
| server.crt | SSL/TLS 証明書ファイルです。認証局が発行したもの、または自己署名のものを使います。 |
| server.csr | 証明書署名要求(CSR)ファイルです。認証局に証明書を申請する際に使います。 |
| ca.crt | 中間CA証明書ファイルです。証明書チェーンを構成するために必要な場合があります。 |
https.createServer() のオプション
| オプション名 | 概要 |
|---|---|
| key | 秘密鍵のデータを指定します。fs.readFileSync() で読み込んだバッファまたは文字列を渡します。 |
| cert | 証明書のデータを指定します。秘密鍵と対応する証明書を渡します。 |
| ca | 中間CA証明書のデータを指定します。証明書チェーンが必要な場合に使います。 |
| passphrase | 秘密鍵にパスフレーズが設定されている場合に指定します。 |
| requestCert | true を設定するとクライアント証明書を要求します。相互TLS(mTLS)認証に使います。 |
サンプルコード
開発環境向けの自己署名証明書を使ったHTTPSサーバーの起動から、HTTPをHTTPSにリダイレクトする実用的なパターンまでを紹介します。
app.js(HTTPSサーバー起動)
var https = require('https');
var http = require('http');
var fs = require('fs');
var path = require('path');
var express = require('express');
var app = express();
app.use(express.json());
var httpsOptions = {
key: fs.readFileSync(path.join(__dirname, 'certs', 'server.key')),
cert: fs.readFileSync(path.join(__dirname, 'certs', 'server.crt'))
};
app.get('/', function(req, res) {
res.send('<h1>HTTPS サーバーが動作しています</h1>');
});
app.get('/info', function(req, res) {
res.json({
protocol: req.protocol,
secure: req.secure,
host: req.hostname
});
});
https.createServer(httpsOptions, app).listen(443, function() {
console.log('HTTPSサーバーを起動しました: https://localhost:443');
});
http.createServer(function(req, res) {
var redirectUrl = 'https://' + req.headers['host'] + req.url;
res.writeHead(301, { 'Location': redirectUrl });
res.end();
}).listen(80, function() {
console.log('HTTPサーバーを起動しました(HTTPSへリダイレクト): http://localhost:80');
});
開発環境用の自己署名証明書を作成する
開発環境では OpenSSL コマンドで自己署名証明書を作成できます。本番環境では Let's Encrypt などの認証局が発行した証明書を使うことが一般的です。
ターミナル
openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes
生成された証明書を使ってHTTPSサーバーを起動します。
app.js(自己署名証明書を使う場合)
var https = require('https');
var fs = require('fs');
var express = require('express');
var app = express();
var options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
app.get('/', function(req, res) {
res.send('開発環境のHTTPSサーバーです');
});
https.createServer(options, app).listen(3443, function() {
console.log('開発用HTTPSサーバーを起動しました: https://localhost:3443');
console.log('注意: 自己署名証明書のためブラウザに警告が表示されます');
});
よくあるミス
ミス1: 証明書ファイルのパスが見つからない
fs.readFileSync() に渡すパスが相対パスの場合、サーバーをどのディレクトリから起動するかによって参照先が変わります。__dirname を使った絶対パスで指定することで、起動ディレクトリに依存しない構成にできます。
NG(ミス1)
var options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
OK(ミス1)
var path = require('path');
var options = {
key: fs.readFileSync(path.join(__dirname, 'certs', 'server.key')),
cert: fs.readFileSync(path.join(__dirname, 'certs', 'server.crt'))
};
ミス2: app.listen() を https.createServer() と併用する
HTTPSで起動する場合は app.listen() の代わりに https.createServer(options, app).listen() を使います。app.listen() はHTTPサーバーを起動するため、証明書オプションを渡すことができません。
NG(ミス2)
app.listen(443, function() {
console.log('起動しました');
});
OK(ミス2)
https.createServer(options, app).listen(443, function() {
console.log('HTTPSサーバーを起動しました');
});
ミス3: HTTP リダイレクトを設定しない
ポート443でHTTPSサーバーを起動しても、ポート80へのHTTPアクセスはそのままHTTPで返ります。ポート80でHTTPサーバーを起動してHTTPSへリダイレクトする構成を取ることで、すべての通信を暗号化できます。
NG(HTTP アクセスがそのまま通る)
https.createServer(options, app).listen(443);
OK(HTTP → HTTPS にリダイレクト)
https.createServer(options, app).listen(443);
http.createServer(function(req, res) {
var redirectUrl = 'https://' + req.headers['host'] + req.url;
res.writeHead(301, { 'Location': redirectUrl });
res.end();
}).listen(80);
概要
ExpressアプリケーションをHTTPSで起動するには、app.listen() の代わりに Node.js 標準の https.createServer(options, app) を使います。options には秘密鍵(key)と証明書(cert)を渡します。ファイルは fs.readFileSync() で同期的に読み込むことが一般的です。
本番環境では Let's Encrypt(Certbot)などを使って取得した証明書を使い、HTTPポート(80)からHTTPSポート(443)への301リダイレクトを設定することが一般的な構成です。リバースプロキシ(Nginx・Apache など)にSSL終端を任せる構成も広く使われており、その場合はExpressアプリ自体はHTTPで動作させ、app.set('trust proxy', true) を設定してクライアントのIPアドレスやプロトコルを正しく取得できるようにします。
開発環境では OpenSSL で自己署名証明書を生成してHTTPSを試すことができますが、自己署名証明書はブラウザに警告が表示されるため、本番での使用には適しません。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。