Linux 강좌 / 서버 백업과 상태 점검 자동화 구성하기

서버 운영에서는 복구할 수 있는 백업과 장애를 알아차릴 상태 점검이 모두 필요합니다. 백업 파일 생성, 파일 무결성, 실제 복원, HTTP 응답과 디스크 여유를 따로 검증하고 서버 밖에서 실패·미실행을 감지할 경로를 마련하세요.

이 글은 수동 백업·복원 검증을 통과한 절차를 예약 실행과 연결합니다. 백업 생성, 별도 복원 검사, 실패 알림을 각각 확인해야 예약 작업이 성공했다고 판단할 수 있습니다.

시스템 설정 실습의 기준은 Ubuntu 26.04 LTS와 Rocky Linux 9 계열의 일반 설치 VM입니다. 컨테이너·WSL·다른 릴리스에서는 서비스와 패키지 구성이 다를 수 있습니다. 가상 머신 실습 환경 만들기에서 콘솔 복구와 버전 확인을 먼저 준비하세요.

이 실습이 보호하는 데이터와 한계

대상은 33강의 정적 콘텐츠처럼 실행 중 변경이 제한된 일반 파일입니다. 서비스 설정·인증서·DNS·배포 절차는 별도로 백업·문서화하고, 데이터베이스는 해당 제품의 일관된 백업 방식을 사용합니다. 아래 로컬 백업은 실행 구조를 배우는 단계이며 서버 디스크 고장이나 계정 침해를 견디는 최종 보관소가 아닙니다.

일반 사용자 권한으로 읽을 수 있는 원본과 본인만 쓸 수 있는 백업 디렉터리를 선택합니다. root가 필요한 파일을 편하게 읽으려고 스크립트 전체를 무조건 root로 예약하지 마세요. 운영 백업은 전용 계정과 허용된 경로·암호화 키 관리·보존 기간을 별도로 정합니다.

인수로 경로를 받는 백업 스크립트 만들기

