모든 배포 가이드 배포

Node.js에서 SSL 인증서 사용하는 방법

Node.js는 https 모듈을 통해 내장 HTTPS를 지원합니다. 인증서 파일을 로드하고 HTTPS 서버를 생성하면 됩니다. 이 가이드에서는 기본 Node.js, Express, 그리고 권장 프로덕션 구성을 다룹니다.

기본 HTTPS 서버

const https = require('https');
const fs = require('fs');

const options = {
  key: fs.readFileSync('/etc/ssl/privkey.pem'),
  cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end('Hello HTTPS');
}).listen(443);

Express에서 HTTPS 사용

const https = require('https');
const fs = require('fs');
const express = require('express');

const app = express();

app.get('/', (req, res) => {
  res.send('Hello HTTPS');
});

const options = {
  key: fs.readFileSync('/etc/ssl/privkey.pem'),
  cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};

https.createServer(options, app).listen(443, () => {
  console.log('HTTPS server running on port 443');
});

HTTP를 HTTPS로 리다이렉트

HTTP 서버와 HTTPS 서버를 모두 실행합니다:

const http = require('http');
const https = require('https');
const fs = require('fs');
const express = require('express');

const app = express();
// ... 라우트 설정

const options = {
  key: fs.readFileSync('/etc/ssl/privkey.pem'),
  cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
};

// HTTPS 서버
https.createServer(options, app).listen(443);

// HTTP 리다이렉트
http.createServer((req, res) => {
  res.writeHead(301, { Location: `https://${req.headers.host}${req.url}` });
  res.end();
}).listen(80);

프로덕션 권장 사항: 리버스 프록시

프로덕션에서는 Node.js에서 직접 TLS를 종료하지 마세요. Nginx, Caddy 또는 로드 밸런서와 같은 리버스 프록시를 앞에 배치합니다:

클라이언트 ──HTTPS──→ Nginx (TLS 종료) ──HTTP──→ Node.js (포트 3000)

이유:

  • Nginx가 TLS를 더 효율적으로 처리 (C vs JavaScript)
  • 인증서 갱신 시 Node.js를 재시작할 필요 없음
  • 포트 443은 root 권한 필요 — Node.js는 root로 실행하면 안 됨
  • 속도 제한, 캐싱, 압축을 프록시에서 처리
  • HTTP/2 지원이 Nginx에서 더 성숙함

개발, 내부 서비스 또는 소규모 프로젝트에서는 Node.js 직접 HTTPS가 괜찮습니다.

주요 프레임워크 설정

Fastify

const fastify = require('fastify')({
  https: {
    key: fs.readFileSync('/etc/ssl/privkey.pem'),
    cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
  },
});

fastify.get('/', async () => ({ hello: 'https' }));
fastify.listen({ port: 443, host: '0.0.0.0' });

Koa

const Koa = require('koa');
const https = require('https');
const fs = require('fs');

const app = new Koa();
app.use(ctx => { ctx.body = 'Hello HTTPS'; });

https.createServer({
  key: fs.readFileSync('/etc/ssl/privkey.pem'),
  cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
}, app.callback()).listen(443);

Next.js / Nuxt / 기타 프레임워크 개발 서버

프레임워크 개발 서버는 보통 로컬 개발용 --https 플래그를 제공합니다. 프로덕션에서는 항상 리버스 프록시를 사용하세요 — 이러한 프레임워크는 Nginx, Caddy 또는 클라우드 로드 밸런서 뒤에서 정적 파일을 제공하거나 SSR을 실행합니다.

환경 변수 패턴

인증서 경로를 하드코딩하지 마세요. 같은 코드가 개발과 프로덕션에서 모두 작동하도록 환경 변수를 사용합니다:

const options = process.env.SSL_KEY ? {
  key: fs.readFileSync(process.env.SSL_KEY),
  cert: fs.readFileSync(process.env.SSL_CERT),
} : null;

if (options) {
  https.createServer(options, app).listen(443);
  console.log('HTTPS server on port 443');
} else {
  app.listen(3000);
  console.log('HTTP server on port 3000 (no SSL_KEY set)');
}

자체 서명 인증서로 개발하기

로컬 개발용으로 자체 서명 인증서를 생성합니다(프로덕션용이 아님):

openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -keyout dev-key.pem -out dev-cert.pem -days 365 -nodes \
  -subj "/CN=localhost"
const options = {
  key: fs.readFileSync('./dev-key.pem'),
  cert: fs.readFileSync('./dev-cert.pem'),
};

