强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Minecraft PaperMC 服务器部署指南 / 09 - 备份与恢复

09 - 备份与恢复

9.1 备份策略

9.1.1 为什么备份如此重要

风险场景 后果 备份能否解决
世界文件损坏 玩家建筑丢失
恶意破坏(Grief) 区域被毁
误操作删除 数据丢失
插件数据损坏 配置丢失
服务器硬件故障 全部数据丢失 ✅(异地备份)
勒索软件攻击 数据被加密 ✅(离线备份)

9.1.2 备份策略 3-2-1 原则

3 份副本:数据本身 + 2 份备份
2 种介质:本地 + 异地(或不同存储设备)
1 份离线:至少 1 份离线备份(防勒索软件)

9.1.3 备份频率建议

服务器类型 建议频率 保留时间 备份类型
小型私人服 每天 1 次 7 天 全量
中型社区服 每 6 小时 14 天 增量 + 全量
大型公共服 每 2 小时 30 天 增量 + 全量
生产/商业服 每小时 90 天 增量 + 全量 + 异地

9.2 全量备份

9.2.1 简单备份脚本

#!/bin/bash
# simple-backup.sh - 简单全量备份脚本

# ============ 配置 ============
SERVER_DIR="/opt/minecraft/paper"
BACKUP_DIR="/opt/minecraft/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="mc_backup_${TIMESTAMP}"
SCREEN_NAME="minecraft"
KEEP_COUNT=10                        # 保留最近 N 个备份

# ============ 初始化 ============
mkdir -p "$BACKUP_DIR"
echo "[$(date)] === 开始备份 ==="

# ============ 通知服务器 ============
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "say §e[备份] 正在创建备份,请稍候...\015"'
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "save-off\015"'
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "save-all\015"'
sleep 5

# ============ 执行备份 ============
echo "[$(date)] 正在备份世界文件..."
tar -czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" \
  -C "$SERVER_DIR" \
  --exclude='cache' \
  --exclude='libraries' \
  --exclude='logs/latest.log' \
  world world_nether world_the_end \
  plugins config \
  server.properties \
  bukkit.yml spigot.yml \
  banned-players.json banned-ips.json \
  ops.json whitelist.json \
  2>/dev/null

# ============ 恢复自动保存 ============
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "save-on\015"'

# ============ 检查备份结果 ============
if [ -f "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" ]; then
    SIZE=$(du -h "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" | cut -f1)
    echo "[$(date)] 备份成功: ${BACKUP_NAME}.tar.gz (${SIZE})"
    screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "say §a[备份] 备份完成!\015"'
else
    echo "[$(date)] 备份失败!"
    screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "say §c[备份] 备份失败!\015"'
    exit 1
fi

# ============ 清理旧备份 ============
echo "[$(date)] 清理旧备份(保留最近 ${KEEP_COUNT} 个)..."
ls -t ${BACKUP_DIR}/mc_backup_*.tar.gz 2>/dev/null | tail -n +$((KEEP_COUNT + 1)) | while read f; do
    echo "[$(date)] 删除旧备份: $(basename $f)"
    rm -f "$f"
done

echo "[$(date)] === 备份完成 ==="

9.2.2 完整服务器备份

#!/bin/bash
# full-backup.sh - 完整服务器备份(包含 JAR 和所有配置)

SERVER_DIR="/opt/minecraft/paper"
BACKUP_DIR="/opt/minecraft/backups/full"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

# 备份整个服务器目录(排除缓存和日志)
tar -czf "${BACKUP_DIR}/full_${TIMESTAMP}.tar.gz" \
  -C "$(dirname $SERVER_DIR)" \
  --exclude='*.cache' \
  --exclude='logs/*.log' \
  --exclude='cache' \
  --exclude='libraries' \
  "$(basename $SERVER_DIR)"

echo "完整备份完成: full_${TIMESTAMP}.tar.gz"
ls -lh "${BACKUP_DIR}/full_${TIMESTAMP}.tar.gz"

9.3 增量备份

增量备份仅备份自上次备份后变更的文件,节省空间和时间。

