앱을 &나 nohup으로 돌리는 것은 서버가 재부팅되거나, 프로세스가 충돌하거나, 로그를 찾고 싶어지기 전까지는 괜찮습니다 — 그때 무너집니다. systemd가 표준 답입니다. 부팅 시 앱을 시작하고, 죽으면 재시작하며, 로그를 캡처합니다. 스크립트나 바이너리를 관리형 서비스로 바꾸는 것은 작은 파일 하나입니다.
1. 유닛 파일을 작성하세요
/etc/systemd/system/myapp.service를 만듭니다:
[Unit]
Description=My application
After=network.target
[Service]
User=myapp
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/python3 /opt/myapp/run.py
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
ExecStart, WorkingDirectory, User를 앱에 맞게 조정하세요. Restart=always가 바로 그것을 살아 있게 하는 것입니다.
2. 전용 사용자를 만드세요 (권장)
sudo useradd --system --no-create-home --shell /usr/sbin/nologin myapp
sudo chown -R myapp:myapp /opt/myapp
비-root 사용자로 실행하면 앱이 언젠가 탈취되더라도 피해를 제한합니다.
3. 활성화하고 시작하세요
sudo systemctl daemon-reload
sudo systemctl enable --now myapp
enable은 부팅 시 시작하게 하고, --now는 즉시 시작합니다.
4. 상태와 로그를 확인하세요
sudo systemctl status myapp
journalctl -u myapp -f # 실시간 로그 따라가기
일상 명령
sudo systemctl restart myapp # 변경 후 재시작
sudo systemctl stop myapp # 멈추기
sudo systemctl disable myapp # 부팅 시 시작 끄기
솔직한 주의점
- 유닛 파일을 편집한 뒤
daemon-reload를 실행하세요. 그러지 않으면 systemd가 옛 버전을 씁니다. - 충돌 루프를 조심하세요. 앱이 즉시 실패하면
Restart=always는 영원히 재시도합니다 —RestartSec=5가 시도 간격을 벌립니다. 로그로 근본 오류를 고치세요. - 비-root
User=를 선호하세요. 그래야 탈취된 앱이 서버 전체를 소유하지 못합니다.
다음 단계
systemd 서비스는 무엇이든 24/7 돌아가게 하는 방법입니다 — 예를 들어 24시간 돌아가는 AI 에이전트나 자체 호스팅 RustDesk 서버 뒤의 릴레이입니다. 앱이 대신 컨테이너화되어 있다면 Docker의 --restart unless-stopped가 같은 역할을 합니다 — Docker 설치하는 방법을 참조하세요.
댓글
아직 댓글이 없습니다. 첫 번째가 되세요.