우분투 · 리눅스 입문 — 19편 (중급)

systemd 서비스 만들기 — systemctl·journalctl

"이 프로그램이 부팅하면 자동으로 켜지고, 죽으면 알아서 다시 켜지면 좋겠다" — 그걸 해주는 게 systemd 서비스입니다. 14편의 짝.

2026년 5월 13일 · 약 8분 · 26편 입문 시리즈 19편

터미널에 systemctl status·journalctl 명령으로 서비스를 관리하는 화면 — systemd 서비스 만들기를 상징하는 일러스트

14편(프로세스 관리)에서 "PID 1 = systemd, 절대 kill 하지 말 것"이라고 했죠. 이번 편이 그 systemd 이야기입니다 — 리눅스가 부팅할 때 가장 먼저 뜨는 프로그램이자, 백그라운드에서 도는 모든 "서비스(데몬)"를 관리하는 총감독.

왜 알아야 하나 — ① 이미 도는 서비스를 다루려면(웹서버 재시작, SSH 재시작, 로그 보기) systemctl·journalctl을 써야 하고, ② 내가 만든 프로그램(스크립트·웹앱)을 "부팅 시 자동 시작 + 죽으면 재시작"으로 등록하려면 .service 파일을 만들어야 합니다. 14편에서 nohup·&로 백그라운드 실행을 봤지만, 그건 "이번 세션 동안만". 진짜 "서버처럼 항상 떠 있게" 하려면 systemd 서비스가 정답이에요. 26편 입문 시리즈 19편, "중급" 묶음.

준비물 — 우분투 + 터미널 + sudo. /etc/systemd/system에 파일을 만들고 서비스를 켜는 실습이 있으니 가상 머신 권장(서비스 설정을 잘못해도 VM이면 부담 없음). 8편(nano)·12편(tail -f 로그)·14편(프로세스)을 봤다면 자연스럽게 이어집니다.

systemd가 뭔가 — init과 서비스

리눅스가 켜지면 커널이 뜨고, 커널이 가장 먼저 실행하는 사용자 프로그램이 systemd(PID 1)입니다. 얘가 하는 일 — 나머지 모든 걸 정해진 순서로 시작하고, 백그라운드 서비스들을 관리하고, 죽은 서비스를 다시 살리고, 로그를 모읍니다. "init 시스템"이라고 부르는 그 역할이에요(옛날엔 SysV init·Upstart였는데 이제 대부분 systemd).

  • 서비스(unit / 데몬) = 백그라운드에서 계속 도는 프로그램. 예: ssh.service(원격 접속 받기), nginx.service(웹), cron.service(예약 작업, 20편). .service 파일이 "이걸 어떻게 실행/재시작/시작순서를 정하나"를 적어둔 설정.
  • 두 가지 상태를 구분하세요 — active(running): 지금 돌고 있나. enabled: 부팅 시 자동으로 시작되나. 둘은 별개 — "지금은 안 돌지만 다음 부팅 땐 켜짐"도 가능.
  • 관리 도구systemctl(서비스를 시작/멈춤/켜기/상태), journalctl(서비스가 남긴 로그를 보기). 이 둘이 9할입니다.

기존 서비스 다루기 — systemctl

$ systemctl status ssh ● ssh.service - OpenSSH server ... Active: active (running) since ... ← 지금 돌고 있나 + 최근 로그 몇 줄. 가장 자주 쓰는 명령 $ sudo systemctl restart ssh ← 재시작 (설정 바꾼 뒤 자주). start(시작)·stop(멈춤)·reload(설정만 다시 읽기)도 있음 $ sudo systemctl enable ssh ← '부팅 시 자동 시작' 켜기. disable 로 끄기. enable --now 하면 켜기+지금 시작 동시 $ systemctl is-active ssh ; systemctl is-enabled ssh active / enabled ← 스크립트에서 상태만 간단히 확인할 때 $ systemctl list-units --type=service --state=running ← 지금 돌고 있는 서비스 목록 (--all 이면 멈춘 것까지) $ systemctl --failed ← 시작 실패한 서비스만. 부팅 후 뭔가 이상하면 여기부터 봄
가장 많이 쓰는 셋: systemctl status 서비스(돌고 있나?·왜 죽었나?), sudo systemctl restart 서비스(설정 바꾸고 적용), sudo systemctl enable --now 서비스(부팅 자동시작 + 지금 켜기). 웹서버·DB·SSH 등을 운영하면 이 셋을 하루에도 몇 번 칩니다. sudo systemctl reboot·poweroff·suspend로 시스템 자체도 제어해요(전원 메뉴의 명령어 버전).

로그 보기 — journalctl

systemd가 모든 서비스의 로그(stdout·stderr — 12편의 그 출구들)를 한 군데 모읍니다. 그게 "저널". 보는 법:

$ journalctl -u ssh ← ssh.service 의 로그만. -u = unit(서비스) 지정. 핵심 명령 $ journalctl -u ssh -f ← 실시간 따라보기 (12편 tail -f 의 systemd 버전). 서비스 동작 디버깅에 최고. Ctrl+C 로 나감 $ journalctl -u ssh --since "1 hour ago" ← 최근 1시간만. --since "today" / "2026-05-13 09:00" 등 시간 지정 $ journalctl -u ssh -p err -b ← -p err: 에러 이상만. -b: 이번 부팅 이후만. "왜 시작 실패했지" 추적할 때 $ journalctl -xe ← 가장 최근 로그 + 설명(-x). systemctl status 가 "실패했다"고만 하면 여기서 자세히 $ journalctl --disk-usage ; sudo journalctl --vacuum-time=7d ← 저널이 차지하는 용량 확인 / 7일치만 남기고 비우기 (15편 디스크 정리에서 나온 그것)

