Next.jsの開発環境をHTTPSにする
このサイトのコンテンツは主にこういう文章だと思っていますが、この環境をブログ専用にしておくのはもったいないです。アプリが作りたくなってClipboard APIとかHTTPSが前提のAPIが必要になる可能性を考えるとHTTPSで開発できるようにしておいて損はないはず。やりましょう。
やりたいこと #link
https://localhost.gojabako.zone:3000 で開発中のページを見る
DNSはlocalhost.gojabako.zoneに127.0.0.1を返す
ブラウザは127.0.0.1:3000にリクエストする
ローカルで3000をlistenしているサーバーがコンテンツを返す
証明書はcertbot (Let's encrypt)で普通のやつをつくる
DNSにレコードを追加する #link
localhost.gojabako.zoneのAレコードを127.0.0.1にします。私の場合ドメインはRoute53なので管理コンソールでやりました。
Google Admin Toolboxで確認すると次の画像のようになっています。
証明書をつくる #link
certbotで作りました。
sudo certbot certonly \
--manual \
--domain localhost.gojabako.zone \
--preferred-chain "ISRG Root X1" \
--preferred-challenges dns
表示される値を_acme-challenge.localhost.gojabako.zoneのTXTレコードに設定してEnterを押すと証明書ができます。
/etc/letsencrypt/live/localhost.gojabako.zone/README
/etc/letsencrypt/live/localhost.gojabako.zone/cert.pem
/etc/letsencrypt/live/localhost.gojabako.zone/chain.pem
/etc/letsencrypt/live/localhost.gojabako.zone/fullchain.pem
/etc/letsencrypt/live/localhost.gojabako.zone/privkey.pem
でもここから読むのはsudoが必要で手間なのでプロジェクトの中にコピーします。秘密鍵はそのままだと読めないのでコピー後に権限をつけます。.gitignoreで*.pemをコミットしないようにしているのでGitHubではREADMEだけがある状態になっています[1]。
sudo cp /etc/letsencrypt/live/localhost.gojabako.zone certificates
sudo chmod +r certificates/localhost.gojabako.zone/privkey.pem
server.mjsをつくる #link
next dev
のサーバーだと作った証明書ファイルを渡す方法がないのでカスタムサーバーが必要になります。
import * as fs from 'fs';
import * as https from 'https';
import * as console from 'console';
import * as url from 'url';
import next from 'next';
const rootUrl = new URL('https://localhost.gojabako.zone:3000');
const [key, cert] = await Promise.all([
fs.promises.readFile('certificates/localhost.gojabako.zone/privkey.pem')),
fs.promises.readFile('certificates/localhost.gojabako.zone/fullchain.pem')),
]);
const server = https.createServer({key, cert});
const app = next({dev: process.env.NODE_ENV !== 'production'});
await app.prepare();
const handleApiRequest = app.getRequestHandler();
server.on('request', (req, res) => {
const parsedUrl = url.parse(new URL(req.url, rootUrl).href, true);
// queryがnullだとhandleApiRequestがエラーになるので{}で埋めます
parsedUrl.query = parsedUrl.query || {};
if (req.url.startsWith('/api/')) {
handleApiRequest(req, res, parsedUrl);
} else {
app.render(req, res, parsedUrl.pathname, parsedUrl.query);
}
});
server.once('error', (error) => {
console.error(error);
});
server.on('listening', () => {
console.info(`> Ready on ${rootUrl}`);
});
server.listen(rootUrl.port);
package.jsonの修正 #link
next dev
をserver.mjs
の実行に変えます。これでnpm run dev
でHTTPSのサーバーが起動します。
"scripts": {
"dev": "node server.mjs"
}
localhost.gojabako.zone:3000をHTTPSで表示できます。
別の端末でも見たい #link
サーバーを動かしている端末以外から開発画面を見る場合はhostsを編集してlocalhost.gojabako.zoneがサーバーを向くようにしましょう。