Skip to main content
Summary

프로그램을 '실행'에서 '운영'으로 바꾸기

지금까지 만든 프로그램은 터미널에서 직접 실행했습니다. 예를 들어 MQTT 온도 발행 프로그램은 다음처럼 실행했을 것입니다.

python3 temperature_publisher.py

이 방식은 연습할 때 좋습니다. 하지만 라즈베리 파이를 스마트홈 장치나 작은 서버처럼 쓰려면 한 가지 문제가 생깁니다. 터미널을 닫거나 라즈베리 파이를 재부팅하면 프로그램이 멈춥니다.

운영은 냄비를 불 위에 올려놓고 계속 지켜보는 일이 아니라, 전기밥솥처럼 정해진 조건에서 스스로 켜지고 문제가 생기면 흔적을 남기게 만드는 일입니다. 이번 장에서는 완성한 파이썬 프로그램과 웹 서버를 재부팅 후에도 자동으로 실행되게 만들고, 오류를 찾고, 보안을 강화하고, 백업 계획까지 세웁니다.

실습 기준 폴더는 다음과 같이 가정하겠습니다.

/home/pi/iot-home

사용자 이름이 pi가 아니라면 이후 명령에서 /home/pi 부분을 자신의 홈 디렉터리로 바꾸세요. 예를 들어 사용자 이름이 maker라면 /home/maker/iot-home처럼 바꾸면 됩니다.

서비스 운영, 자동 실행, 보안 관리AI 생성 이미지

systemd로 파이썬 프로그램 자동 시작하기

라즈베리 파이 OS는 systemd라는 서비스 관리자를 사용합니다. 서비스 관리자는 전원 스위치가 아니라 건물 관리실에 가깝습니다. 어떤 프로그램을 언제 켜고, 죽으면 어떻게 기록하고, 부팅할 때 자동으로 시작할지 관리합니다.

먼저 프로젝트 폴더와 프로그램이 있는지 확인합니다.

cd ~/iot-home
ls

예를 들어 이전 장에서 만든 MQTT 온도 발행 프로그램이 temperature_publisher.py라면, 직접 한 번 실행해 봅니다.

python3 temperature_publisher.py

정상적으로 MQTT 메시지가 발행된다면 Ctrl + C로 멈춥니다. 자동 실행 등록은 프로그램이 손으로 실행될 때 먼저 정상이어야 합니다.

이제 서비스 파일을 만듭니다.

sudo nano /etc/systemd/system/temperature-publisher.service

아래 내용을 입력합니다.

[Unit]
Description=MQTT temperature publisher
After=network-online.target mosquitto.service
Wants=network-online.target

[Service]
WorkingDirectory=/home/pi/iot-home
ExecStart=/usr/bin/python3 -u /home/pi/iot-home/temperature_publisher.py
Restart=on-failure
RestartSec=5
User=pi

[Install]
WantedBy=multi-user.target

-u는 파이썬 출력 버퍼를 줄여 print()로 남긴 메시지가 로그에 더 빨리 보이게 하는 옵션입니다. 필수는 아니지만, 오류를 추적할 때 도움이 됩니다.

저장한 뒤 systemd에 새 서비스 파일을 읽게 합니다.

sudo systemctl daemon-reload
sudo systemctl start temperature-publisher
sudo systemctl status temperature-publisher

상태 화면에 active (running)이 보이면 실행 중입니다. 이제 부팅할 때 자동으로 시작되게 등록합니다.

sudo systemctl enable temperature-publisher

실수하기 쉬운 지점이 있습니다.

  • WorkingDirectory는 프로그램이 실행될 기준 폴더입니다. 상대 경로로 파일을 읽거나 쓴다면 꼭 맞아야 합니다.

  • ExecStart에는 ~를 쓰지 말고 전체 경로를 씁니다.

  • User=pi는 프로그램을 어떤 사용자 권한으로 실행할지 정합니다. 사용자 이름이 다르면 바꿔야 합니다.

  • 파일 이름의 하이픈과 밑줄을 혼동하지 마세요. 예제에서는 서비스 이름은 temperature-publisher, 파이썬 파일은 temperature_publisher.py입니다.

  • 서비스 파일을 고친 뒤에는 sudo systemctl daemon-reload를 다시 실행해야 합니다.

