mkcert로 Next.js 프로젝트에 HTTPS 적용하기
왜 로컬 개발 환경에서 HTTPS가 필요했을까?
프로젝트를 진행하면서 백엔드와의 API 연동 과정에서 예상치 못한 문제에 부딪혔다. 바로 쿠키 기반 인증과 도메인 불일치 문제였다.
문제 상황
백엔드에서는 보안상의 이유로 로그인 후 accessToken을 쿠키로 전달해 주는 방식을 채택했다. 이 쿠키의 존재 여부를 확인해서 로그인된 사용자와 로그인하지 않은 사용자를 구분하는 것이 목표였다.
하지만 여기서 문제가 발생했다:
- 프론트엔드 개발 환경: http://localhost:3000
- 백엔드 배포 환경: https://yetda.kro.kr
이렇게 프로토콜(http vs https)과 도메인이 다르면 쿠키가 제대로 전달되지 않는다. 특히 SameSite 정책과 Secure 플래그 때문에 HTTPS 환경에서 설정된 쿠키는 HTTP 환경에서 접근할 수 없다.
시도했던 다른 방법들
처음에는 다른 방법으로 해결해보려고 했다:
1. 사용자 조회 API 방식
- 로그인이 필요한 페이지마다 사용자 조회 API를 호출
- 조회되지 않으면 로그인 폼으로 리다이렉트
- 조회되면 해당 페이지 접근 허용
문제점: 매번 API 호출로 인한 성능 저하와 불필요한 네트워크 요청
2. 상태관리(Zustand) 활용 방식
- isLogin 상태를 Boolean 타입으로 관리
- 로그인 성공 시 상태 업데이트
- 페이지 이동 시 상태 확인
문제점:
- 페이지 새로고침 시 상태 초기화
- 브라우저 탭 간 상태 동기화 문제
- App Router에서 app/project/new/sell/[id] 같은 깊은 경로에서 토큰이 사라지는 이슈
근본적인 해결책: 개발 환경 통일
결국 가장 확실한 방법은 개발 환경을 배포 환경과 최대한 유사하게 맞추는 것이었다:
- 도메인 통일: localhost → test.kro.kr
- 프로토콜 통일: http → https
이렇게 하면:
- 쿠키가 정상적으로 전달됨
- 배포 전 실제 환경과 동일한 조건에서 테스트 가능
- CORS 문제 해결
- 보안 관련 기능들을 로컬에서도 정확히 테스트 가능
로컬 개발 환경에서 HTTPS를 적용하는 것은 단순히 SSL 인증서가 필요한 API 연동이나 HTTPS 전용 기능을 테스트하는 것 이상의 의미가 있었다. 이번 글에서는 mkcert를 사용해서 이 모든 문제를 해결하는 과정을 정리해 보겠다!
mkcert란?
mkcert는 로컬 개발 환경에서 신뢰할 수 있는 SSL 인증서를 쉽게 만들 수 있는 도구다. 복잡한 설정 없이도 브라우저에서 경고 없이 HTTPS 사이트를 테스트할 수 있게 해 준다.
1. mkcert 설치 및 설정
1.1 mkcert 다운로드
mkcert GitHub 릴리스 페이지에서 본인의 운영체제에 맞는 파일을 다운로드한다.
- Windows: mkcert-v1.4.4-windows-amd64.exe
- macOS: mkcert-v1.4.4-darwin-amd64
- Linux: mkcert-v1.4.4-linux-amd64
1.2 프로젝트에 mkcert 설치 (폴더 생성 + 파일명 변경은 선택 사항)
- Next.js 프로젝트 루트 디렉토리에 mkcert 폴더를 생성한다.
- 다운로드한 파일을 mkcert 폴더에 넣고 mkcert.exe (Windows) 또는 mkcert (macOS/Linux)로 이름을 변경한다.
- 터미널에서 해당 폴더로 이동한다.
cd mkcert
1.3 루트 인증서 설치
먼저 mkcert의 루트 인증서를 시스템에 설치해야 한다.
# Windows
./mkcert.exe -install
# macOS/Linux
./mkcert -install
Windows에서는 루트 인증서 설치 창이 나타나며, "예"를 클릭하면 설치가 완료된다.
2. SSL 인증서 발급
2.1 도메인 인증서 생성
개발에 사용할 도메인들을 지정해서 인증서를 발급받는다.
# Windows
./mkcert.exe localhost 127.0.0.1 ::1 test.kro.kr test.kro.kr
# macOS/Linux
./mkcert localhost 127.0.0.1 ::1 test.kro.kr www.test.kro.kr
성공적으로 실행되면 다음과 같은 파일들이 생성됩니다:
- yetdatest.kro.kr+3-key.pem (개인키)
- yetdatest.kro.kr+3.pem (인증서)
2.2 파일 확인
생성된 인증서 파일들이 mkcert 폴더에 있는지 확인한다.
프로젝트 루트/
├── mkcert/
│ ├── mkcert.exe
│ ├── test.kro.kr+3-key.pem
│ └── test.kro.kr+3.pem
└── package.json
3. Next.js에 HTTPS 적용
3.1 package.json 수정
package.json 파일의 scripts 섹션에서 dev 명령어를 다음과 같이 수정한다:
{
"scripts": {
"dev": "next dev --experimental-https --experimental-https-key ./mkcert/test.kro.kr+3-key.pem --experimental-https-cert ./mkcert/test.kro.kr+3.pem",
"build": "next build",
"start": "next start"
}
}
* ./mkcert/test.kro.kr+3-key.pem 해당 파일은 경로에 따라 맞게 수정해주면 된다!
3.2 개발 서버 실행
이제 개발 서버를 실행하면 HTTPS로 접속할 수 있다:
npm run dev
서버가 시작되면 https://localhost:3000으로 접속할 수 있다.
4. 추가 설정 (선택사항)
4.1 환경변수 활용
더 깔끔한 관리를 위해 환경변수를 활용할 수 있다:
# .env.local
HTTPS_KEY=./mkcert/test.kro.kr+3-key.pem
HTTPS_CERT=./mkcert/test.kro.kr+3.pem
{
"scripts": {
"dev": "next dev --experimental-https --experimental-https-key $HTTPS_KEY --experimental-https-cert $HTTPS_CERT"
}
}
4.2 커스텀 도메인 설정
hosts 파일을 수정해서 커스텀 도메인을 사용할 수 있다:
Windows: C:\Windows\System32\drivers\etc\hosts macOS/Linux: /etc/hosts
127.0.0.1 test.kro.kr
127.0.0.1 www.test.kro.kr
이제 https://test.kro.kr:3000으로 접속할 수 있다.
주의사항
- 개발 환경에서만 사용: mkcert로 생성한 인증서는 오직 개발 환경에서만 사용해야 한다.
- 인증서 보안: 생성된 인증서 파일들은 버전 관리 시스템에 포함하지 않는 것이 좋다. .gitignore에 추가하자.
- 포트 충돌: 3000번 포트가 이미 사용 중이라면 다른 포트를 사용하자.
# 다른 포트 사용
npm run dev -- -p 3001
이처럼 mkcert를 사용하면 복잡한 설정 없이도 로컬 개발 환경에서 HTTPS를 쉽게 테스트할 수 있다.