PM2로 Next.js 프로덕션 운영하기 — 무중단 배포와 모니터링
Vercel에 올리면 편하지만, 트래픽이 늘수록 비용도 같이 늘어납니다. 자체 서버에서 Next.js를 운영하려면 PM2가 사실상 표준입니다. 프로세스 관리, 무중단 배포, 로그 관리, 자동 재시작까지 — PM2 하나로 프로덕션 환경을 안정적으로 운영하는 방법을 정리했습니다.
0초
다운타임 (reload)
1줄
자동 시작 설정
무제한
로그 자동 회전
24/7
프로세스 감시
1PM2 기초 — 왜 PM2인가
Node.js 프로세스를 node server.js로 직접 실행하면 에러 한 번에 서비스 전체가 죽습니다. PM2는 프로세스가 죽으면 자동으로 재시작하고, CPU 코어 수만큼 프로세스를 복제하며, 로그를 파일로 관리합니다.
# PM2 전역 설치
npm install -g pm2 # Next.js 앱 시작 (기본) pm2 start npm --name "my-app" -- start # 상태 확인 pm2 status # 실시간 로그 확인 pm2 logs my-app --lines 50
| 기능 | node 직접 실행 | PM2 |
|---|---|---|
| 에러 시 자동 재시작 | 불가 | 자동 |
| 멀티 프로세스 | 수동 구현 | cluster 모드 |
| 로그 관리 | stdout만 | 파일 + 회전 |
| 무중단 배포 | 불가 | reload 명령 |
| 서버 재부팅 시 | 수동 시작 | systemd 연동 |
PM2의 핵심 가치
PM2는 단순한 프로세스 매니저가 아닙니다. 프로덕션에서 Node.js 앱을 안정적으로 운영하기 위한 모든 기능을 제공합니다. 특히 무중단 배포(reload)와 자동 재시작은 서비스 가용성을 크게 높여줍니다.
2ecosystem.config.js 작성
CLI에서 매번 옵션을 입력하는 대신, ecosystem.config.js 파일 하나에 모든 설정을 담아두면 관리가 훨씬 편합니다. 여러 앱을 한 서버에서 운영할 때도 이 파일 하나로 제어할 수 있습니다.
ecosystem.config.js
module.exports = {
apps: [
{
name: "main-site",
script: "node_modules/.bin/next",
args: "start",
cwd: "/home/deploy/main-site",
instances: 1, // Next.js는 fork 모드 권장
exec_mode: "fork",
env: {
NODE_ENV: "production",
PORT: 3000,
},
max_memory_restart: "500M",
error_file: "./logs/error.log",
out_file: "./logs/output.log",
merge_logs: true,
log_date_format: "YYYY-MM-DD HH:mm:ss",
},
{
name: "admin-site",
script: "node_modules/.bin/next",
args: "start",
cwd: "/home/deploy/admin-site",
instances: 1,
exec_mode: "fork",
env: {
NODE_ENV: "production",
PORT: 3001,
},
max_memory_restart: "300M",
},
],
};# ecosystem 파일로 시작/관리
# 전체 앱 시작 pm2 start ecosystem.config.js # 특정 앱만 시작 pm2 start ecosystem.config.js --only main-site # 설정 변경 후 적용 pm2 reload ecosystem.config.js
max_memory_restart 설정을 꼭 하세요
Next.js 앱은 시간이 지나면 메모리 사용량이 조금씩 늘어나는 경우가 있습니다.max_memory_restart를 설정해두면 메모리 초과 시 자동으로 재시작되어 OOM 킬을 방지할 수 있습니다.
3Cluster 모드 vs Fork 모드
PM2의 가장 강력한 기능 중 하나가 cluster 모드입니다. CPU 코어 수만큼 워커를 생성해서 요청을 분산 처리합니다. 그런데 Next.js에서는 좀 다릅니다.
| 항목 | Fork 모드 | Cluster 모드 |
|---|---|---|
| 프로세스 수 | 1개 | CPU 코어 수 |
| 로드 밸런싱 | 없음 | 내장 (라운드 로빈) |
| 무중단 배포 | 순간 중단 있음 | 완전 무중단 |
| Next.js 호환성 | 완벽 | 주의 필요 |
| 메모리 사용 | 적음 | 코어 수 x 배 |
Next.js는 Fork 모드를 권장합니다
Next.js는 자체적으로 멀티 스레드 처리를 합니다. PM2 cluster 모드를 사용하면 포트 충돌이나 ISR 캐시 불일치 문제가 발생할 수 있습니다. 만약 멀티 인스턴스가 필요하다면 Caddy나 Nginx에서 리버스 프록시 로드 밸런싱을 쓰는 게 안전합니다.
4reload vs restart — 무중단 배포
배포할 때 pm2 restart를 쓰면 프로세스를 죽이고 새로 시작하기 때문에 순간적으로 서비스가 중단됩니다. 배포 자동화를 적용하면 Git Push부터 프로덕션 반영까지 한 번에 처리할 수 있습니다.pm2 reload는 새 프로세스를 먼저 띄운 뒤 이전 프로세스를 종료하므로 다운타임이 없습니다. 단, 클러스터 모드에서만 무중단 재시작이 가능합니다. fork 모드에서는 restart와 동일하게 동작합니다.
# 배포 시 명령어 비교
# restart: 기존 프로세스 kill → 새 프로세스 start # 다운타임 발생 (보통 2~5초) pm2 restart my-app # reload: 새 프로세스 start → 준비 완료 후 → 기존 프로세스 kill # 다운타임 0초 (cluster 모드에서 완벽 동작) pm2 reload my-app # fork 모드에서는 gracefulReload 옵션 활용 pm2 reload my-app --update-env
| 명령어 | 동작 | 다운타임 | 사용 시점 |
|---|---|---|---|
| restart | kill → start | 2~5초 | 설정 변경, 긴급 복구 |
| reload | start → ready → kill old | 0초 (cluster 모드) | 일반 배포 (cluster 모드) |
| stop + start | 완전 중지 → 시작 | 수초~수분 | 점검, 마이그레이션 |
배포 스크립트에서 항상 reload를 쓰세요
습관적으로 restart를 쓰는 분들이 많은데, 프로덕션에서는 반드시 reload를 사용해야 합니다. 코드 배포용 쉘 스크립트에 pm2 reload를 기본으로 넣어두면 실수로 다운타임을 만드는 일이 없습니다. 단, 무중단 재시작(zero-downtime reload)은 클러스터 모드에서만 동작합니다. fork 모드에서는 reload가 restart와 동일하게 동작하므로 순간적인 중단이 발생합니다.
5로그 관리와 logrotate
PM2는 기본적으로 로그를 파일에 기록합니다. 문제는 관리하지 않으면 로그 파일이 무한정 커진다는 겁니다. 디스크가 꽉 차서 서비스가 죽는 어이없는 장애를 막으려면 logrotate 설정이 필수입니다.
# pm2-logrotate 모듈 설치 및 설정
# logrotate 모듈 설치 pm2 install pm2-logrotate # 설정 변경 pm2 set pm2-logrotate:max_size 10M # 파일당 최대 크기 pm2 set pm2-logrotate:retain 7 # 보관 파일 수 pm2 set pm2-logrotate:compress true # 이전 로그 gzip 압축 pm2 set pm2-logrotate:dateFormat YYYY-MM-DD_HH-mm pm2 set pm2-logrotate:rotateModule true # 로그 경로 확인 pm2 logs --nostream # 로그 파일 위치만 표시
| 설정 | 권장 값 | 설명 |
|---|---|---|
| max_size | 10M | 파일이 이 크기를 넘으면 새 파일 생성 |
| retain | 7 | 최근 7개 로그 파일만 보관 |
| compress | true | 이전 로그를 gzip으로 압축 |
| workerInterval | 30 | 30초마다 로그 크기 체크 |
디스크 부족 장애를 예방하세요
실제 운영 중 로그 파일이 수십 GB까지 커져서 디스크가 100%에 도달하면, Next.js가 정상적으로 응답할 수 없게 됩니다. logrotate는 PM2 설치 직후 바로 설정하는 걸 권장합니다. 서버 상태를 실시간으로 감시하려면 Grafana + Prometheus 통합 모니터링 도 함께 구축해 보세요.
6systemd 연동과 자동 재시작
서버가 재부팅되면 PM2 프로세스도 같이 사라집니다. pm2 startup 명령어로 systemd 서비스를 등록하면, 서버 부팅 시 PM2가 자동으로 시작되고 이전에 실행 중이던 앱도 자동으로 복원됩니다.
# systemd 서비스 등록
# 1. startup 스크립트 생성 pm2 startup systemd # 출력되는 sudo 명령어를 복사해서 실행 # 2. 현재 프로세스 목록 저장 pm2 save # 3. 서버 재부팅 후 자동 복원 확인 sudo reboot # ... 재부팅 후 ... pm2 status # 이전 프로세스들이 자동으로 실행됨 # systemd 서비스 상태 확인 systemctl status pm2-deploy
# 유용한 PM2 모니터링 명령어
# 대시보드 (CPU, 메모리, 로그 실시간 확인) pm2 monit # 프로세스별 상세 정보 pm2 show my-app # 메모리 사용량 변화 추적 pm2 show my-app | grep memory # 재시작 횟수 확인 (비정상 재시작이 많으면 문제) pm2 show my-app | grep restarts
pm2 save를 잊지 마세요
앱을 추가하거나 설정을 변경한 뒤에는 반드시 pm2 save를 실행해야 합니다. 이 명령어가 현재 프로세스 목록을 디스크에 저장하고, 서버 재부팅 시 이 목록을 기준으로 복원합니다.
요약 체크리스트
PM2 프로덕션 운영 핵심 요약
- ✓ecosystem.config.js 파일로 모든 앱 설정을 관리한다
- ✓Next.js는 fork 모드를 사용하고, 멀티 인스턴스는 리버스 프록시로 처리한다
- ✓배포 시 restart 대신 reload를 사용한다 (무중단 배포는 cluster 모드에서만 가능)
- ✓pm2-logrotate로 로그 파일 크기를 제한하고 자동 압축한다
- ✓pm2 startup + pm2 save로 서버 재부팅 시 자동 복원을 설정한다
- ✓max_memory_restart를 설정해서 메모리 누수로 인한 장애를 방지한다
본 글은 PM2 v5 기준으로 작성되었으며, 실제 운영 환경의 OS 버전, Node.js 버전, 앱 구조에 따라 설정값이 달라질 수 있습니다. 특히 cluster 모드는 앱의 특성을 충분히 테스트한 후 적용하시기 바랍니다. 본 콘텐츠의 비상업적 공유는 자유이나, 상업적 이용 시 문의 페이지를 통해 연락 바랍니다.
서버 운영이 부담스러우신가요?
Treeru는 PM2, Caddy, 배포 자동화까지 포함한 서버 운영 환경을 구축해 드립니다. 안정적인 프로덕션 환경을 상담받으세요.
서버 운영 상담 신청댓글
(5개)로그인하면 댓글을 작성할 수 있습니다.
fork 모드와 cluster 모드 차이를 이렇게 명확하게 설명한 글은 처음입니다. Next.js는 자체 클러스터링이 있어서 fork가 낫다는 팁이 유용했어요.
우리 팀도 Vercel에서 자체 서버로 옮기면서 PM2를 도입했는데, 이 글에 나온 것처럼 ecosystem 파일 하나로 관리하니까 훨씬 깔끔해졌습니다.
systemd 연동 부분이 특히 좋았습니다. 서버 재부팅 후 PM2가 자동으로 살아나는 게 프로덕션에서는 필수인데, startup 명령어 하나면 되니까요.
관련 글
© 2026 TreeRU. All rights reserved.
본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.