주의: 서비스 파일은 /etc/systemd/system 아래에 만들기 때문에 sudo가 필요합니다. 잘못된 ExecStart 경로를 넣어도 보드가 망가지지는 않지만, 서비스는 시작되지 않습니다. 먼저 손으로 실행해 보고 서비스로 등록하세요.

가상환경을 사용했다면 ExecStart는 시스템 파이썬이 아니라 가상환경 안의 파이썬을 가리켜야 합니다.

ExecStart=/home/pi/iot-home/.venv/bin/python -u /home/pi/iot-home/temperature_publisher.py

Flask 웹 대시보드도 같은 방식으로 등록할 수 있습니다. 개발용 서버를 내부망 실습용으로만 쓴다는 조건에서 예를 들면 다음과 같습니다.

sudo nano /etc/systemd/system/iot-dashboard.service
[Unit]
Description=IoT Flask dashboard
After=network-online.target
Wants=network-online.target

[Service]
WorkingDirectory=/home/pi/iot-home
ExecStart=/home/pi/iot-home/.venv/bin/python -u /home/pi/iot-home/app.py
Restart=on-failure
RestartSec=5
User=pi

[Install]
WantedBy=multi-user.target

등록과 실행은 같습니다.

sudo systemctl daemon-reload
sudo systemctl enable --now iot-dashboard
sudo systemctl status iot-dashboard

같은 네트워크의 PC에서 브라우저를 열고 다음 주소로 접속해 확인합니다.

http://라즈베리파이IP:5000

만약 접속되지 않는다면 Flask 코드에서 host='0.0.0.0'으로 실행하고 있는지, 방화벽이나 공유기 설정이 막고 있지는 않은지 확인하세요. 이전 웹 대시보드 실습처럼 내부망에서만 테스트하는 용도라면 이 정도로 충분합니다.

journalctl로 오류가 난 시간을 따라가기

자동 실행의 단점은 오류 메시지를 눈앞에서 바로 보기 어렵다는 것입니다. 대신 systemd는 서비스의 표준 출력과 오류를 로그로 모읍니다. 이때 사용하는 명령이 journalctl입니다.

온도 발행 서비스 로그를 확인합니다.

journalctl -u temperature-publisher

권한 때문에 로그가 보이지 않는다면 앞에 sudo를 붙여 실행합니다.

sudo journalctl -u temperature-publisher

최근 로그만 보려면 다음처럼 입력합니다.

journalctl -u temperature-publisher -n 50

실시간으로 따라가려면 -f를 붙입니다.

journalctl -u temperature-publisher -f

문제가 생겼을 때는 다음 순서로 확인합니다.

  1. 서비스가 실행 중인지 확인합니다.

systemctl status temperature-publisher
  1. 최근 오류를 봅니다.

journalctl -u temperature-publisher -n 100
  1. 특정 시점 이후의 로그를 봅니다.

journalctl -u temperature-publisher --since "2026-07-15 09:00"
  1. 코드를 수정한 뒤 서비스를 재시작합니다.

sudo systemctl restart temperature-publisher

자주 만나는 오류는 대체로 세 가지입니다.

  • No such file or directory: 파일 경로가 틀렸습니다. WorkingDirectory와 ExecStart를 확인합니다.

  • ModuleNotFoundError: 필요한 파이썬 패키지가 현재 실행 환경에 없습니다. 가상환경을 쓴다면 ExecStart가 .venv/bin/python을 가리키는지 확인합니다.

  • Permission denied: 파일, 장치, GPIO, 데이터베이스 접근 권한이 부족합니다. 무조건 sudo로 실행하기보다 파일 소유자와 그룹을 먼저 확인합니다.

