Next.js 프로젝트에 local https 환경을 만들자 (feat. mkcert)

mkcert를 활용해 next.js 프로젝트의 로컬 개발 환경에 https 적용하기
nextjsmkcert
avatar
2025.03.11
·
8 min read

들어가기에 앞서..

대부분의 경우에 로컬 https 환경은 필수적이지 않습니다. 그러나 인증 문제나 CORS 등 일부 특수한 case에 따라 필요해지는 순간이 있는데, 이때 mkcert를 이용해 간단하게 로컬 https 환경을 조성하는 방법을 공유해보려고 합니다.

필요 기술

  • mkcert

  • dotenv

본문

[Step 1] mkcert 설치 및 인증

저는 mac에서 homebrew 를 사용하고 있기 때문에 터미널에서 아래와 같이 진행하였습니다

# 로컬에 mkcert 설치
$ brew install mkcert

# 로컬을 인증된 발급기관으로 추가 (ssl 공급자 인증을 위해 필요합니다)
$ mkcert -install

[Step 1.5] .env 파일 생성 및 환경변수 설정

- .env 파일 대신 하드 타입핑으로 진행해도 괜찮습니다.

저의 경우 프로젝트 레포를 멀티 테넌시로 구성해야 했기에 로컬 호스트 주소를 환경변수로 관리하게 되었습니다. 한번에 여러 프로젝트를 띄우고 있을 때 port 겹침을 방지하기 위해 개별적인 포트 번호를 사용합니다.

# 예시
LOCAL_HOST=local.example.com
PORT=4431

[Step 2] dotenv 라이브러리 추가

node 환경에서 환경변수 파일을 인식시키기 위해 dotenv 라이브러리를 설치해줍니다

$ npm i dotenv

[Step 3] setup 스크립트 작성

setup 스크립트에서는 https 인증서를 발행하고, pem 파일을 생성합니다.
동작 순서는 아래와 같습니다.

1단계 - .env 파일의 존재 유무 확인
2단계 - .env 파일 속 LOCAL_HOST 환경변수 존재 유무 확인
==== .env 없이 진행하셨다면 위 2단계는 생략하셔도 됩니다. ====
3단계 - /etc/hosts 파일에 해당 로컬 호스트를 추가합니다
4단계 - mkcert 로 인증서를 발행하고 pem 파일이 레포에 생성됩니다.

#!/bin/bash

# 환경 변수 파일 경로
ENV_FILE_NAME=".env"
# 환경 변수명
ENV_HOST_KEY="LOCAL_HOST"
# /etc/hosts 파일 경로
HOSTS_FILE_PATH="/etc/hosts"

###############################################################################

# 환경 변수 파일이 없을 경우 에러 메시지 출력 후 종료
if [ ! -f "$ENV_FILE_NAME" ]; then
  echo "=====================   🚨 ERROR: NO ENV FILE   ====================="
  echo "== 환경 변수 파일이 없습니다"
  echo "== $ENV_FILE_NAME 파일을 생성해주세요"
  echo "====================================================================="
  echo ""
  exit 1
fi

echo "> ✅ 환경 변수 파일 $ENV_FILE_NAME 를 찾았습니다"

###############################################################################

# 환경 변수 파일에서 로컬 호스트 값 추출
LOCAL_HOST=$(grep ^"$ENV_HOST_KEY"= "$ENV_FILE_NAME" | cut -d '=' -f2)

# 환경 변수 파일에 로컬 호스트 값이 없을 경우 에러 메시지 출력 후 종료
if [ -z "$LOCAL_HOST" ]; then
  echo ""
  echo "==============   🚨 ERROR: $ENV_HOST_KEY NOT DECLARED   ================"
  echo "== $ENV_FILE_NAME 파일에 $ENV_HOST_KEY 환경변수를 설정해주세요"
  echo "====================================================================="
  echo ""
  exit 1
fi

echo "> ✅ 환경 변수 $ENV_HOST_KEY 가 $ENV_FILE_NAME 에 선언되어 있습니다 (값: $LOCAL_HOST)"

###############################################################################