자체 서명 인증서는 신뢰되지 않으므로 브라우저에 경고가 표시됩니다 — 개발용으로 경고를 클릭하여 넘어가세요.

인증서 핫 리로딩

재시작 없이 인증서를 다시 로드하는 방법(Let’s Encrypt 갱신에 유용):

const tls = require('tls');

function loadCerts() {
  return {
    key: fs.readFileSync('/etc/ssl/privkey.pem'),
    cert: fs.readFileSync('/etc/ssl/fullchain.pem'),
  };
}

const server = https.createServer({
  SNICallback: (hostname, cb) => {
    const ctx = tls.createSecureContext(loadCerts());
    cb(null, ctx);
  },
}, app);

이 방법은 새 연결마다 파일을 다시 읽습니다. 더 나은 성능을 위해 파일 변경 시에만 다시 로드하는 파일 감시기를 추가하세요.

자주 묻는 질문

Node.js에서 SSL을 처리해야 하나요, 아니면 리버스 프록시를 사용해야 하나요?

프로덕션에서는 리버스 프록시를 사용하세요. 개발, 소규모 프로젝트 또는 내부 서비스에서는 Node.js 직접 HTTPS가 괜찮습니다. 리버스 프록시 패턴이 표준인 이유는 관심사를 분리하고 TLS를 더 효율적으로 처리하기 때문입니다.

GetHTTPS 인증서를 Node.js에서 사용할 수 있나요?

네. GetHTTPS는 표준 PEM 파일(privkey.pem, fullchain.pem)을 생성하며, Node.js에서 fs.readFileSync()로 직접 읽을 수 있습니다.

Node.js에서 인증서 갱신은 어떻게 처리하나요?

리버스 프록시를 사용하는 경우, 파일을 교체하고 프록시를 리로드하면 됩니다 — Node.js를 재시작할 필요가 없습니다. TLS를 직접 처리하는 경우, 위의 SNICallback 방식을 사용하거나 인증서 파일을 교체한 후 Node.js 프로세스를 재시작합니다.

개발용 localhost SSL은 어떻게 하나요?

자체 서명 인증서(위에 표시됨) 또는 mkcert를 사용하여 로컬에서 신뢰할 수 있는 개발 인증서를 생성하세요. localhost에는 Let’s Encrypt를 사용하지 마세요 — 공개적으로 접근할 수 없는 도메인은 검증할 수 없습니다.

Deno나 Bun에서 GetHTTPS 인증서를 사용할 수 있나요?

네. Deno와 Bun 모두 PEM 파일로 TLS를 지원합니다:

Deno:

Deno.serve({
  port: 443,
  cert: Deno.readTextFileSync("/etc/ssl/fullchain.pem"),
  key: Deno.readTextFileSync("/etc/ssl/privkey.pem"),
}, (req) => new Response("Hello HTTPS"));

Bun:

Bun.serve({
  port: 443,
  tls: {
    cert: Bun.file("/etc/ssl/fullchain.pem"),
    key: Bun.file("/etc/ssl/privkey.pem"),
  },
  fetch(req) { return new Response("Hello HTTPS"); },
});

GetHTTPS에서 받은 동일한 PEM 파일이 모든 JavaScript 런타임에서 작동합니다.

관련 기사

시작하기 2026-05-08
무료 SSL 인증서 받는 방법 (단계별 가이드)
5분 만에 Let's Encrypt에서 무료 SSL 인증서를 발급받으세요 - 소프트웨어 설치 불필요, 계정 생성 불필요. 4가지 방법, 두 가지 챌린지 유형, 6개 플랫폼 설치, 문제 해결을 포함하는 완전 가이드입니다.
배포 2026-05-08
Docker와 리버스 프록시에서의 SSL 인증서
Nginx 리버스 프록시, 자동 Let's Encrypt가 포함된 Traefik, 수동 인증서 마운트를 사용하여 Docker 컨테이너의 HTTPS를 구성합니다.
SSL 및 인증서 2026-05-07
SSL 인증서 형식: PEM, PFX, DER 설명
PEM, PFX/PKCS#12, DER 인증서 형식을 이해하세요. 서버에 필요한 형식과 OpenSSL을 사용하여 형식 간 변환하는 방법을 알아보세요.
브라우저에서 무료 SSL 인증서 받기
설치 불필요, 계정 불필요. 개인키는 항상 기기에 남습니다.
인증서 발급