Node.jsのExpressを利用したアプリケーションの開発時にhttpsを利用しないといけない制約が出た場合のSSLの設定方法について説明を行っています。

動作確認は、macOSのBig Surで行っています。Node.jsが事前にOSにインスールされていることが前提となっています。

Expressではhttpsを利用するための機能は備わっていますが、httpsを利用するために秘密鍵と自己証明者が必要となります。秘密鍵と証明書を作成するためopensslコマンドを実行しますが、opensslコマンドはmacOSの中に入っています。

Expressの環境構築

httpsサーバとして設定を行う前にExpressを使ってhttpサーバを構築します。

任意の名前のフォルダを作成(ここではmyapp)を作成し、フォルダ内でnpm init -yコマンドを実行しpackage.jsonファイルを作成します。


 % mkdir myapp
 % cd myapp
 % npm init -y

Expressのインストールを行います。


% npm install express
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN myapp@1.0.0 No description
npm WARN myapp@1.0.0 No repository field.

+ express@4.17.1
added 50 packages from 37 contributors and audited 50 packages in 1.878s
found 0 vulnerabilities

ファイルの更新を監視するためにnodemonをインストールします。


  % npm install nodemon
nodemonを利用しない場合はindex.jsファイルを更新する度に更新したファイルの再読み込みを行う必要があります。

myappフォルダにindex.jsファイルを作成して以下を記述します。


const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Listening on port ${port}!`))

index.jsファイル作成後Expressを起動します。nodemonを利用しています。


% npx nodemon index.js
[nodemon] 2.0.7
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node index.js`
Example app listening on port 3000!

index.jsファイルで指定したポート3000にブラウザからアクセスし、ブラウザ上にHello World!が表示されることを確認します。表示されればExpsssの環境構築は完了です。

Hello Worldがブラウザに表示
Hello Worldがブラウザに表示

https設定

httpsを設定していない場合にhttps://localhost:3000にブラウザからアクセスすると以下の画面が表示されます。このエラーが表示されるのはhttps通信にWEBサーバが対応していないためです。

https未設定時での設定
https未設定時での設定

秘密鍵と自己署名証明書の作成

opensslコマンドを利用して秘密鍵(privatekey.pem)と自己署名証明書(cert.pem)を作成します。対話形式でContry Nameなど聞かれますが開発用で一時的にhttpsを利用するために設定を行うのでいずれかの質問の一つを入力してください。後はEnterを押してください。ここではContry Nameに”JP”を入力しています。


 % openssl req -x509 -newkey rsa:2048 -keyout privatekey.pem -out cert.pem -nodes -days 365
Generating a 2048 bit RSA private key
.....................................................................................+++
...................+++
writing new private key to 'privatekey.pem'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:JP
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:
Email Address []:

実行すると実行フォルダにprivatekey.pemとcert.pemファイルが作成されます。

-nodesオプションを指定しない場合はパスフレーズを入力する必要があります。パスフレーズを設定している場合はExpressで鍵と証明書に作成したファイルを指定しても動作しません。–nodesオプションなしで作成後に秘密鍵からパスフレーズをなくすコマンドを実行することで-nodesオプションありの場合と同じように設定することが可能です。% openssl rsa -in privatekey.pem -out privatekey_a.pem 。keyにはprivatekey_a.pemを指定します。

作成した秘密鍵と自己署名証明書をindex.jsファイルで指定します。秘密鍵と自己署名証明書はindex.jsファイルと同じフォルダに保存しているので./privatekey.pemを設定しています。パスには気をつけてください。


const express = require('express')
const app = express()
const port = 3000
const fs = require('fs');
const server = require('https').createServer({
    key: fs.readFileSync('./privatekey.pem'),
    cert: fs.readFileSync('./cert.pem'),
}, app)

app.get('/', (req, res) => res.send('Hello World!'))

server.listen(port, () => console.log(`Listening on port ${port}!`))

Chromeブラウザからのアクセス(NET::ERR_CERT_INVALID)

設定後にhttps://localhost:3000にアクセスすると先ほどとは異なり警告画面が表示されます。証明書を一時的に作成しているだけなので、認証情報が正しくないためにこのエラー(NET::ERR_CERT_INVALID)が表示されています。

警告が表示
警告が表示

ページを表示させるためには、詳細設定のボタンをクリックしてください。

詳細情報を表示
詳細情報を表示

この画面でthisisunsafeと入力してください。URLの入力欄には証明書が正しくないため”保護されていない通信”と表示されますがブラウザ上にはhttpで接続した時と同じ内容が表示されます。

https経由でページを表示
https経由でページを表示

また保護されていない通信をクリックすると以下の画面が表示されます。証明書が無効であることがわかります。

保護されていない通信をクリック
保護されていない通信をクリック

自己証明ルート証明書であることがわかり、先ほどのopensslの実行時に入力したCountry NameのJPやコマンドのオプションに指定したX.509などを確認することができます。

正しい証明書の場合
正しい証明書の場合

証明書が有効の場合は以下のように証明書(有効)が表示されます。

接続が保護されている場合
接続が保護されている場合

一度”thisisunsafe”を入力すると次の接続で警告が表示されなくなった場合は保護されていない通信をクリックして、”警告を再度有効にする”をクリックしてください。

Firefoxブラウザからのアクセス

ChromeブラウザではなくFirefoxブラウザを開発に利用している人もいるかと思います。Firefoxブラウザで接続するとChromeと同様に警告が表示されます。Advancedボタンをクリックしてください。

Firexの警告
Firefoxの警告

証明書が信頼できないために警告が表示されています。開発用で問題がないことがわかっているのでAccept the Risk and Continue(リスクを理解した上で続ける)ボタンをクリックします。

より詳細なメッセージ
より詳細なメッセージ

http通信で接続した時と同じ内容が表示されます。

httpで表示された内容が表示
httpで表示された内容が表示

以上でExpressにおけるhttpsの設定方法の手順は完了です。開発しているExpressを利用したアプリケーションでhttpsが必要な場合はぜひ試してみてください。