Next.jsの開発環境をHTTPSにする

公開 ( 更新)履歴 (7)

このサイトのコンテンツは主にこういう文章だと思っていますが、この環境をブログ専用にしておくのはもったいないです。アプリが作りたくなってClipboard APIとかHTTPSが前提のAPIが必要になる可能性を考えるとHTTPSで開発できるようにしておいて損はないはず。やりましょう。

やりたいこと #link

  1. https://localhost.gojabako.zone:3000 で開発中のページを見る

    1. DNSはlocalhost.gojabako.zoneに127.0.0.1を返す

    2. ブラウザは127.0.0.1:3000にリクエストする

    3. ローカルで3000をlistenしているサーバーがコンテンツを返す

  2. 証明書はcertbot (Let's encrypt)で普通のやつをつくる

やりたいことの図
やりたいことの図

DNSにレコードを追加する #link

localhost.gojabako.zoneのAレコードを127.0.0.1にします。私の場合ドメインはRoute53なので管理コンソールでやりました。

Route53の管理画面
Route53の管理画面

Google Admin Toolboxで確認すると次の画像のようになっています。

Google Admin Toolboxの画面
Google Admin Toolboxの画面

証明書をつくる #link

certbotで作りました。

certbotのコマンド
  1. sudo certbot certonly \
  2. --manual \
  3. --domain localhost.gojabako.zone \
  4. --preferred-chain "ISRG Root X1" \
  5. --preferred-challenges dns

表示される値を_acme-challenge.localhost.gojabako.zoneのTXTレコードに設定してEnterを押すと証明書ができます。

証明書の場所 (macOS, certbot 1.19.0)
  1. /etc/letsencrypt/live/localhost.gojabako.zone/README
  2. /etc/letsencrypt/live/localhost.gojabako.zone/cert.pem
  3. /etc/letsencrypt/live/localhost.gojabako.zone/chain.pem
  4. /etc/letsencrypt/live/localhost.gojabako.zone/fullchain.pem
  5. /etc/letsencrypt/live/localhost.gojabako.zone/privkey.pem

でもここから読むのはsudoが必要で手間なのでプロジェクトの中にコピーします。秘密鍵はそのままだと読めないのでコピー後に権限をつけます。.gitignoreで*.pemをコミットしないようにしているのでGitHubではREADMEだけがある状態になっています[1]

コピーと権限付与のコマンド
  1. sudo cp /etc/letsencrypt/live/localhost.gojabako.zone certificates
  2. sudo chmod +r certificates/localhost.gojabako.zone/privkey.pem

server.mjsをつくる #link

next devのサーバーだと作った証明書ファイルを渡す方法がないのでカスタムサーバーが必要になります。

server.mjs
  1. import * as fs from 'fs';
  2. import * as https from 'https';
  3. import * as console from 'console';
  4. import * as url from 'url';
  5. import next from 'next';
  6. const rootUrl = new URL('https://localhost.gojabako.zone:3000');
  7. const [key, cert] = await Promise.all([
  8. fs.promises.readFile('certificates/localhost.gojabako.zone/privkey.pem')),
  9. fs.promises.readFile('certificates/localhost.gojabako.zone/fullchain.pem')),
  10. ]);
  11. const server = https.createServer({key, cert});
  12. const app = next({dev: process.env.NODE_ENV !== 'production'});
  13. await app.prepare();
  14. const handleApiRequest = app.getRequestHandler();
  15. server.on('request', (req, res) => {
  16. const parsedUrl = url.parse(new URL(req.url, rootUrl).href, true);
  17. // queryがnullだとhandleApiRequestがエラーになるので{}で埋めます
  18. parsedUrl.query = parsedUrl.query || {};
  19. if (req.url.startsWith('/api/')) {
  20. handleApiRequest(req, res, parsedUrl);
  21. } else {
  22. app.render(req, res, parsedUrl.pathname, parsedUrl.query);
  23. }
  24. });
  25. server.once('error', (error) => {
  26. console.error(error);
  27. });
  28. server.on('listening', () => {
  29. console.info(`> Ready on ${rootUrl}`);
  30. });
  31. server.listen(rootUrl.port);

package.jsonの修正 #link

next devserver.mjsの実行に変えます。これでnpm run devでHTTPSのサーバーが起動します。

  1. "scripts": {
  2. "dev": "node server.mjs"
  3. }

localhost.gojabako.zone:3000をHTTPSで表示できます。

証明書の情報を表示しているところ
証明書の情報を表示しているところ

別の端末でも見たい #link

サーバーを動かしている端末以外から開発画面を見る場合はhostsを編集してlocalhost.gojabako.zoneがサーバーを向くようにしましょう。