파이썬 코드 안에서도 로그를 남기면 원인 추적이 쉬워집니다. 가장 간단한 방법은 print()를 쓰는 것입니다. systemd 서비스로 실행하면 print() 출력도 journalctl에서 볼 수 있습니다.

print("temperature publisher started")

운영 시간이 길어지면 print()보다 logging 모듈을 쓰는 편이 좋지만, 초보 단계에서는 먼저 "언제 시작했고, 어떤 값에서 실패했는지"를 남기는 습관이 중요합니다.

기본 보안: 문을 잠그고 필요한 창만 열기

라즈베리 파이가 네트워크에 연결되면 작은 컴퓨터가 아니라 작은 서버가 됩니다. 서버는 편리하지만 공격 대상도 됩니다. 복잡한 보안 장비를 먼저 고민하기보다 기본 문단속부터 해야 합니다.

먼저 초기 설정 때 정한 비밀번호가 약하거나 여러 곳에서 재사용한 비밀번호라면 바꿉니다.

passwd

짧은 단어 하나보다 길고 기억하기 쉬운 문장을 쓰는 편이 안전합니다. 예를 들어 여러 단어를 조합한 긴 비밀번호가 좋습니다.

SSH를 오래 쓸 계획이라면 비밀번호 로그인보다 SSH 키 로그인을 권장합니다. 개인 PC에서 키를 만들고 라즈베리 파이에 공개키를 복사합니다.

개인 PC에서 실행합니다.

ssh-keygen -t ed25519
ssh-copy-id pi@라즈베리파이IP

사용자 이름이 pi가 아니라면 pi@라즈베리파이IP 부분도 자신의 사용자 이름으로 바꾸세요.

그다음 새 터미널을 열어 키로 접속되는지 확인합니다.

ssh pi@라즈베리파이IP

키 로그인이 되는 것을 확인한 뒤에만 비밀번호 로그인을 끕니다. 라즈베리 파이에서 다음 파일을 만듭니다.

sudo nano /etc/ssh/sshd_config.d/99-local.conf

다음 내용을 넣습니다.

PasswordAuthentication no
PermitRootLogin no

설정 파일 문법을 확인합니다. 아무 메시지도 나오지 않으면 보통 문제가 없다는 뜻입니다.

sudo sshd -t

그다음 SSH 설정을 다시 읽습니다.

sudo systemctl reload ssh

주의: 비밀번호 로그인을 끄기 전에 절대 현재 SSH 창을 닫지 마세요. 새 창에서 키 로그인이 되는지 먼저 확인해야 합니다. 실패하면 모니터와 키보드를 직접 연결해 복구해야 할 수 있습니다.

불필요한 서비스도 줄입니다. 켜진 서비스 목록을 확인합니다.

systemctl list-unit-files --state=enabled

예를 들어 원격 데스크톱을 쓰지 않는다면 관련 서비스를 끌 수 있습니다. 서비스 이름은 운영체제 버전과 설치 상태에 따라 다를 수 있으므로 먼저 목록과 상태를 확인합니다.

systemctl list-unit-files | grep -i vnc
systemctl status vncserver-x11-serviced
sudo systemctl disable --now vncserver-x11-serviced

위 서비스가 없다는 메시지가 나오면 다른 원격 데스크톱 도구를 쓰고 있거나 설치되어 있지 않은 것입니다. Mosquitto, Node-RED, Flask 대시보드처럼 실제로 쓰는 서비스만 남기는 것이 좋습니다.

정기 업데이트도 기본 보안입니다.

sudo apt update
sudo apt upgrade

운영 중인 장비에서는 업데이트 직후 재부팅이 필요할 수 있습니다. 중요한 장치라면 바로 적용하기보다 백업 후, 사용자가 적은 시간에 진행하세요.

