홈서버 구축 완전 가이드 8편: 백업 전략과 모니터링
Home Server Complete Guide Part 8: Backup Strategy and Monitoring
서론: 백업은 보험이다
홈서버를 운영하다 보면 언젠가는 문제가 발생합니다. 하드디스크 고장, 실수로 인한 파일 삭제, 랜섬웨어 감염 등 데이터 손실의 위험은 항상 존재합니다. 지난 편에서 보안 설정을 마쳤다면, 이제 최악의 상황에 대비해야 할 차례입니다.
"백업은 하고 있는가?"라는 질문에 "물론이죠"라고 답하는 분들도 많지만, 실제로 복구 테스트를 해본 적이 있는 분은 드뭅니다. 백업은 단순히 파일을 복사하는 것이 아니라, 복구 가능한 상태를 유지하는 것입니다. 이번 편에서는 체계적인 백업 전략과 함께, 문제가 발생하기 전에 미리 감지할 수 있는 모니터링 시스템을 구축하는 방법을 알아보겠습니다.
1. 3-2-1 백업 규칙
1.1 3-2-1 규칙이란?
데이터 백업의 황금률로 불리는 3-2-1 규칙은 다음과 같습니다:
- 3개의 복사본: 원본 데이터 포함 최소 3개의 복사본을 유지합니다.
- 2가지 다른 매체: 최소 2가지 다른 유형의 저장 매체에 백업합니다 (예: 내장 HDD + 외장 HDD, SSD + NAS).
- 1개는 오프사이트: 최소 1개의 백업은 물리적으로 다른 장소에 보관합니다 (클라우드 또는 다른 지역의 서버).
이 규칙을 따르면 화재, 도난, 하드웨어 고장 등 대부분의 재해 상황에서도 데이터를 복구할 수 있습니다.
1.2 홈서버에 적용하기
홈서버 환경에서 3-2-1 규칙을 적용하는 실제 예시입니다:
| 복사본 | 저장 위치 | 백업 방식 | 주기 |
|---|---|---|---|
| 원본 | 서버 메인 디스크 | - | - |
| 백업 1 | 서버 내 별도 디스크 또는 NAS | rsync | 매일 |
| 백업 2 | 클라우드 (Google Drive, Backblaze 등) | rclone | 매주 |
2. rsync를 이용한 로컬 백업
2.1 rsync 기본 사용법
rsync는 Linux에서 가장 널리 사용되는 파일 동기화 도구입니다. 변경된 파일만 전송하기 때문에 효율적이고 빠릅니다.
# rsync 설치 확인 (대부분 기본 설치됨)
rsync --version
# 기본 사용법
rsync -av /source/directory/ /backup/directory/
# 주요 옵션 설명
# -a : 아카이브 모드 (권한, 소유자, 타임스탬프 등 보존)
# -v : 상세 출력
# -z : 압축 전송 (원격 백업 시 유용)
# --delete : 소스에서 삭제된 파일을 백업에서도 삭제
# --exclude : 특정 파일/디렉토리 제외
# --progress : 전송 진행 상황 표시
2.2 실용적인 rsync 예제
# 홈 디렉토리 백업 (특정 파일 제외)
rsync -av --progress \
--exclude='.cache' \
--exclude='*.tmp' \
--exclude='node_modules' \
/home/username/ /backup/home/
# Docker 볼륨 백업
rsync -av --progress \
/var/lib/docker/volumes/ /backup/docker-volumes/
# 원격 서버로 백업 (SSH 사용)
rsync -avz --progress \
-e "ssh -p 2222" \
/home/username/ user@remote-server:/backup/
# 양방향 동기화가 필요한 경우 (주의해서 사용)
rsync -av --delete /source/ /destination/
2.3 증분 백업 구현
날짜별로 증분 백업을 유지하면 특정 시점으로 복구할 수 있습니다.
# 하드링크를 이용한 증분 백업
#!/bin/bash
BACKUP_DIR="/backup/incremental"
SOURCE_DIR="/home/username"
DATE=$(date +%Y-%m-%d)
LATEST="$BACKUP_DIR/latest"
# 이전 백업이 있으면 하드링크 사용
if [ -d "$LATEST" ]; then
rsync -av --delete \
--link-dest="$LATEST" \
"$SOURCE_DIR/" "$BACKUP_DIR/$DATE/"
else
rsync -av "$SOURCE_DIR/" "$BACKUP_DIR/$DATE/"
fi
# latest 심볼릭 링크 업데이트
rm -f "$LATEST"
ln -s "$BACKUP_DIR/$DATE" "$LATEST"
# 30일 이상 된 백업 삭제
find "$BACKUP_DIR" -maxdepth 1 -type d -mtime +30 -exec rm -rf {} \;
3. 자동 백업 스크립트 (cron)
3.1 백업 스크립트 작성
체계적인 백업 스크립트를 작성해 보겠습니다.
#!/bin/bash
# /usr/local/bin/backup.sh
# 설정
BACKUP_ROOT="/backup"
LOG_FILE="/var/log/backup.log"
DATE=$(date +%Y-%m-%d_%H-%M-%S)
DISCORD_WEBHOOK="YOUR_DISCORD_WEBHOOK_URL"
# 로그 함수
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# 알림 함수
notify() {
local message="$1"
local status="$2" # success or error
if [ "$status" = "error" ]; then
color="15158332" # 빨간색
else
color="3066993" # 초록색
fi
curl -H "Content-Type: application/json" \
-d "{\"embeds\":[{\"title\":\"백업 알림\",\"description\":\"$message\",\"color\":$color}]}" \
"$DISCORD_WEBHOOK" 2>/dev/null
}
# 백업 시작
log "=== 백업 시작 ==="
# 1. Docker 컨테이너 중지 (데이터 일관성 보장)
log "Docker 컨테이너 일시 중지..."
docker-compose -f /home/username/docker-compose.yml stop
# 2. 중요 디렉토리 백업
DIRS_TO_BACKUP=(
"/home/username/data"
"/var/lib/docker/volumes"
"/etc/nginx"
"/etc/letsencrypt"
)
for dir in "${DIRS_TO_BACKUP[@]}"; do
if [ -d "$dir" ]; then
dest_dir="$BACKUP_ROOT/daily/$(basename $dir)"
log "백업 중: $dir -> $dest_dir"
rsync -av --delete "$dir/" "$dest_dir/" 2>&1 | tee -a "$LOG_FILE"
fi
done
# 3. 데이터베이스 백업
log "데이터베이스 백업..."
mkdir -p "$BACKUP_ROOT/database"
docker exec mysql-container mysqldump -u root -pPASSWORD --all-databases > "$BACKUP_ROOT/database/mysql_$DATE.sql"
# 4. Docker 컨테이너 재시작
log "Docker 컨테이너 재시작..."
docker-compose -f /home/username/docker-compose.yml start
# 5. 오래된 백업 정리
log "오래된 백업 정리..."
find "$BACKUP_ROOT/database" -name "*.sql" -mtime +7 -delete
# 백업 완료
BACKUP_SIZE=$(du -sh "$BACKUP_ROOT" | cut -f1)
log "=== 백업 완료 (총 크기: $BACKUP_SIZE) ==="
notify "백업이 성공적으로 완료되었습니다.\n총 크기: $BACKUP_SIZE" "success"
3.2 cron 설정
# 스크립트에 실행 권한 부여
sudo chmod +x /usr/local/bin/backup.sh
# crontab 편집
sudo crontab -e
# 매일 새벽 3시에 백업 실행
0 3 * * * /usr/local/bin/backup.sh
# 매주 일요일 새벽 4시에 클라우드 백업 실행
0 4 * * 0 /usr/local/bin/cloud-backup.sh
# cron 로그 확인
grep CRON /var/log/syslog
팁: cron 작업이 제대로 실행되는지 확인하려면 처음에는 짧은 간격으로 설정하고, 정상 동작을 확인한 후 원하는 주기로 변경하세요.
4. 클라우드 백업 (rclone)
4.1 rclone 설치 및 설정
rclone은 다양한 클라우드 스토리지를 명령줄에서 관리할 수 있는 도구입니다. Google Drive, Dropbox, OneDrive, AWS S3, Backblaze B2 등 수십 가지 서비스를 지원합니다.
# rclone 설치
curl https://rclone.org/install.sh | sudo bash
# 또는 apt로 설치
sudo apt install rclone
# rclone 설정 (대화형)
rclone config
4.2 Google Drive 설정 예시
# rclone config 실행 후
# n) New remote 선택
# name> gdrive
# Storage> drive (Google Drive)
# client_id> (Enter 키로 기본값 사용 또는 자체 ID 입력)
# client_secret> (Enter 키로 기본값 사용)
# scope> 1 (Full access)
# root_folder_id> (Enter 키)
# service_account_file> (Enter 키)
# Edit advanced config? n
# Use auto config? y (웹 브라우저로 인증)
# Configure as team drive? n
# 설정 확인
rclone listremotes
# 연결 테스트
rclone lsd gdrive:
4.3 rclone 백업 스크립트
#!/bin/bash
# /usr/local/bin/cloud-backup.sh
BACKUP_SOURCE="/backup/daily"
REMOTE_NAME="gdrive"
REMOTE_PATH="homeserver-backup"
LOG_FILE="/var/log/cloud-backup.log"
DATE=$(date +%Y-%m-%d)
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log "=== 클라우드 백업 시작 ==="
# 백업 디렉토리 동기화
rclone sync "$BACKUP_SOURCE" "$REMOTE_NAME:$REMOTE_PATH/$DATE" \
--progress \
--transfers 4 \
--checkers 8 \
--log-file="$LOG_FILE" \
--log-level INFO
# 오래된 클라우드 백업 삭제 (30일 이상)
log "오래된 클라우드 백업 정리..."
rclone delete "$REMOTE_NAME:$REMOTE_PATH" \
--min-age 30d \
--log-file="$LOG_FILE"
# 사용량 확인
USAGE=$(rclone about "$REMOTE_NAME:" --json | jq -r '.used // 0')
log "=== 클라우드 백업 완료 (사용량: $USAGE bytes) ==="
4.4 암호화 백업
중요한 데이터는 클라우드에 올리기 전에 암호화하는 것이 좋습니다.
# rclone crypt 설정
rclone config
# n) New remote
# name> gdrive-crypt
# Storage> crypt
# remote> gdrive:encrypted-backup
# filename_encryption> standard
# directory_name_encryption> true
# Password> (강력한 비밀번호 입력)
# Salt> (Enter로 자동 생성)
# 암호화된 백업 사용
rclone sync /backup/sensitive gdrive-crypt:
5. 시스템 모니터링 도구
5.1 htop - 프로세스 모니터
htop은 터미널에서 사용하는 대화형 프로세스 뷰어입니다.
# htop 설치
sudo apt install htop
# 실행
htop
# 주요 단축키
# F2: 설정
# F3: 검색
# F4: 필터
# F5: 트리 뷰
# F6: 정렬
# F9: 시그널 보내기 (kill)
# F10: 종료
5.2 glances - 종합 시스템 모니터
glances는 htop보다 더 많은 정보를 한눈에 보여주는 도구입니다.
# glances 설치
sudo apt install glances
# 또는 pip로 설치 (최신 버전)
pip3 install glances
# 기본 실행
glances
# 웹 서버 모드로 실행 (원격 모니터링)
glances -w -p 61208
# Docker 컨테이너 모니터링 포함
glances --enable-plugin docker
# 특정 시간마다 리포트 저장
glances --export csv --export-csv-file /var/log/glances.csv
5.3 netdata - 실시간 웹 대시보드
netdata는 아름다운 웹 인터페이스와 함께 실시간 모니터링을 제공합니다.
# netdata 설치 (공식 스크립트)
wget -O /tmp/netdata-kickstart.sh https://my-netdata.io/kickstart.sh
bash /tmp/netdata-kickstart.sh
# 서비스 상태 확인
sudo systemctl status netdata
# 웹 인터페이스 접속 (기본 포트: 19999)
# http://서버IP:19999
# 설정 파일 위치
# /etc/netdata/netdata.conf
# 알림 설정
# /etc/netdata/health_alarm_notify.conf
# netdata Discord 알림 설정
sudo nano /etc/netdata/health_alarm_notify.conf
# 다음 내용 추가/수정
SEND_DISCORD="YES"
DISCORD_WEBHOOK_URL="YOUR_DISCORD_WEBHOOK_URL"
DEFAULT_RECIPIENT_DISCORD="alerts"
6. Grafana + Prometheus 모니터링 스택
6.1 Docker Compose로 설치
전문적인 모니터링 환경을 구축하려면 Grafana와 Prometheus 조합이 표준입니다.
# docker-compose-monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
- '--storage.tsdb.retention.time=15d'
ports:
- "9090:9090"
restart: unless-stopped
grafana:
image: grafana/grafana:latest
container_name: grafana
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=your_secure_password
- GF_USERS_ALLOW_SIGN_UP=false
ports:
- "3000:3000"
restart: unless-stopped
depends_on:
- prometheus
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
ports:
- "9100:9100"
restart: unless-stopped
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
container_name: cadvisor
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
ports:
- "8080:8080"
restart: unless-stopped
volumes:
prometheus_data:
grafana_data:
6.2 Prometheus 설정
# prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: []
rule_files: []
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
- job_name: 'cadvisor'
static_configs:
- targets: ['cadvisor:8080']
# 스택 실행
docker-compose -f docker-compose-monitoring.yml up -d
# Grafana 접속: http://서버IP:3000
# 기본 계정: admin / your_secure_password
# Grafana에서 Prometheus 데이터 소스 추가
# Configuration > Data Sources > Add data source > Prometheus
# URL: http://prometheus:9090
6.3 유용한 Grafana 대시보드
Grafana 대시보드는 직접 만들 수도 있지만, 커뮤니티에서 공유하는 대시보드를 가져와 사용할 수 있습니다.
- Node Exporter Full (ID: 1860): 시스템 전체 모니터링
- Docker Container Monitoring (ID: 193): Docker 컨테이너 모니터링
- Nginx (ID: 9614): Nginx 웹 서버 모니터링
# 대시보드 가져오기
# Grafana > Dashboards > Import
# Dashboard ID 입력 후 Load
# Prometheus 데이터 소스 선택 후 Import
7. 알림 설정
7.1 Discord 웹훅 알림
#!/bin/bash
# /usr/local/bin/discord-notify.sh
WEBHOOK_URL="YOUR_DISCORD_WEBHOOK_URL"
send_notification() {
local title="$1"
local message="$2"
local color="${3:-3447003}" # 기본 파란색
curl -H "Content-Type: application/json" \
-d "{
\"embeds\": [{
\"title\": \"$title\",
\"description\": \"$message\",
\"color\": $color,
\"timestamp\": \"$(date -u +%Y-%m-%dT%H:%M:%SZ)\"
}]
}" \
"$WEBHOOK_URL"
}
# 사용 예시
# send_notification "서버 알림" "백업이 완료되었습니다." "3066993" # 초록색
# send_notification "경고" "디스크 사용량 90% 초과" "15158332" # 빨간색
7.2 Telegram 봇 알림
#!/bin/bash
# /usr/local/bin/telegram-notify.sh
BOT_TOKEN="YOUR_BOT_TOKEN"
CHAT_ID="YOUR_CHAT_ID"
send_telegram() {
local message="$1"
curl -s -X POST "https://api.telegram.org/bot$BOT_TOKEN/sendMessage" \
-d chat_id="$CHAT_ID" \
-d text="$message" \
-d parse_mode="HTML"
}
# 사용 예시
# send_telegram "서버 알림
# 백업이 완료되었습니다.
# 시간: $(date)"
7.3 시스템 상태 알림 스크립트
#!/bin/bash
# /usr/local/bin/system-check.sh
source /usr/local/bin/discord-notify.sh
# 디스크 사용량 체크
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$DISK_USAGE" -gt 85 ]; then
send_notification "디스크 경고" "루트 파티션 사용량: ${DISK_USAGE}%" "15158332"
fi
# 메모리 사용량 체크
MEM_USAGE=$(free | awk '/Mem:/ {printf "%.0f", $3/$2 * 100}')
if [ "$MEM_USAGE" -gt 90 ]; then
send_notification "메모리 경고" "메모리 사용량: ${MEM_USAGE}%" "15158332"
fi
# 서비스 상태 체크
SERVICES=("docker" "nginx" "ssh")
for service in "${SERVICES[@]}"; do
if ! systemctl is-active --quiet "$service"; then
send_notification "서비스 다운" "$service 서비스가 중지되었습니다!" "15158332"
fi
done
# 부하 체크
LOAD=$(uptime | awk -F'load average:' '{print $2}' | awk -F',' '{print $1}' | tr -d ' ')
CPU_CORES=$(nproc)
LOAD_INT=${LOAD%.*}
if [ "$LOAD_INT" -gt "$CPU_CORES" ]; then
send_notification "부하 경고" "시스템 부하: $LOAD (CPU 코어: $CPU_CORES)" "15105570"
fi
# cron에 등록 (5분마다 체크)
sudo crontab -e
*/5 * * * * /usr/local/bin/system-check.sh
8. 장애 대응과 복구 절차
8.1 장애 대응 체크리스트
서버 장애 발생 시 당황하지 않도록 미리 체크리스트를 준비해 두세요.
- 문제 확인: 어떤 서비스가 영향을 받는가?
- 로그 확인: journalctl, /var/log/ 확인
- 리소스 확인: CPU, 메모리, 디스크 공간
- 네트워크 확인: 연결 상태, 방화벽 규칙
- 최근 변경 사항: 업데이트, 설정 변경 여부
- 서비스 재시작: 해당 서비스 또는 서버 재시작
- 롤백: 필요시 이전 상태로 복구
8.2 백업에서 복구하기
# rsync 백업에서 복구
sudo rsync -av --progress /backup/daily/data/ /home/username/data/
# 데이터베이스 복구
docker exec -i mysql-container mysql -u root -pPASSWORD < /backup/database/mysql_2026-01-22.sql
# 클라우드 백업에서 복구
rclone copy gdrive:homeserver-backup/2026-01-22 /restore/ --progress
# Docker 볼륨 복구
sudo systemctl stop docker
sudo rsync -av /backup/docker-volumes/ /var/lib/docker/volumes/
sudo systemctl start docker
8.3 복구 테스트의 중요성
백업만 하고 복구 테스트를 안 하면 실제 상황에서 당황할 수 있습니다. 정기적으로 복구 테스트를 진행하세요.
# 복구 테스트 스크립트 예시
#!/bin/bash
# /usr/local/bin/recovery-test.sh
TEST_DIR="/tmp/recovery-test-$(date +%Y%m%d)"
mkdir -p "$TEST_DIR"
echo "=== 백업 복구 테스트 시작 ==="
# 1. 로컬 백업 테스트
echo "로컬 백업에서 샘플 파일 복구 중..."
rsync -av /backup/daily/data/sample-file.txt "$TEST_DIR/"
if [ -f "$TEST_DIR/sample-file.txt" ]; then
echo "로컬 백업 복구 성공"
else
echo "로컬 백업 복구 실패!"
fi
# 2. 클라우드 백업 테스트
echo "클라우드 백업에서 샘플 파일 복구 중..."
rclone copy gdrive:homeserver-backup/latest/sample-file.txt "$TEST_DIR/cloud/"
if [ -f "$TEST_DIR/cloud/sample-file.txt" ]; then
echo "클라우드 백업 복구 성공"
else
echo "클라우드 백업 복구 실패!"
fi
# 정리
rm -rf "$TEST_DIR"
echo "=== 복구 테스트 완료 ==="
마치며
백업과 모니터링은 평소에는 눈에 띄지 않지만, 문제가 발생했을 때 그 가치를 발휘합니다. 귀찮더라도 3-2-1 규칙에 따라 백업 체계를 구축하고, 모니터링 시스템으로 서버 상태를 항상 파악할 수 있도록 해두세요.
특히 중요한 것은 "복구 가능한" 백업을 유지하는 것입니다. 백업 파일이 있어도 복구할 수 없다면 의미가 없습니다. 정기적으로 복구 테스트를 진행하고, 복구 절차를 문서화해 두는 것이 좋습니다.
이것으로 홈서버 구축 완전 가이드 시리즈를 마무리합니다. 하드웨어 선택부터 OS 설치, 네트워크 설정, Docker, 보안, 그리고 백업과 모니터링까지 홈서버 운영에 필요한 핵심 내용을 다루었습니다. 이 가이드가 여러분의 홈서버 여정에 도움이 되길 바랍니다.
추가적인 질문이나 궁금한 점이 있다면 댓글로 남겨주세요!