ブラウザの機能のなかには、HTTPS でないと利用できなかったり、HTTPS か HTTP かで挙動が変わったりする機能がある。
そのため、ローカル開発環境を HTTPS で構築したいことがある。
一番簡単なのは自己署名証明書を作成し利用することだと思うが、その場合ブラウザが警告を出すため、利便性の点で難がある。
以下の記事では、Let's Encrypt で取得した正規の証明書を使って、ローカル開発環境を HTTPS 化している。
これなら、ブラウザが警告を出すことはない。
勉強がてら、この内容を実践してみた。
この方法を試すためには、自由に使えるドメインを所有している必要がある。
既にnumb86.net
というドメインを所有していたので、これを利用してlocalhost.numb86.net
というドメインで開発環境を作っていく。
A レコードの値として 127.0.0.1 を設定する
127.0.0.1
はループバックアドレスという特殊な IP アドレスで、自分自身を指す。
例えば、以下のコードを Deno で実行してhttp://127.0.0.1:8080/
にアクセスすると、Hello Deno.
と表示される。
なお、Deno のバージョンは1.2.2
。
import { listenAndServe, } from "https://deno.land/std@0.63.0/http/mod.ts"; listenAndServe({ port: 8080 }, (req) => { req.respond({ status: 200, headers: new Headers({ "content-type": "text/plain", }), body: "Hello Deno.\n", }); }); console.log("Server running on localhost:8080");
この127.0.0.1
をlocalhost.numb86.net
と紐付けることで、localhost.numb86.net
へのアクセスがローカル開発環境に対するアクセスとなるようにする。
元々ネームサーバとして Route 53 を利用していたので、その管理画面で設定を行う。
dig
コマンドで、正しく設定されていることを確認する。
$ dig localhost.numb86.net a +short 127.0.0.1
これで、http://localhost.numb86.net:8080/
にアクセスしてもHello Deno.
が表示されるようになった。
次は、localhost.numb86.net
の証明書を Let's Encrypt で取得する。
DNS 認証による証明書の取得
Let's Encrypt は ACME(Automatic Certificate Management Environment)というプロトコルを利用しており、そのプロトコルで定義されている「チャレンジ」によって、申請の正当性をチェックしている。
今回の例で言えば、証明書を取得しようとしている私が本当にlocalhost.numb86.net
の管理者であるかを確認するために、チャレンジが行われる。
チャレンジにはいくつか種類があるが、今回のようなケースでは「DNS-01」というチャレンジを使う。
まず、certbot
というツールをインストールする。
$ brew install certbot $ certbot --version certbot 1.6.0
certbot
は ACME のクライアントのひとつ。
以下のコマンドで、チャレンジを行う。
$ sudo certbot certonly --manual -d localhost.numb86.net --preferred-challenges dns-01
いくつか質問に答えていくと、以下のように表示される。
Please deploy a DNS TXT record under the name _acme-challenge.localhost.numb86.net with the following value: XXX Before continuing, verify the record is deployed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Press Enter to Continue
XXX
の部分にトークンが表示される。
それを、_acme-challenge.localhost.numb86.net
の TXT レコードの値として設定する。
表示されている通り、TXT レコードの設定が終わるまではエンターキーは押さない。
これも Route 53 で設定する。
設定が反映されているか、dig
コマンドで確認する。トークンが表示されれば、設定は完了している。
$ dig _acme-challenge.localhost.numb86.net txt +short "XXX"
設定が完了した状態でエンターキーを押すと、チャレンジが完了し、証明書が手に入る。
/etc/letsencrypt/live/localhost.numb86.net/
にインストールされている。
cert.pem
が証明書で、privkey.pem
が秘密鍵。
このディレクトリにアクセスするには権限が必要だったので、sudo su
でroot
に切り替えて操作した。
また、ファイルのパーミッションを変えておかないと取り扱いづらいので、以下のコマンドも実行した。
$ sudo chmod 664 privkey.pem
Deno で HTTPS サーバを立てる
証明書が手に入ったので、それを使って HTTPS サーバを立てる。
以下のコードを Deno で実行してhttps://localhost.numb86.net:8443/
にアクセスすると、Hello Secure Deno!
と表示される。
import { listenAndServeTLS, } from "https://deno.land/std@0.63.0/http/mod.ts"; listenAndServeTLS( { port: 8443, certFile: "./cert.pem", keyFile: "./privkey.pem" }, (req) => { req.respond({ status: 200, headers: new Headers({ "content-type": "text/plain", }), body: "Hello Secure Deno!\n", }); }, ); console.log("Server running on localhost:8443");
自己署名証明書ではないので、警告も出ない。
webpack-dev-server で HTTPS サーバを立てる
この環境を使って、webpack-dev-server で HTTPS サーバを立てることもできる。
以下のバージョンで動作確認をした。
- webpack@4.44.1
- webpack-cli@3.3.12
- webpack-dev-server@3.11.0
以下のファイルと、上記の秘密鍵、証明書を用意した上で$ yarn run webpack-dev-server --mode=development
を実行すると、https://localhost.numb86.net:8443/
にHello webpack!
と表示される。
<!-- ./dist/index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>webpack</title> </head> <body> <div id="app"></div> <script src="./index.js"></script> </body> </html>
// ./src/index.js const elem = document.querySelector('#app'); elem.textContent = 'Hello webpack!';
// ./webpack.config.js const path = require('path'); const fs = require('fs'); module.exports = () => { return { entry: { index: './src/index.js', }, output: { path: path.resolve(__dirname, 'dist'), }, devServer: { contentBase: path.resolve(__dirname, 'dist'), host: 'localhost.numb86.net', port: 8443, https: true, key: fs.readFileSync('./privkey.pem'), cert: fs.readFileSync('./cert.pem') }, } };