9.3.1 使用 rsync 增量备份

#!/bin/bash
# incremental-backup.sh - 使用 rsync 增量备份

SERVER_DIR="/opt/minecraft/paper"
BACKUP_DIR="/opt/minecraft/backups/incremental"
LATEST_LINK="${BACKUP_DIR}/latest"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p "$BACKUP_DIR"

# rsync 增量备份(硬链接未变更文件)
rsync -a --delete \
  --link-dest="$LATEST_LINK" \
  --exclude='cache' \
  --exclude='libraries' \
  --exclude='logs/latest.log' \
  "$SERVER_DIR/" \
  "${BACKUP_DIR}/${TIMESTAMP}/"

# 更新 latest 链接
rm -f "$LATEST_LINK"
ln -s "${BACKUP_DIR}/${TIMESTAMP}" "$LATEST_LINK"

echo "增量备份完成: ${TIMESTAMP}"
echo "备份大小: $(du -sh ${BACKUP_DIR}/${TIMESTAMP} | cut -f1)"

9.3.2 使用 restic 增量备份

# 安装 restic
sudo apt install restic    # Debian/Ubuntu
sudo dnf install restic    # Fedora

# 初始化备份仓库
restic init --repo /opt/minecraft/backups/restic

# 执行增量备份
restic backup /opt/minecraft/paper \
  --repo /opt/minecraft/backups/restic \
  --exclude cache \
  --exclude libraries \
  --tag minecraft

# 查看备份列表
restic snapshots --repo /opt/minecraft/backups/restic

# 恢复到指定时间点
restic restore latest \
  --repo /opt/minecraft/backups/restic \
  --target /opt/minecraft/paper-restored

# 设置保留策略
restic forget \
  --repo /opt/minecraft/backups/restic \
  --keep-daily 7 \
  --keep-weekly 4 \
  --keep-monthly 6 \
  --prune

9.4 WorldEdit 区域还原

对于局部破坏(如熊孩子破坏),WorldEdit 的还原比全量备份恢复更精准。

9.4.1 WorldEdit 备份与还原

# 1. 选中要保护的区域
//pos1                  # 选择第一个角
//pos2                  # 选择第二个角

# 2. 创建快照(保存到文件)
//save my_backup        # 保存为 my_backup.schematic

# 3. 还原区域
//load my_backup        # 加载快照
//paste                 # 粘贴到当前位置

# 4. 还原并匹配空气
//paste -a              # 粘贴(包含空气方块)

9.4.2 CoreProtect 区域回滚

CoreProtect 是回滚玩家操作的首选工具:

# 查看 50 格范围内最近 24 小时的操作
/co lookup u:Griefer t:24h r:50

# 回滚特定玩家的操作
/co rollback u:Griefer t:24h r:50

# 回滚方块破坏
/co rollback u:Griefer t:24h r:50 a:break

# 回滚方块放置
/co rollback u:Griefer t:24h r:50 a:place

# 回滚容器操作(拿取物品)
/co rollback u:Griefer t:24h r:50 a:container

# 恢复回滚(如果回滚错误)
/co restore u:Griefer t:24h r:50

# 查看回滚结果
/co lookup u:Griefer t:24h r:50 a:+break,-place

9.4.3 CoreProtect 操作查询

# 检查特定方块
/co inspect                  # 开启检查模式
# 然后点击方块查看操作历史

# 查看谁破坏了某个方块
/co lookup t:7d r:5 a:break

# 查看最近的 TNT 爆炸
/co lookup a:explode t:1h r:100

# 查看容器被谁打开过
/co lookup a:container t:24h r:20

9.5 云备份方案

9.5.1 使用 rclone 上传到云存储

# 安装 rclone
curl https://rclone.org/install.sh | sudo bash

# 配置云存储(以 Google Drive 为例)
rclone config
# 按提示选择 Google Drive 并完成授权

# 上传备份
rclone copy /opt/minecraft/backups/mc_backup_latest.tar.gz \
  remote:minecraft-backups/ \
  --progress