# /etc/hosts 파일에 해당 로컬 호스트가 이미 있을 경우
if grep -q "$LOCAL_HOST" "$HOSTS_FILE_PATH"; then
  echo "> ✅ $HOSTS_FILE_PATH 에 $LOCAL_HOST 가 등록되어 있습니다"
else
# /etc/hosts 파일에 해당 로컬 호스트가 없을 경우 신규 추가
  echo ""
  echo "> 🚀 신규 로컬 호스트 [$LOCAL_HOST]를 $HOSTS_FILE_PATH 에 추가하기 위해 기기의 비밀번호(mac 비밀번호)를 입력하세요"
  echo "127.0.0.1\t$LOCAL_HOST" | sudo tee -a "$HOSTS_FILE_PATH" >/dev/null
  echo "> ✅ $HOSTS_FILE_PATH 에 신규 로컬 호스트 [$LOCAL_HOST]을 등록하였습니다"
fi

###############################################################################

# 로컬 호스트에 대한 https 인증서 생성
mkcert -key-file localhost-key.pem -cert-file localhost-cert.pem "$LOCAL_HOST"

[Step 4] start-local-server 스크립트 작성

공식 문서: Nextjs-Custom-Server

위 문서를 참고하여 커스텀 https 서버를 만들어보겠습니다.
createServer 함수를 http 가 아닌 https 라이브러리에서 import 해야 함을 유의합니다.
[Step 3] 에서 생성한 인증서를 fs 라이브러리로 읽어옵니다.

/* eslint-disable @typescript-eslint/no-require-imports */

const { createServer } = require("https");
const { parse } = require("url");
const next = require("next");
const fs = require("fs");

require("dotenv").config();

const port = process.env.PORT;
const hostname = process.env.LOCAL_HOST;

const dev = process.env.NODE_ENV !== "production";

if (!port) throw new Error(" 🚨 PORT 환경변수가 설정되지 않았습니다!!");
if (!hostname) throw new Error(" 🚨 LOCAL_HOST 환경변수가 설정되지 않았습니다!!");

const app = next({ port, dev, hostname });
const handle = app.getRequestHandler();

console.log(" 🚀 로컬 서버 시작중...");

app.prepare().then(() => {
  const localServer = createServer(
    {
      key: fs.readFileSync("localhost-key.pem"),
      cert: fs.readFileSync("localhost-cert.pem"),
    },
    (req, res) => {
      const parsedUrl = parse(req.url, true);
      handle(req, res, parsedUrl);
    }
  );

  localServer.listen(port);

  console.log(` ✅ Ready: \t https://${hostname}:${port} \n`);
});

[Step 5] package.json 에 커맨드 추가

편의를 위해 package.json 에 만들어둔 script 실행문을 커맨드로 추가합니다.

"scripts": {
  "setup": "sh src/scripts/setup.sh",
  "dev": "node src/scripts/start-local-server.js",
  ...
},

[Step 6] local https server 실행

이제 모든 준비가 완료되었으니 동작을 확인해봅시다.
setup 커맨드를 먼저 실행한 뒤, 인증서가 발급되면 dev 커맨드까지 실행합니다.
아래 사진과 같이 안전한 연결 까지 확인하시면 완전히 끝났습니다.
* 만약 안전하지 않은 연결 이 뜬다면 mkcert -install 을 다시 실행한 뒤 로컬 서버를 재실행해보세요. 시간이 지나면 자동으로 안전한 연결 로 변경될 수도 있습니다.

$ npm run setup
# '/etc/hosts' 파일에 접근하기 위해선 pc의 비밀번호가 필요합니다.
# 비밀번호를 입력하라는 화면이 노출되면 pc의 비밀번호를 입력하세요.

$ npm run dev
3952

마무리

사실 Nextjs에서는 next dev 명령어 실행 시 --experimental-https 키를 통해 localhost를 바로 https로 실행하는 방법이 있긴 합니다. 🙂
그러나 shared cookie와 같이 domain이 중요한 상황이 올 때 https://localhost:PORT 로는 금방 한계를 느끼게 되는 것 같습니다.

프로젝트 세팅 시간을 줄이는데 도움이 되길 바라며 여기서 포스팅을 마치도록 하겠습니다.
예제 github repo도 같이 공유드립니다 local-https-example.github







- 컬렉션 아티클