리눅스 서버를 운영하다 보면 "서비스가 안 떠요"라는 상황을 자주 만납니다.
이때 무작정 재시작만 반복하면 원인을 놓치기 쉽습니다. 특히 systemd 기반 배포판에서는
로그, 유닛 파일, 권한, 포트 충돌, 환경 변수만 차근차근 확인해도 대부분의 장애 원인을 빠르게 좁힐 수 있습니다.
이번 글은 Ubuntu, Debian, Rocky Linux처럼 systemd를 사용하는 환경에서 서비스가 시작되지 않을 때 따라가기
좋은 점검 순서를 정리한 글입니다.
1. 먼저 상태부터 본다
가장 먼저 할 일은 서비스 상태 확인입니다.
systemctl status nginx
여기서 확인할 포인트는 아래와 같습니다.
- Active: 값이 failed인지 activating에서 멈췄는지
- 마지막 에러 메시지에 permission denied, address already in use, no such file 같은 단서가 있는지
- Main PID가 바로 종료되는지
- 재시작 반복으로 Start request repeated too quickly가 보이는지
상태 출력만으로도 절반은 방향이 잡힙니다.
2. journalctl 로그를 함께 본다
systemctl status는 요약 정보에 가깝습니다. 실제 원인은 저널 로그에 더 자세히 남아 있습니다.
journalctl -u nginx -n 100 --no-pager
실시간으로 따라가려면 아래 명령이 편합니다.
journalctl -u nginx -f
특히 아래 메시지는 자주 나옵니다.
- 설정 파일 문법 오류
- 실행 파일 경로 오류
- 환경 파일 누락
- 권한 문제
- 포트 점유 충돌
- 필요한 디렉터리 미존재
서비스가 시작되다 바로 죽는다면 journalctl을 먼저 보는 습관이 가장 중요합니다.
3. 유닛 파일이 올바른지 확인한다
커스텀 서비스라면 유닛 파일 설정이 잘못된 경우가 많습니다.
systemctl cat myapp
중점적으로 볼 항목은 다음과 같습니다.
- ExecStart= 경로가 실제 파일과 일치하는지
- WorkingDirectory=가 맞는지
- User=와 Group=이 존재하는지
- EnvironmentFile= 경로가 실제로 있는지
- Restart= 정책 때문에 실패가 가려지고 있지 않은지
유닛 파일을 수정했다면 꼭 아래 명령을 실행해야 합니다.
sudo systemctl daemon-reload
이 단계를 빼먹으면 설정을 바꿔도 예전 정의로 동작합니다.
4. 실행 파일과 권한을 점검한다
서비스가 시작되지 않는 이유 중 흔한 축은 권한 문제입니다.
ls -l /usr/local/bin/myapp ls -ld /var/lib/myapp /var/log/myapp id myapp
확인할 내용은 아래와 같습니다.
- 실행 파일에 실행 권한이 있는지
- 서비스 계정이 로그 디렉터리나 데이터 디렉터리에 쓸 수 있는지
- 심볼릭 링크가 끊어지지 않았는지
- 보안 정책 때문에 실행이 막히지 않는지
SELinux가 켜진 환경이라면 권한이 맞아 보여도 정책 때문에 막히는 경우가 있습니다. Rocky Linux, AlmaLinux, RHEL 계열에서는 아래도 같이 확인해두면 좋습니다.
getenforce ausearch -m avc -ts recent
5. 포트 충돌 여부를 확인한다
웹 서버, API 서버, DB 프록시 계열은 포트 충돌 때문에 실패하는 경우가 많습니다.
ss -lntp | grep ':80 ' ss -lntp | grep ':443 '
이미 다른 프로세스가 같은 포트를 잡고 있다면 서비스는 정상 설정이어도 올라오지 않습니다. 이럴 때는 아래를 판단해야 합니다.
- 기존 프로세스가 정상 프로세스인지
- 이전 인스턴스가 비정상 종료 후 남아 있는지
- 설정 파일에서 포트를 잘못 지정했는지
6. 설정 파일 문법 검사를 먼저 한다
애플리케이션마다 문법 검사 명령이 따로 있는 경우가 많습니다.
예를 들면:
nginx -t apachectl configtest sshd -t named-checkconf
서비스 재시작 전에 문법 검사를 먼저 하면 장애 시간을 줄일 수 있습니다. 특히 웹 서버나 SSH 설정은 실서버에서 바로 재시작하기보다 문법 검사 후 반영하는 습관이 안전합니다.
7. 환경 변수와 외부 의존성을 본다
개발한 애플리케이션 서비스는 환경 변수 누락으로 실패하는 경우가 생각보다 많습니다.
예를 들어 아래 항목을 확인합니다.
- .env 파일 또는 EnvironmentFile= 존재 여부
- DB 주소, 포트, 계정 정보가 맞는지
- 외부 API DNS 해석이 되는지
- 필요한 마운트 경로나 네트워크가 먼저 준비되는지
의존 서비스가 필요한 경우에는 After=와 Requires= 설정도 확인해야 합니다.
8. 직접 같은 계정으로 실행해본다
원인이 안 보이면 서비스 계정으로 직접 실행해보는 방법이 효과적입니다.
sudo -u myapp /usr/local/bin/myapp
이렇게 실행했을 때만 보이는 오류가 있습니다.
- 라이브러리 누락
- 상대 경로 문제
- 홈 디렉터리 의존성
- 파일 쓰기 권한 오류
- 환경 변수 누락
즉, systemd 문제처럼 보여도 실제로는 애플리케이션 실행 문제인 경우가 많습니다.
9. 자주 만나는 대표 원인 5가지
실무에서 특히 자주 만나는 패턴은 아래 다섯 가지입니다.
- ExecStart 경로 오타
- 로그/데이터 디렉터리 권한 부족
- 이미 사용 중인 포트 충돌
- 설정 파일 문법 오류
- 환경 변수 또는 의존 서비스 누락
장애 대응 속도를 높이려면 이 다섯 가지를 먼저 의심하는 습관이 좋습니다.
10. 점검 순서를 체크리스트로 정리하면
서비스가 안 뜰 때는 아래 순서로 보면 됩니다.
- systemctl status 서비스명
- journalctl -u 서비스명 -n 100 --no-pager
- systemctl cat 서비스명
- 실행 파일 경로 및 권한 확인
- 포트 충돌 확인
- 애플리케이션 설정 문법 검사
- 환경 변수 및 의존 서비스 확인
- 서비스 계정으로 직접 실행
이 순서대로만 따라가도 감으로 재시작하는 방식보다 훨씬 빠르게 원인을 찾을 수 있습니다.
마무리
리눅스 트러블 슈팅은 복잡한 기술보다도 "무슨 순서로 확인하느냐"가 더 중요할 때가 많습니다.
systemd 서비스 장애는 상태 확인, 저널 로그, 유닛 파일, 권한, 포트, 설정 문법만 체계적으로 봐도 대부분 해결 실마리를 찾을 수 있습니다.
장애가 발생했을 때 당황하지 말고, 이번 글의 순서대로 하나씩 지워나가 보세요.
원인은 생각보다 가까운 곳에 있습니다.