# 自动同步
rclone sync /opt/minecraft/backups/ \
  remote:minecraft-backups/ \
  --include "*.tar.gz" \
  --progress

9.5.2 支持的云存储

服务 配置命令 特点
Google Drive rclone config 15GB 免费
OneDrive rclone config 5GB 免费
Dropbox rclone config 2GB 免费
S3 (AWS) rclone config 按量付费
阿里云 OSS rclone config 国内首选
腾讯云 COS rclone config 国内备选
坚果云 rclone config WebDAV 协议

9.5.3 使用 Duplicity 加密备份

# 安装
sudo apt install duplicity

# 加密备份到云存储
duplicity /opt/minecraft/paper/world \
  s3://s3.amazonaws.com/my-bucket/minecraft-backup \
  --encrypt-key YOUR_GPG_KEY \
  --full-if-older-than 7D

# 恢复
duplicity restore \
  s3://s3.amazonaws.com/my-bucket/minecraft-backup \
  /opt/minecraft/paper/world-restored

9.6 自动备份定时任务

9.6.1 Crontab 配置

# 编辑 crontab
crontab -e

# 每 6 小时全量备份
0 */6 * * * /opt/minecraft/scripts/backup.sh >> /var/log/mc-backup.log 2>&1

# 每天凌晨 2 点做完整备份
0 2 * * * /opt/minecraft/scripts/full-backup.sh >> /var/log/mc-backup.log 2>&1

# 每周日凌晨 3 点上传到云存储
0 3 * * 0 /opt/minecraft/scripts/cloud-upload.sh >> /var/log/mc-backup.log 2>&1

# 每月 1 日清理旧云备份
0 4 1 * * rclone delete remote:minecraft-backups/ --min-age 90d

9.6.2 Systemd Timer(替代 Crontab)

# /etc/systemd/system/mc-backup.timer

[Unit]
Description=Minecraft Backup Timer

[Timer]
OnCalendar=*-*-* */6:00:00
Persistent=true

[Install]
WantedBy=timers.target
# /etc/systemd/system/mc-backup.service

[Unit]
Description=Minecraft Backup Service

[Service]
Type=oneshot
ExecStart=/opt/minecraft/scripts/backup.sh
User=minecraft
sudo systemctl daemon-reload
sudo systemctl enable mc-backup.timer
sudo systemctl start mc-backup.timer

# 查看定时器状态
sudo systemctl list-timers mc-backup.timer

9.7 备份验证

9.7.1 自动验证脚本

#!/bin/bash
# verify-backup.sh - 验证备份完整性

BACKUP_FILE="$1"
VERIFY_DIR="/tmp/mc-backup-verify"

if [ -z "$BACKUP_FILE" ]; then
    echo "用法: $0 <备份文件路径>"
    exit 1
fi

echo "=== 备份验证 ==="
echo "文件: $BACKUP_FILE"

# 1. 检查文件是否存在
if [ ! -f "$BACKUP_FILE" ]; then
    echo "错误: 备份文件不存在"
    exit 1
fi

# 2. 检查文件大小
SIZE=$(stat -c%s "$BACKUP_FILE")
if [ "$SIZE" -lt 1024 ]; then
    echo "错误: 备份文件过小 (${SIZE} bytes)"
    exit 1
fi
echo "文件大小: $(du -h "$BACKUP_FILE" | cut -f1)"

# 3. 验证压缩完整性
if [[ "$BACKUP_FILE" == *.tar.gz ]]; then
    if gzip -t "$BACKUP_FILE" 2>/dev/null; then
        echo "压缩完整性: 通过"
    else
        echo "错误: 压缩文件损坏"
        exit 1
    fi
fi

# 4. 检查关键文件是否存在
rm -rf "$VERIFY_DIR"
mkdir -p "$VERIFY_DIR"
tar -xzf "$BACKUP_FILE" -C "$VERIFY_DIR" 2>/dev/null

MISSING=0
for f in world/level.dat plugins; do
    if [ ! -e "${VERIFY_DIR}/$f" ]; then
        echo "警告: 缺少 $f"
        MISSING=$((MISSING + 1))
    fi