백업은 이미지 백업과 프로젝트 백업을 나눠 생각하기

백업은 "언젠가 고장 날 것"을 인정하는 작업입니다. 라즈베리 파이에서 가장 흔한 저장장치는 microSD 카드입니다. 작고 편리하지만 전원 문제, 쓰기 작업, 오래된 사용으로 손상될 수 있습니다.

백업은 두 종류로 나눕니다.

첫째, microSD 카드 이미지 백업입니다. 운영체제, 설치된 패키지, 설정, 프로젝트까지 통째로 복사합니다. 장점은 복구가 빠르다는 것입니다. 카드가 망가지면 새 카드에 이미지를 기록해 거의 같은 상태로 되돌릴 수 있습니다. 단점은 파일 크기가 크고, 자주 만들기 번거롭다는 점입니다.

둘째, 프로젝트 폴더 백업입니다. 코드, 설정 파일, 데이터베이스, 센서 기록처럼 실제 프로젝트에 중요한 파일만 복사합니다. 가볍고 자주 할 수 있습니다. 대신 운영체제 설치와 패키지 설치는 다시 해야 할 수 있습니다.

프로젝트 폴더를 다른 PC나 NAS로 복사할 때는 rsync가 편리합니다. 개인 PC에서 실행합니다.

rsync -av pi@라즈베리파이IP:/home/pi/iot-home/ ./iot-home-backup/

라즈베리 파이 안에서 USB 저장장치로 복사할 수도 있습니다. 예를 들어 USB가 /media/pi/USB에 연결되어 있다면 다음처럼 백업합니다.

rsync -av /home/pi/iot-home/ /media/pi/USB/iot-home-backup/

나중에 백업 폴더를 원본과 똑같이 맞추고 싶을 때는 --delete 옵션을 쓸 수 있습니다. 다만 원본에서 지운 파일이 백업에서도 지워지므로, 처음에는 -av만 사용해 동작을 익히는 편이 안전합니다.

SQLite 데이터베이스를 사용한다면 실행 중인 파일을 그대로 복사하는 것보다 백업 파일을 따로 만드는 방법이 안전합니다. 프로젝트 폴더에서 다음처럼 실행합니다.

sqlite3 readings.db ".backup 'readings-backup.db'"

서비스 파일도 백업 대상입니다. 프로젝트 코드만 백업하고 서비스 파일을 잊으면 복구 후 자동 실행이 되지 않습니다.

sudo cp /etc/systemd/system/temperature-publisher.service ~/iot-home/
sudo cp /etc/systemd/system/iot-dashboard.service ~/iot-home/

복구할 때는 이 파일들을 다시 /etc/systemd/system/으로 복사하고 sudo systemctl daemon-reload를 실행해야 합니다.

백업 계획은 복잡할 필요가 없습니다. 초보 단계에서는 다음 정도면 충분합니다.

  • 프로젝트 코드는 수정할 때마다 PC로 복사합니다.

  • 센서 데이터베이스는 하루 또는 일주일 단위로 백업합니다.

  • 서비스 파일과 중요한 설정 파일도 프로젝트 백업에 포함합니다.

  • 큰 설정 변경 전에는 microSD 카드 이미지를 만듭니다.

  • 복구가 되는지 새 카드나 임시 폴더에서 한 번 시험합니다.

백업은 만든 순간이 아니라 복구에 성공했을 때 의미가 있습니다.

24시간 운영을 위한 전원, 온도, 저장장치 점검

라즈베리 파이를 하루 종일 켜 두면 코드보다 환경 문제가 더 자주 드러납니다. 갑자기 재부팅되거나, 느려지거나, 데이터가 깨진다면 전원과 온도부터 봐야 합니다.

현재 온도를 확인합니다.

vcgencmd measure_temp

스로틀링 상태도 확인합니다. 스로틀링은 온도나 전원 문제 때문에 성능을 낮추는 동작입니다.

