systemd로 Node.js 애플리케이션 실행하기
SSH 연결이 끊기거나 머신이 재부팅되어도 살아남도록 VDS에서 Node 애플리케이션을 실행하는 방법을 알아봐요. systemd 유닛, 환경 변수, 로그를 다뤄요.
업데이트 2026년 8월 23일
SSH 세션에서 수동으로 node index.js를 실행하면 세션이 끊길 때 프로세스도 함께 종료돼요. 애플리케이션을 영구적으로 실행하고 재부팅 후에도 자동으로 다시 시작되게 하려면 systemd 서비스로 등록하세요. systemd는 시스템에 기본 내장된 메커니즘이라 따로 설치할 것이 없어요.
준비
오래된 시스템 패키지가 아니라 공식 저장소에서 Node를 설치하세요.
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt install -y nodejs
node -v
전용 사용자를 만드세요. 애플리케이션은 root로 실행되면 안 돼요.
useradd -r -m -d /srv/app -s /usr/sbin/nologin appuser
chown -R appuser:appuser /srv/app
sudo -u appuser npm ci --omit=dev --prefix /srv/app
systemd 서비스
/etc/systemd/system/myapp.service 파일은 다음과 같아요.
[Unit]
Description=My Node app
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=appuser
WorkingDirectory=/srv/app
EnvironmentFile=/srv/app/.env
ExecStart=/usr/bin/node /srv/app/index.js
Restart=always
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target
systemctl daemon-reload
systemctl enable --now myapp
systemctl status myapp
Restart=always는 프로세스가 비정상 종료된 뒤 다시 시작하게 해줘요. EnvironmentFile은 따옴표도 export도 없는 순수한 KEY=value 형식의 파일이며, 비밀번호가 들어 있으니 권한을 600으로 설정하세요.
프록시를 통한 외부 노출
애플리케이션은 127.0.0.1:3000에서만 수신하고, 인증서가 있는 웹 서버가 외부에 서비스하도록 구성하세요.
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
자세한 내용은 리버스 프록시와 Let's Encrypt 문서를 참고하세요. 애플리케이션이 0.0.0.0에서 수신하면 프록시를 우회해 암호화 없이 인터넷에서 접근할 수 있어요.
로그와 업데이트
journalctl -u myapp -f
journalctl -u myapp --since "1 hour ago" -p err
systemctl restart myapp
stdout으로 출력되는 내용은 자동으로 journal에 기록돼요. 별도의 로그 파일이나 로그 로테이션을 설정할 필요가 없어요.
자주 발생하는 오류
| 증상 | 원인 |
|---|---|
status=203/EXEC | ExecStart의 node 또는 파일 경로가 잘못됨 — 절대 경로를 사용하세요 |
| 서비스가 반복 재시작됨 | 애플리케이션이 시작 시 비정상 종료됨: journalctl -u myapp -n 50을 확인하세요 |
EADDRINUSE | 수동으로 실행한 프로세스가 아직 실행 중임: ss -tulpn | grep 3000 |
| SSH에서는 작동하지만 서비스로는 작동하지 않음 | 환경 변수가 누락됨 — systemd에는 해당 변수가 없으니 EnvironmentFile에 설정하세요 |
| VDS-1에서 빌드 중 메모리 부족 | 로컬에서 빌드한 뒤 완성된 빌드를 서버에 업로드하세요 |
systemd 위에 pm2를 올리지 마세요. 하나의 프로세스를 두 개의 관리자가 제어하면 혼란이 생겨요. pm2가 프로세스를 재시작하는 동안 systemd는 프로세스가 살아 있다고 판단하게 돼요.