직접 만든 스크립트나 앱을 "서버 켜질 때 자동으로, 죽으면 다시" 띄우고 싶을 때 답은 systemd 서비스 등록입니다. nohup이나 & 로 돌리면 재부팅·크래시에 무력합니다. 유닛 파일 하나면 끝납니다.
1단계 — 유닛 파일 작성
/etc/systemd/system/myapp.service 를 만듭니다.
INI
[Unit]
Description=My App
After=network.target
[Service]
ExecStart=/usr/bin/node /opt/myapp/server.js
WorkingDirectory=/opt/myapp
User=app
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
ExecStart 는 절대 경로여야 합니다(node 만 쓰면 실패). Restart=on-failure 로 크래시 시 자동 재기동됩니다.
2단계 — 등록하고 켜기
서버 터미널
sudo systemctl daemon-reload # 유닛 파일 변경 후 항상
sudo systemctl enable --now myapp # 부팅 자동시작 + 즉시 실행
systemctl status myapp
daemon-reload 를 빼먹으면 수정한 내용이 반영되지 않습니다. 가장 흔한 실수입니다.
안 뜰 때 — 원인별 진단
서버 터미널
journalctl -u myapp -n 50 --no-pager # 이 서비스 로그만
systemctl status myapp # 종료 코드·마지막 줄
| 증상 | 원인 | 해결 |
|---|---|---|
status=203/EXEC | ExecStart 경로 틀림·실행권한 없음 | which로 절대경로, chmod +x |
status=200/CHDIR | WorkingDirectory 없음 | 경로 생성·수정 |
| 즉시 죽고 재시작 반복 | 앱 자체 에러 | journalctl에서 앱 로그 확인 |
Failed to start 뒤 묵묵부답 | 유닛 문법 오류 | systemd-analyze verify myapp.service |
체크리스트
로컬 터미널
systemd-analyze verify /etc/systemd/system/myapp.service # 문법 검증
sudo systemctl daemon-reload # 변경 반영
systemctl status myapp # 실행 상태
journalctl -u myapp -f # 실시간 로그 추적
유닛 파일 작성부터 Restart 정책·타이머·의존성까지 직접 서비스를 띄워보는 실습은 리눅스 트랙에서 회원가입 없이 무료로 할 수 있습니다.