vcgencmd get_throttled

결과가 throttled=0x0이면 부팅 이후로 전원 부족이나 과열로 인한 스로틀링 기록이 없다는 뜻입니다. 다른 값이 나온다면 전원 부족이나 과열 가능성을 의심합니다.

디스크 여유 공간도 확인합니다.

df -h

로그, 사진, 센서 데이터가 계속 쌓이면 저장장치가 가득 찰 수 있습니다. 저장공간이 100%에 가까워지면 데이터베이스 쓰기 실패, 웹 서버 오류, 부팅 문제로 이어질 수 있습니다.

메모리 사용량은 다음처럼 봅니다.

free -h

CPU와 실행 중인 프로세스는 top 또는 htop으로 확인합니다. htop이 없다면 설치할 수 있습니다.

sudo apt install htop
htop

systemd 로그가 어느 정도 공간을 쓰는지도 가끔 확인합니다.

journalctl --disk-usage

오래된 로그를 정리해야 한다면 기간을 정해 줄일 수 있습니다.

sudo journalctl --vacuum-time=14d

이 명령은 14일보다 오래된 journal 로그를 정리합니다. 장애 원인 분석에 필요한 로그까지 지우지 않도록, 문제가 없는 시점에만 실행하세요.

24시간 운영을 안정화하는 기본 원칙은 다음과 같습니다.

  • 라즈베리 파이 모델에 맞는 정품급 전원 어댑터를 사용합니다.

  • 케이스 안에 열이 갇히면 방열판이나 팬을 사용합니다.

  • 영상, 로그, 센서 데이터처럼 자주 쓰는 파일은 용량 증가를 주기적으로 확인합니다.

  • 전원을 뽑기 전에는 가능하면 종료 명령을 실행합니다.

sudo shutdown now
  • 중요한 장비라면 microSD보다 SSD 부팅을 고려합니다.

microSD 카드는 쓰기 작업이 많을수록 수명이 줄어들 수 있습니다. 센서 값을 1초마다 저장하는 프로젝트와 5분마다 저장하는 프로젝트는 저장장치에 주는 부담이 다릅니다. 꼭 필요한 주기로만 기록하고, 오래된 데이터는 정리하는 규칙을 코드나 스크립트로 만들어 두는 것이 좋습니다.

예를 들어 30일이 지난 로그 파일을 지우려면 프로젝트 폴더에서 다음처럼 확인 후 실행할 수 있습니다.

find ~/iot-home/logs -type f -mtime +30
find ~/iot-home/logs -type f -mtime +30 -delete

주의: find ... -delete는 조건에 맞는 파일을 바로 삭제합니다. 먼저 -delete 없이 어떤 파일이 선택되는지 확인한 뒤 실행하세요.

운영 점검표 만들기

마지막으로 운영 점검표를 만들어 둡니다. 장애가 생겼을 때 무엇부터 볼지 정해져 있으면 당황하지 않습니다.

1. 전원 LED와 네트워크 연결 확인
2. SSH 접속 가능 여부 확인
3. systemctl status 서비스이름 확인
4. journalctl -u 서비스이름 -n 100 확인
5. df -h로 저장공간 확인
6. vcgencmd measure_temp와 get_throttled 확인
7. 최근 코드 수정, 업데이트, 배선 변경 여부 확인
8. 필요하면 백업에서 복구

서비스 운영의 핵심은 완벽한 코드를 한 번에 쓰는 것이 아닙니다. 프로그램이 자동으로 시작되고, 실패하면 로그를 남기고, 저장장치가 망가져도 복구할 수 있게 만드는 것입니다. 여기까지 준비하면 라즈베리 파이는 실습용 보드를 넘어, 집 안에서 계속 일하는 작은 서버가 됩니다.

책 목록

라즈베리 파이 학습: 설치부터 GPIO, 웹 서버, IoT 프로젝트까지

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기