흐름: 서비스가 이상하다 → systemctl status 서비스(상태와 최근 로그 몇 줄) → 더 보려면 journalctl -u 서비스 -e(끝부터) 또는 -xe → 동작을 지켜보려면 journalctl -u 서비스 -f 켜두고 그 서비스를 restart해보기. 이 패턴이면 "왜 안 되는지"가 거의 다 보입니다.

내 서비스 만들기 — .service 파일

이제 핵심 — 내가 만든 스크립트나 앱을 "부팅 시 자동 시작 + 죽으면 재시작" 서비스로 등록하기. 예로, 간단한 스크립트 하나를 서비스로:

$ sudo nano /etc/systemd/system/myapp.service [Unit] Description=My app # 사람이 알아볼 설명 After=network-online.target # 네트워크가 준비된 뒤 시작 Wants=network-online.target [Service] ExecStart=/home/jspark/myapp/run.sh # 실행할 명령 (절대 경로! 스크립트는 chmod +x — 9편) WorkingDirectory=/home/jspark/myapp # 그 디렉토리에서 실행 User=jspark # 누구 권한으로 (root 말고 일반 사용자 권장) Restart=on-failure # 죽으면 다시 시작 (always=무조건, on-failure=비정상 종료 시) RestartSec=5 # 5초 후 재시작 [Install] WantedBy=multi-user.target # 'enable' 하면 일반 부팅 단계에 포함 # 저장 후 ↓ $ sudo systemctl daemon-reload # 새/바뀐 .service 파일을 systemd 가 다시 읽게 (수정할 때마다 필수) $ sudo systemctl enable --now myapp # 부팅 자동시작 켜기 + 지금 시작 $ systemctl status myapp # 잘 떴나 확인 $ journalctl -u myapp -f # 로그 지켜보기
⚠️ 몇 가지 함정:ExecStart절대 경로로(~·상대경로 안 됨), 스크립트면 실행 권한(chmod +x, 9편) 필요. ② .service 파일을 고친 뒤엔 항상 sudo systemctl daemon-reload — 안 하면 옛 설정이 그대로. ③ User=를 빼면 root로 돌아갑니다 — 가능하면 일반 사용자로(보안). ④ 시스템에 원래 있던 서비스 파일(/lib/systemd/system/...)은 직접 고치지 말고 sudo systemctl edit 서비스로 덮어쓰기(override)만 — 8편처럼 원본은 건드리지 않는 원칙. ⑤ Restart=always인데 즉시 죽는 프로그램이면 무한 재시작 루프가 됩니다 — RestartSec를 충분히 주고 journalctl -u로 왜 죽는지 먼저 보세요.
오늘의 정리: systemd = PID 1, init + 서비스 관리자. active(지금 도나) ≠ enabled(부팅 시 자동). 다루기: systemctl status/restart/enable --now 서비스·list-units --type=service·--failed. 로그: journalctl -u 서비스·-f(실시간)·--since·-p err -b·-xe. 내 서비스: /etc/systemd/system/이름.service[Unit]/[Service]/[Install] 작성(ExecStart 절대경로·User=·Restart=on-failure) → sudo systemctl daemon-reloadenable --now. 원본 서비스 파일은 systemctl edit로만.

시리즈 흐름

  1. 1~16편 입문·기초·중급(vim·프로세스·디스크·네트워크) ✔   17편 ufw ✔   18편 SSH 키 ✔
  2. 19편 — systemd 서비스 (이 글) ✔
  3. 20편 — cron (정해진 시각·주기로 명령 자동 실행 — crontab -e·* * * * *). "중급" 묶음 마무리
  4. 21편~ — 셸 스크립트 작성법 / 베스트 프랙티스 / sed·awk / 로그 분석 / 서버 보안 / 도커 (고급)

오늘 할 일: systemctl status ssh로 SSH 서비스 상태를 보고, journalctl -u ssh -e로 그 로그를 끝부터 보세요. (가상 머신이면) 간단한 스크립트(echo "alive $(date)" >> /tmp/myapp.log; sleep 10 같은 걸 무한 루프로) 하나 만들어 .service로 등록하고 enable --nowjournalctl -u 그서비스 -f로 도는 걸 지켜보기. "부팅 자동시작 서비스를 만든다"는 감이 잡히면 됩니다. 20편에서 만나요. (systemd 전체는 man systemd.service·man systemctl, 또는 우분투 서버 문서.)

우분투·리눅스 입문 시리즈

이제 프로그램을 "항상 떠 있게" 만듭니다. 20편 "리눅스 cron 사용법"으로 "중급" 묶음을 마무리합니다.

다음 편은 JUNAI 블로그에서 이어 보세요.

© 2026 JUNAI · 우분투·리눅스 입문 시리즈 19편 · 본 글은 2026년 5월 13일 기준으로 작성되었습니다.

© 2026 주나이테크(주) @JUNAITECH