done

if [ "$MISSING" -eq 0 ]; then
    echo "关键文件: 全部存在"
else
    echo "警告: 缺少 ${MISSING} 个关键文件"
fi

# 5. 清理
rm -rf "$VERIFY_DIR"

echo "=== 验证完成 ==="

9.8 备份管理最佳实践

9.8.1 备份存储策略

时间段 保留策略 存储位置
最近 24 小时 每 6 小时保留 本地 SSD
最近 7 天 每天保留 本地 HDD
最近 30 天 每周保留 NAS/云存储
30 天以上 每月保留 冷存储/归档

9.8.2 备份清单文档

## 备份清单

| 备份类型 | 频率 | 保留时间 | 存储位置 | 负责人 |
|----------|------|----------|----------|--------|
| 世界增量 | 每 6h | 7 天 | 本地 | 自动脚本 |
| 全量备份 | 每天 | 30 天 | NAS | 自动脚本 |
| 异地备份 | 每周 | 90 天 | 云存储 | 手动触发 |
| 配置备份 | 每次变更 | 永久 | Git | 开发者 |

## 恢复测试

- [ ] 每月执行一次恢复测试
- [ ] 验证恢复后服务器可正常启动
- [ ] 验证玩家数据完整性

9.9 灾难恢复流程

9.9.1 完整恢复步骤

# 1. 停止服务器
sudo systemctl stop minecraft

# 2. 备份当前损坏的数据(以防万一)
mv /opt/minecraft/paper /opt/minecraft/paper_damaged_$(date +%s)

# 3. 从备份恢复
BACKUP_FILE="/opt/minecraft/backups/full/full_20260510.tar.gz"
mkdir -p /opt/minecraft/paper
tar -xzf "$BACKUP_FILE" -C /opt/minecraft/

# 4. 确认权限
chown -R minecraft:minecraft /opt/minecraft/paper

# 5. 启动服务器测试
sudo systemctl start minecraft

# 6. 检查日志
sudo journalctl -u minecraft -f

# 7. 验证服务器状态
# 在游戏内连接并检查世界是否正常

9.9.2 部分恢复(仅恢复世界)

# 1. 停止服务器
sudo systemctl stop minecraft

# 2. 备份当前世界
mv /opt/minecraft/paper/world /opt/minecraft/paper/world_broken

# 3. 从备份中仅提取世界
tar -xzf /opt/minecraft/backups/latest.tar.gz -C /opt/minecraft/paper/ world/

# 4. 启动服务器
sudo systemctl start minecraft

9.10 常见问题

Q1:备份时服务器卡顿?

# 使用 nice 降低备份进程优先级
nice -n 19 /opt/minecraft/scripts/backup.sh

# 使用 ionice 降低 IO 优先级
ionice -c 3 /opt/minecraft/scripts/backup.sh

# 使用 pigz 多线程压缩
tar -cf - world | pigz -p 4 > backup.tar.gz

Q2:备份文件太大?

# 使用 zstd 压缩(比 gzip 更快更小)
tar --zstd -cf backup.tar.zst world/

# 修剪世界中未使用的区块(详见第 04 章)
java -jar mcaselector.jar --mode delete --world world --radius 10000 --center 0,0

# 排除不必要的文件
tar -czf backup.tar.gz --exclude='world/region/r.10.*' world/

Q3:如何恢复被删除的玩家数据?

# 从 CoreProtect 恢复(如果有记录)
/co restore u:<玩家名> t:7d

# 从备份中提取玩家数据
tar -xzf backup.tar.gz world/playerdata/<uuid>.dat

# 从 LuckPerms 恢复权限
/lp user <玩家名> import

9.11 本章小结

要点 说明
遵循 3-2-1 原则 3 份副本、2 种介质、1 份离线
定期自动备份 Crontab 或 Systemd Timer
增量备份节省空间 rsync 或 restic
定期验证备份 确保备份可恢复
CoreProtect 用于局部回滚 比全量恢复更精准
云备份防灾难 异地存储是最后防线

扩展阅读