서버 운영
Node.js 앱이 로컬에선 멀쩡한데 서버에서만 죽을 때
로컬 재현이 안 되는 Node.js 크래시가 서버에서만 반복될 때, 프로세스 상태와 로그로 원인을 좁히는 순서를 정리했다.
서버에서만 죽는 Node.js 앱을 마주하면 막막하다. 로컬에서는 이상이 없으니 환경 차이 어딘가에 원인이 있다는 건 알지만, 어디서부터 봐야 할지 모른다. 주로 OOM, 미처리 예외, 환경변수 누락, 디스크 풀, 포트 충돌 중 하나다.
프로세스가 어떻게 죽었는지부터 확인한다
sudo journalctl -u 서비스이름 -n 100 --no-pager
exit code가 137이면 OOM(메모리 부족)으로 강제 종료된 것이다. free -h로 메모리 여유를 보고, Node.js 실행 옵션에 --max-old-space-size가 설정돼 있는지 확인한다. exit code 1이면 앱 로직에서 uncaught exception이 난 것이다. 에러 메시지가 로그에 있으니 그걸 읽으면 된다.
포트와 디스크
재시작 직후 포트가 이미 점유돼 있으면 앱이 올라오지 못한다.
sudo ss -lntp | grep :3000
df -h
이전 프로세스가 좀비로 남아 포트를 잡고 있는 경우가 생각보다 많다. 디스크가 100%면 로그 파일이나 npm 캐시가 공간을 다 잡아먹은 것이다.
환경변수 누락 확인
로컬 .env에는 있지만 서버에는 없는 변수가 원인인 경우도 흔하다. 앱 시작 시점에 필수 환경변수를 검증하는 코드가 없으면 런타임에서야 에러가 터진다.
sudo journalctl -u 서비스이름 -n 50 | grep -iE "env|undefined|cannot read"
에러 메시지에서 어떤 키가 undefined로 나오는지 찾고, 서버 환경에 해당 값이 있는지 점검한다.
원인별 확인 포인트
- exit 137 → OOM,
free -h와 메모리 제한 설정 확인 - exit 1 → 앱 에러 로그, uncaught exception 메시지
- 포트 에러 →
ss -lntp로 포트 점유 여부 - 디스크 에러 →
df -h
원인이 특정됐으면 한 번에 하나씩 바꾸면서 검증한다. 여러 설정을 동시에 바꾸면 어떤 게 효과가 있었는지 알 수 없다.