Devlog.
게시일

Next.js 개발 서버에 https 적용하기

cover
date
Oct 16, 2023
slug
nextjs-개발-서버에-https-적용하기
status
Published
tags
Next.js
summary
mkcert로 Next.js에 https 적용하기
type
Post

발단

프로젝트를 진행하면서 Google OAuth를 이용해 로그인을 구현했다. 배포를 위해 Google OAuth를 프로덕션 단계로 변경하면서 다음과 같은 오류가 발생했다.
notion image
따라서 개발 서버에도 https를 적용해야할 필요가 생겼다.

Next.js 13.5

Next.js가 13.5 버전으로 업데이트되면서 개발 서버에 https를 지원하는 옵션이 추가되었다.
개발 서버에 https를 적용하려면 개발 서버 실행 시 --experimental-https 옵션을 붙여 실행한다.
npx next dev --experimental-https
실행하게 되면 프로젝트 루트에 certificates 폴더가 생성되고 그 아래에 key 파일과 cert 파일이 생성되며, .gitignore에 certificates 폴더가 추가된다.
하지만 위와 같이 --experimental-https 옵션만 사용하는 경우, localhost에 대해서만 SSL 인증이 적용되고 app.localhost와 같은 서브 도메인이나 localhost외의 다른 도메인에는 적용되지 않는다.
개발 서버를 실행하는 소스 코드를 살펴보면 --experimental-https-key, —-experimental-https-cert, —-experimental-https-ca 옵션을 통해 key 파일, cert 파일, ca 파일의 경로를 입력할 수 있는 것을 확인할 수 있다.
따라서 서브 도메인을 추가로 사용하는 경우 별도로 인증서를 생성해서 해당 옵션을 통해 적용해야 한다.

인증서 생성 및 적용 자동화

mkcert를 통해 인증서를 발급할 것이고, 운영체제에 관계 없이 스크립트를 실행하기 위해 shelljs를 사용하여 스크립트를 생성할 것이다.
1. 먼저 mkcert를 설치한다.
2. 프로젝트에 shelljs를 설치한다.
npm i -D shelljs
3. 프로젝트 루트에 make-cert.js 파일을 생성하고 다음과 같이 작성한다.
// make-cert.js const shell = require('shelljs'); // mkcert가 설치되지 않은 경우 종료한다. if (!shell.which('mkcert')) { shell.echo('mkcert not installed.'); shell.exit(1); } // certificates 폴더를 생성한다. shell.mkdir('-p', 'certificates'); shell.exec('mkcert -install'); // key 파일과 cert 파일의 경로와 이름, 적용할 도메인은 필요에 맞게 작성한다. shell.exec( 'mkcert -key-file certificates/key.pem -cert-file certificates/cert.pem <적용할 도메인 작성>', );
4. 다음 명령어로 package.jsonscripts에 실행 명령을 추가한다.
npm pkg set scripts.dev:https="node make-cert.js && next dev --experimental-https --experimental-https-key certificates/key.pem --experimental-https-cert certificates/cert.pem --experimental-https-ca \"\$(mkcert -CAROOT)\"/rootCA.pem"
이후 npm run dev:https로 개발 서버를 실행한다.

Next.js 13.4 이하

13.4 버전 이하에서는 custom server를 구성해서 https를 적용해야 한다.
1. 인증서 생성 및 적용 자동화의 1번부터 3번까지 동일하게 진행한다.
2. 프로젝트 루트에 server.js 파일을 생성하고 다음과 같이 작성한다.
const { createServer } = require('https'); const { parse } = require('url'); const next = require('next'); const { readFileSync } = require('fs'); const dev = process.env.NODE_ENV !== 'production'; const hostname = 'localhost'; const port = 3000; // when using middleware `hostname` and `port` must be provided below const app = next({ dev, hostname, port }); const handle = app.getRequestHandler(); const httpsOptions = { key: readFileSync('certificates/key.pem'), cert: readFileSync('certificates/cert.pem'), }; app.prepare().then(() => { createServer(httpsOptions, async (req, res) => { try { // Be sure to pass `true` as the second argument to `url.parse`. // This tells it to parse the query portion of the URL. const parsedUrl = parse(req.url, true); await handle(req, res, parsedUrl); } catch (err) { console.error('Error occurred handling', req.url, err); res.statusCode = 500; res.end('internal server error'); } }) .once('error', (err) => { console.error(err); process.exit(1); }) .listen(port, () => { console.log(`> Ready on https://${hostname}:${port}`); }); });
3. 프로젝트에 cross-env를 설치한다.
npm i -D cross-env
4. 다음 명령어로 package.jsonscripts에 실행 명령을 추가한다.
npm pkg set scripts.dev:https="node make-cert.js && cross-env NODE_EXTRA_CA_CERTS=\"\$(mkcert -CAROOT)\"/rootCA.pem node server.js"
이후 npm run dev:https로 개발 서버를 실행한다.

Reference

 

태그