로컬 HTTPS — mkcert 와 자체 CA
로컬 HTTPS — mkcert 와 자체 CA
요즘 웹 기능 중 일부는 HTTP 에서는 동작하지 않습니다. Service Worker · WebAuthn · 일부 미디어 API · Cookie SameSite=None 의 Secure 플래그가 그렇습니다. 운영에서는 자연스럽게 HTTPS 가 깔리지만, 로컬 개발에서는 별도 설정이 필요. 이 글은 로컬 HTTPS 가 필요한 자리 · mkcert 의 모델 · OS 별 트러스트 스토어 · 다른 길 (openssl · ngrok · Caddy local CA) · HSTS preload 와의 충돌 같은 미묘한 자리.
1. 로컬 HTTPS 가 필요한 자리
브라우저 보안 모델이 점점 강해지면서 https:// 또는 http://localhost 만 허용되는 기능이 늘어남.
| 기능 | HTTP localhost | HTTP 다른 호스트 | HTTPS |
|---|---|---|---|
| Service Worker · PWA | 가능 | 불가 | 가능 |
| WebAuthn | 가능 | 불가 | 가능 |
getUserMedia (카메라 · 마이크) |
일부 가능 | 불가 | 가능 |
SameSite=None Cookie |
Secure 강제 |
Secure 강제 |
가능 |
| Cross-origin Cookie · CORS | 제한 | 제한 | 자연스러움 |
localhost 자체는 보안 컨텍스트로 취급되어 일부 기능이 동작. 다음 자리에서 로컬 HTTPS 가 필요해집니다.
- 가상 호스트 (
app.test·myapp.local) 를 쓸 때. - Cookie 의
SameSite=NoneSecure시험. - 프로덕션과 동일한 흐름 (HSTS · 리다이렉트 · 쿠키 동작) 검증.
- WebRTC · 카메라 · 마이크 등을 IP 기반 접근에서 시험.
2. mkcert 에 대한 이야기
Filippo Valsorda 가 2018 에 공개한 로컬 CA 발급 도구. Go 로 작성된 단일 바이너리.
흐름:
- 첫 실행 시 로컬 머신에만 신뢰되는 자체 CA (루트 인증서) 생성.
- 만든 CA 를 OS 와 브라우저의 트러스트 스토어에 등록.
- 도메인 인증서를 그 CA 로 서명해 발급.
# Mac
brew install mkcert nss # nss 는 Firefox 트러스트용
mkcert -install
mkcert localhost 127.0.0.1 ::1 myapp.local "*.myapp.local"
# Linux
sudo apt install libnss3-tools mkcert
mkcert -install
mkcert localhost 127.0.0.1 myapp.local
# Windows (PowerShell, scoop 또는 chocolatey)
scoop install mkcert
mkcert -install
mkcert localhost 127.0.0.1 myapp.local
결과로 myapp.local+3.pem (인증서) 과 myapp.local+3-key.pem (개인키) 두 파일. 개발 서버에 이 두 파일을 지정.
3. Vite · Next · 일반 Node 서버
// Vite
import fs from 'node:fs';
export default {
server: {
https: {
cert: fs.readFileSync('./myapp.local+3.pem'),
key: fs.readFileSync('./myapp.local+3-key.pem'),
},
},
};
// Node http2
import http2 from 'node:http2';
http2.createSecureServer({
cert: fs.readFileSync('./myapp.local+3.pem'),
key: fs.readFileSync('./myapp.local+3-key.pem'),
}, app).listen(8443);
4. OS 트러스트 스토어
mkcert -install 이 자동 처리하지만 내부 동작은 OS 마다 다름.
| OS | 저장소 | 도구 |
|---|---|---|
| macOS | System Keychain | security add-trusted-cert |
| Windows | Trusted Root Certification Authorities | certmgr.msc 또는 certutil |
| Linux (Debian / Ubuntu) | /usr/local/share/ca-certificates/ + update-ca-certificates |
ca-certificates 패키지 |
| Linux (Fedora / RHEL) | /etc/pki/ca-trust/source/anchors/ + update-ca-trust |
ca-certificates |
브라우저:
- Chrome · Edge · Safari — OS 트러스트 스토어 그대로 사용.
- Firefox — 별도 NSS 데이터베이스. mkcert 는
nss도구로 자동 등록.
5. 다른 길
openssl 자체 서명 — 일회성 · 서버 간 통신 · 로컬 단일 사용에 충분 (CA 미트러스트라 매번 경고):
openssl req -x509 -newkey rsa:4096 -nodes \
-keyout key.pem -out cert.pem \
-days 365 -subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
ngrok · localhost.run · cloudflared tunnel — 로컬 서버를 외부 HTTPS URL 로 노출:
| 도구 | 메모 |
|---|---|
| ngrok (2013) | 가장 오래됨. 무료 + 유료 정적 도메인. |
| Cloudflare Tunnel | Cloudflare 계정 + 도메인 결합. 무료 티어 폭 넓음. |
| localhost.run | 가입 없이 SSH 만으로 노출. |
| Tailscale Funnel | Tailnet 도메인 노출. |
장점은 자체 CA 가 필요 없음 (이미 신뢰된 인증서). 단점은 외부 서비스 의존.
6. Caddy 의 자체 local CA
Caddy 는 첫 실행 시 자체 local CA 를 만들고 OS 트러스트 스토어에 등록 가능. mkcert 와 모델은 같지만 Caddy 의 리버스 프록시 흐름과 자연스럽게 결합.
{
local_certs
}
myapp.local {
reverse_proxy 127.0.0.1:3000
}
이 한 자리만 돼도 https://myapp.local 이 신뢰된 인증서로 동작. mkcert 별도 설치 없이.
7. 빌트인 옵션
일부 프레임워크는 자체적으로 HTTPS 옵션:
next dev --experimental-https(Next 13.5 ~).- Vite
server.https = true만 두면 자동 자체 서명 (브라우저 경고 발생).
빌트인은 빠르지만 트러스트 안 된 인증서. 실 시험은 mkcert · Caddy 가 권장되는 흐름.
8. hosts 파일 + mkcert
localhost 가 아닌 가상 호스트로 시험하려면 hosts 파일 매핑:
# Mac / Linux: /etc/hosts
# Windows: C:\Windows\System32\drivers\etc\hosts
127.0.0.1 myapp.local
127.0.0.1 api.myapp.local
mkcert myapp.local "*.myapp.local"
*.myapp.local 로 와일드카드를 두면 서브도메인이 늘어나도 같은 인증서 재사용.
9. 팀 공유는 권장 안 됨
mkcert 의 CA 는 한 머신에만 신뢰되어야 안전. 팀이 같은 CA 를 공유하는 흐름은 권장 안 됨 — 그 CA 가 유출되면 팀의 모든 머신이 위협. 각자 mkcert -install 후 자기 머신에서 발급.
CI 에서 HTTPS 시험은 자체 서명 + NODE_TLS_REJECT_UNAUTHORIZED=0 조합 또는 testcontainers 같은 격리 환경. mkcert 를 CI 머신에 설치하면 매번 새 CA 가 만들어져 혼선.
10. 자주 걸리는 자리
Firefox 미인식 — NSS 라이브러리 (libnss3-tools · nss) 없으면 Firefox 트러스트 스토어에 자동 등록 안 됨. mkcert 가 경고 출력.
HSTS preload 충돌 — .dev · .app · .test 일부 TLD 가 HSTS preload 에 포함되어 HTTP 가 강제로 HTTPS 로 리다이렉트됨. .local 또는 .localhost 가 비교적 안전.
mkcert 미설치 머신에서 인증서 사용 — 다른 사람의 머신에서 같은 인증서를 쓰면 OS 가 CA 를 모르므로 경고. 머신마다 새로 발급해야 함.
포트 80 / 443 권한 — 일반 사용자는 1024 미만 포트 바인딩이 권한 필요 (Linux). 8443 같은 고포트 사용 또는 setcap / 포트 포워딩.
인증서 SAN 누락 — CN 만 두면 최근 브라우저가 거부. subjectAltName 에 모든 호스트 · IP 포함.
유효 기간 — mkcert 도메인 인증서는 825 일 기본. 만료 후 재발급.
트러스트 스토어 재설치 — OS 재설치 · 로그인 사용자 변경 시 CA 가 사라짐. mkcert -install 다시 실행.
하고픈 말
대부분의 로컬 개발은 http://localhost 보안 컨텍스트로 충분합니다. PWA · WebAuthn 같은 운영 흐름을 그대로 시험해야 할 때만 mkcert (단일 머신) 또는 Caddy local_certs (리버스 프록시 결합) 를 도입할 만한 자리. CI 에는 testcontainers 가 더 깔끔.
Next
- cloud-emulator-stack
- (infra 끝)
mkcert GitHub · Caddy Local Certs · openssl x509 docs · ngrok 공식 · Cloudflare Tunnel · Tailscale Funnel · MDN Secure Contexts · HSTS Preload 를 참고합니다.