前言:备份就是保险

运营家庭服务器总会遇到问题。硬盘故障、误删文件、勒索软件感染等数据丢失的风险始终存在。如果你在上一篇完成了安全设置,现在是时候为最坏的情况做准备了。

被问到"你做备份了吗?"时,很多人会回答"当然了",但实际做过恢复测试的人很少。备份不仅仅是复制文件,而是保持可恢复的状态。本篇将介绍系统的备份策略,以及如何搭建在问题发生前就能提前感知的监控系统。

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示例

# 备份home目录(排除特定文件)
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> (回车使用默认值或输入自己的ID)
# client_secret> (回车使用默认值)
# scope> 1 (Full access)
# root_folder_id> (回车)
# service_account_file> (回车)
# Edit advanced config? n
# Use auto config? y (通过Web浏览器认证)
# 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> (回车自动生成)

# 使用加密备份
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

# Web服务器模式运行(远程监控)
glances -w -p 61208

# 包含Docker容器监控
glances --enable-plugin docker

# 定期保存报告
glances --export csv --export-csv-file /var/log/glances.csv

5.3 netdata - 实时Web仪表板

netdata提供漂亮的Web界面和实时监控。

# 安装netdata(官方脚本)
wget -O /tmp/netdata-kickstart.sh https://my-netdata.io/kickstart.sh
bash /tmp/netdata-kickstart.sh

# 检查服务状态
sudo systemctl status netdata

# 访问Web界面(默认端口: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 Web服务器监控
# 导入仪表板
# Grafana > Dashboards > Import
# 输入Dashboard ID后Load
# 选择Prometheus数据源后Import

7. 告警设置

7.1 Discord Webhook告警

#!/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 故障响应检查清单

服务器故障发生时,请提前准备好检查清单以免慌张。

  1. 确认问题:哪些服务受到影响?
  2. 检查日志:查看journalctl、/var/log/
  3. 检查资源:CPU、内存、磁盘空间
  4. 检查网络:连接状态、防火墙规则
  5. 最近更改:是否有更新、配置更改
  6. 重启服务:重启相关服务或服务器
  7. 回滚:必要时恢复到之前的状态

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规则建立备份体系,通过监控系统随时掌握服务器状态。

特别重要的是保持"可恢复"的备份。即使有备份文件,如果无法恢复也没有意义。定期进行恢复测试,并记录恢复流程是最好的做法。

家庭服务器搭建完全指南系列到此结束。从硬件选择到操作系统安装、网络设置、Docker、安全,以及备份和监控,我们涵盖了家庭服务器运营所需的核心内容。希望本指南对您的家庭服务器之旅有所帮助。

如有其他问题或疑问,请在评论中留言!