mkdir -p "$HOME/bin"
cat > "$HOME/bin/course-backup.sh" <<'EOF'
#!/usr/bin/env bash
set -u
set -o pipefail
umask 077
if (( $# != 2 )); then
  printf "Usage: %s SOURCE_DIRECTORY BACKUP_DIRECTORY\n" "$0" >&2
  exit 2
fi
source_dir=$(realpath -e -- "$1") || exit 1
backup_dir=$(realpath -e -- "$2") || exit 1
[[ -d "$source_dir" && -d "$backup_dir" ]] || exit 1
case "$backup_dir/" in
  "$source_dir/"*) printf "Backup must be outside source\n" >&2; exit 1 ;;
esac
work=$(mktemp -d "$backup_dir/backup.XXXXXXXX") || exit 1
if ! tar -czf "$work/data.tar.gz" -C "$source_dir" .; then
  printf "Archive failed: %s\n" "$work" >&2; exit 1
fi
if ! tar -tzf "$work/data.tar.gz" > /dev/null; then
  printf "Archive listing failed\n" >&2; exit 1
fi
if ! (cd "$work" && sha256sum data.tar.gz > data.tar.gz.sha256); then
  printf "Checksum creation failed\n" >&2; exit 1
fi
if ! date --iso-8601=seconds > "$work/created-at.txt"; then exit 1; fi
printf "complete\n" > "$work/COMPLETE" || exit 1
printf "Backup ready: %s\n" "$work"
EOF
bash -n "$HOME/bin/course-backup.sh"

스크립트는 실행마다 고유한 디렉터리를 만들어 이름 충돌을 피합니다. 마지막 COMPLETE 표시가 있는 자료만 완료된 백업으로 판단합니다. 실패한 디렉터리가 남으면 원인을 확인하고 복구 시점 목록에 포함하지 않습니다. 생성 시각은 기록하지만 오래된 백업을 자동 삭제하지는 않습니다.

실행·무결성·복원을 각각 시험하기

lab=$(mktemp -d "$HOME/linux-ops-lab.XXXXXX")
mkdir "$lab/site" "$lab/backups" "$lab/restored"
printf "site version 1\n" > "$lab/site/index.html"
bash "$HOME/bin/course-backup.sh" "$lab/site" "$lab/backups"
find "$lab/backups" -maxdepth 2 -type f -print

출력된 Backup ready: 경로를 실제 변수에 넣어 아래처럼 확인합니다. ACTUAL_BACKUP_DIRECTORY는 이번 실행이 출력한 디렉터리로 바꿉니다. 체크섬 검증과 tar 목록 성공은 복원 가능한 애플리케이션을 보장하지 않으므로 내용을 비교하고 실제 웹 서비스 사용도 별도로 시험해야 합니다.

backup=ACTUAL_BACKUP_DIRECTORY
test -f "$backup/COMPLETE"
(cd "$backup" && sha256sum -c data.tar.gz.sha256)
tar -xzf "$backup/data.tar.gz" -C "$lab/restored"
diff -r "$lab/site" "$lab/restored"

정상 결과는 COMPLETE 존재, 체크섬 OK, diff 차이 없음입니다. 복원은 빈 디렉터리에서 수행하고 권한·소유자·필요한 레이블도 확인합니다. 원격 보관소로 옮긴 뒤에도 체크섬과 복원 시험을 반복하세요. 공간이 부족할 때 임의로 오래된 사본을 모두 삭제하지 말고 필요한 복구 시점을 보존하는 정책을 적용합니다.

HTTP 응답과 여유 공간 점검 스크립트

curl·df·awk가 필요합니다. URL과 최소 여유 KiB를 인수로 받으며 HTTP 200~299를 정상으로 간주합니다. 서비스가 리디렉션을 의도하거나 로그인 페이지를 반환한다면 판단 기준을 맞춰야 합니다. 이 예제는 응답 본문의 정확성, 데이터베이스 상태나 모든 기능을 검사하지는 않습니다.

cat > "$HOME/bin/course-health.sh" <<'EOF'
#!/usr/bin/env bash
set -u
set -o pipefail
if (( $# != 3 )); then
  printf "Usage: %s URL MIN_FREE_KIB STORAGE_PATH\n" "$0" >&2; exit 2
fi
url=$1
minimum=$2
path=$3
[[ "$minimum" =~ ^[0-9]+$ ]] || exit 2
if ! status=$(curl -sS -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 15 "$url"); then
  printf "HTTP transport failed\n" >&2; exit 1
fi
[[ "$status" =~ ^2[0-9][0-9]$ ]] || { printf "HTTP status=%s\n" "$status" >&2; exit 1; }
available=$(df -Pk -- "$path" | awk 'NR==2 {print $4}') || exit 1
[[ "$available" =~ ^[0-9]+$ ]] || exit 1
(( 10#$available >= 10#$minimum )) || { printf "Low storage: %s KiB\n" "$available" >&2; exit 1; }
printf "OK http=%s free_kib=%s\n" "$status" "$available"
EOF
bash -n "$HOME/bin/course-health.sh"
bash "$HOME/bin/course-health.sh" http://127.0.0.1/ 102400 "$HOME"

최소 102400 KiB는 약 100 MiB인 실습 임계값이며 운영 권장값이 아닙니다. 증가 속도·복구 작업 공간을 반영해 정하고 아이노드는 별도로 확인하세요. 이름 기반 Nginx 사이트는 실제 도메인 URL 또는 적절한 Host 설정으로 점검해야 하며 기본 사이트의 200을 목표 사이트의 성공으로 오인하지 않습니다.

타이머 연결과 외부 실패 감지

29강의 사용자 service·timer 구조를 재사용하되 ExecStart를 /bin/bash %h/bin/course-backup.sh 실제원본 실제백업경로로 지정합니다. 경로에 공백이 있다면 systemd 명령줄 문법에 맞게 각 인수를 인용하며, 먼저 같은 명령을 수동 실행합니다. 일정은 백업 변경량·복구 목표에 맞게 정하고 상태 점검은 별도 유닛으로 분리합니다.

타이머의 다음 실행과 서비스 종료 상태, 마지막 COMPLETE 생성 시각을 따로 확인합니다. 같은 서버 안의 점검은 서버 전체가 멈추면 함께 멈추므로 서버 밖의 모니터가 실제 URL과 마지막 백업 시각을 확인해야 합니다. 메일·메신저 알림은 수신 경로와 실패 시점도 시험하고, 경보가 발생했을 때 누가 무엇을 복구할지 정합니다.

실패 실험과 정리

없는 원본 경로로 백업이 실패하는지, 존재하지 않는 HTTP 경로에서 점검이 실패하는지, 지나치게 큰 여유 공간 임계값에서 실패하는지 한 조건씩 확인하고 원래 값을 복구합니다. 완료 표시 없는 백업을 성공으로 보고하지 않는지도 확인하세요. 실습 타이머를 먼저 중지·해제한 뒤 스크립트와 새 작업 폴더만 정리합니다.

공식 문서