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

Nextcloud 私有云部署教程 / 12 - 备份恢复

12 - 备份恢复

建立完善的备份恢复体系:自动备份、增量备份、快照管理与灾难恢复方案。


12.1 备份策略概述

需要备份的内容

组件路径重要性说明
数据目录data/ 或自定义路径🔴 关键用户所有文件
配置文件config/config.php🔴 关键含密钥、数据库凭据
数据库MySQL/PostgreSQL🔴 关键文件索引、分享、用户信息
应用目录apps/🟡 重要自安装的应用
主题目录themes/🟡 重要自定义主题
SSL 证书/etc/letsencrypt/🟢 可选可重新申请

备份策略对比

策略优点缺点适用场景
全量备份恢复简单占用空间大,耗时长小规模部署
增量备份节省空间,速度快恢复较复杂中大型部署
快照备份一致性好,恢复快依赖存储系统虚拟化/容器环境
异地备份灾难恢复网络带宽需求生产环境必选

12.2 全量备份

完整备份脚本

#!/bin/bash
# nextcloud-backup.sh - Nextcloud 全量备份脚本

set -euo pipefail

# ======== 配置 ========
BACKUP_ROOT="/backup/nextcloud"
NC_ROOT="/var/www/nextcloud"
NC_DATA="/data/nextcloud-data"
DB_TYPE="mysql"
DB_NAME="nextcloud"
DB_USER="ncuser"
DB_PASS="StrongPassword123!"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="$BACKUP_ROOT/$DATE"
RETENTION_DAYS=30

# ======== 函数 ========
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
}

cleanup() {
    if [ $? -ne 0 ]; then
        log "ERROR: Backup failed!"
        rm -rf "$BACKUP_DIR"
    fi
}

trap cleanup EXIT

# ======== 开始备份 ========
log "Starting Nextcloud backup..."

# 创建备份目录
mkdir -p "$BACKUP_DIR"/{config,data,database,apps,themes}

# 1. 开启维护模式
log "Enabling maintenance mode..."
sudo -u www-data php "$NC_ROOT/occ" maintenance:mode --on

# 2. 备份配置文件
log "Backing up configuration..."
cp -a "$NC_ROOT/config/" "$BACKUP_DIR/config/"

# 3. 备份数据库
log "Backing up database..."
case "$DB_TYPE" in
    mysql)
        mysqldump \
            --single-transaction \
            --routines \
            --triggers \
            --quick \
            --lock-tables=false \
            -u "$DB_USER" \
            -p"$DB_PASS" \
            "$DB_NAME" | gzip > "$BACKUP_DIR/database/nextcloud.sql.gz"
        ;;
    pgsql)
        PGPASSWORD="$DB_PASS" pg_dump \
            -U "$DB_USER" \
            -Fc \
            "$DB_NAME" > "$BACKUP_DIR/database/nextcloud.dump"
        ;;
esac

# 4. 备份数据目录(使用 rsync 增量同步)
log "Backing up data directory..."
rsync -a --delete \
    "$NC_DATA/" "$BACKUP_DIR/data/" \
    --exclude='*.part' \
    --exclude='.cache'

# 5. 备份应用和主题
log "Backing up apps and themes..."
rsync -a "$NC_ROOT/apps/" "$BACKUP_DIR/apps/"
rsync -a "$NC_ROOT/themes/" "$BACKUP_DIR/themes/"

# 6. 关闭维护模式
log "Disabling maintenance mode..."
sudo -u www-data php "$NC_ROOT/occ" maintenance:mode --off

# 7. 创建备份清单
cat > "$BACKUP_DIR/manifest.txt" << EOF
Backup Date: $DATE
Nextcloud Version: $(sudo -u www-data php "$NC_ROOT/occ" status --output=json | jq -r '.version')
Database Type: $DB_TYPE
Data Directory: $NC_DATA
EOF

# 8. 压缩备份
log "Compressing backup..."
tar czf "$BACKUP_ROOT/nextcloud_$DATE.tar.gz" -C "$BACKUP_ROOT" "$DATE"
rm -rf "$BACKUP_DIR"

# 9. 清理旧备份
log "Cleaning up old backups..."
find "$BACKUP_ROOT" -name "nextcloud_*.tar.gz" -mtime +$RETENTION_DAYS -delete

# 10. 计算备份大小
BACKUP_SIZE=$(du -sh "$BACKUP_ROOT/nextcloud_$DATE.tar.gz" | cut -f1)
log "Backup completed: nextcloud_$DATE.tar.gz ($BACKUP_SIZE)"

设置定时备份

# 保存脚本
sudo cp nextcloud-backup.sh /usr/local/bin/
sudo chmod +x /usr/local/bin/nextcloud-backup.sh

# 设置 crontab(每天凌晨 2:00)
sudo crontab -e
0 2 * * * /usr/local/bin/nextcloud-backup.sh >> /var/log/nextcloud-backup.log 2>&1

12.3 增量备份

使用 rsync 增量备份

#!/bin/bash
# nextcloud-incremental-backup.sh

BACKUP_ROOT="/backup/nextcloud"
NC_DATA="/data/nextcloud-data"
DATE=$(date +%Y%m%d)
FULL_BACKUP="$BACKUP_ROOT/full"
INCREMENTAL_DIR="$BACKUP_ROOT/incremental/$DATE"

# 创建硬链接增量备份(节省空间)
rsync -a --delete \
    --link-dest="$FULL_BACKUP" \
    "$NC_DATA/" "$INCREMENTAL_DIR/"

echo "Incremental backup: $INCREMENTAL_DIR"

使用 BorgBackup

# 安装 BorgBackup
sudo apt install -y borgbackup

# 初始化仓库
borg init --encryption=repokey /backup/borg-nextcloud

# 创建备份
borg create \
    --stats \
    --compression zstd \
    /backup/borg-nextcloud::nextcloud-{now:%Y%m%d-%H%M%S} \
    /var/www/nextcloud \
    /data/nextcloud-data

# 列出备份
borg list /backup/borg-nextcloud

# 恢复特定备份
borg extract /backup/borg-nextcloud::nextcloud-20260510-020000

# 自动清理旧备份
borg prune \
    --keep-daily=7 \
    --keep-weekly=4 \
    --keep-monthly=12 \
    /backup/borg-nextcloud

BorgBackup 自动备份脚本:

#!/bin/bash
# borg-nextcloud-backup.sh

export BORG_REPO="/backup/borg-nextcloud"
export BORG_PASSPHRASE="YourBorgPassword"

# 开启维护模式
sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --on

# 备份数据库
mysqldump -u ncuser -pStrongPassword123! nextcloud | gzip > /tmp/nextcloud-db.sql.gz

# 创建 Borg 备份
borg create --stats --compression zstd \
    ::nextcloud-{now:%Y%m%d-%H%M%S} \
    /var/www/nextcloud \
    /data/nextcloud-data \
    /tmp/nextcloud-db.sql.gz

# 清理
rm /tmp/nextcloud-db.sql.gz
sudo -u www-data php /var/www/nextcloud/occ maintenance:mode --off

# 清理旧备份
borg prune --keep-daily=7 --keep-weekly=4 --keep-monthly=12

# 检查仓库完整性
borg check

12.4 快照备份

LVM 快照

# 假设数据目录在 LVM 卷 /dev/vg0/ncdata

# 创建快照(10GB 快照空间)
sudo lvcreate -s -n ncdata_snap -L 10G /dev/vg0/ncdata

# 挂载快照
sudo mkdir -p /mnt/snapshot
sudo mount /dev/vg0/ncdata_snap /mnt/snapshot

# 备份快照
tar czf /backup/ncdata_snapshot.tar.gz -C /mnt/snapshot .

# 卸载并删除快照
sudo umount /mnt/snapshot
sudo lvremove -f /dev/vg0/ncdata_snap

Btrfs 快照

# 如果数据目录在 Btrfs 分区上

# 创建快照
sudo btrfs subvolume snapshot /data/nextcloud-data /data/snapshots/ncdata-$(date +%Y%m%d)

# 列出快照
sudo btrfs subvolume list /data

# 删除旧快照
sudo btrfs subvolume delete /data/snapshots/ncdata-20260501

ZFS 快照

# 创建 ZFS 快照
sudo zfs snapshot tank/nextcloud@$(date +%Y%m%d)

# 列出快照
sudo zfs list -t snapshot

# 回滚到快照
sudo zfs rollback tank/nextcloud@20260510

# 发送快照到远程
sudo zfs send tank/nextcloud@20260510 | ssh remotehost "zfs recv backup/nextcloud"

12.5 恢复流程

全量恢复

#!/bin/bash
# nextcloud-restore.sh

set -euo pipefail

BACKUP_FILE="/backup/nextcloud/nextcloud_20260510_020000.tar.gz"
NC_ROOT="/var/www/nextcloud"
NC_DATA="/data/nextcloud-data"
DB_TYPE="mysql"
DB_NAME="nextcloud"
DB_USER="ncuser"
DB_PASS="StrongPassword123!"

echo "=== Nextcloud 恢复流程 ==="
echo "备份文件: $BACKUP_FILE"
echo ""

# 1. 解压备份
echo "1. 解压备份..."
RESTORE_DIR="/tmp/nextcloud-restore"
mkdir -p "$RESTORE_DIR"
tar xzf "$BACKUP_FILE" -C "$RESTORE_DIR"
BACKUP_DIR="$RESTORE_DIR/$(ls $RESTORE_DIR)"

# 2. 停止 Web 服务器
echo "2. 停止 Web 服务器..."
sudo systemctl stop nginx

# 3. 恢复配置文件
echo "3. 恢复配置文件..."
sudo rm -rf "$NC_ROOT/config"
sudo cp -a "$BACKUP_DIR/config/" "$NC_ROOT/config/"

# 4. 恢复数据目录
echo "4. 恢复数据目录..."
sudo rm -rf "$NC_DATA"
sudo mkdir -p "$NC_DATA"
sudo rsync -a "$BACKUP_DIR/data/" "$NC_DATA/"

# 5. 恢复应用和主题
echo "5. 恢复应用和主题..."
sudo rsync -a "$BACKUP_DIR/apps/" "$NC_ROOT/apps/"
sudo rsync -a "$BACKUP_DIR/themes/" "$NC_ROOT/themes/"

# 6. 恢复数据库
echo "6. 恢复数据库..."
case "$DB_TYPE" in
    mysql)
        # 删除旧数据库
        mysql -u root -p"$DB_PASS" -e "DROP DATABASE IF EXISTS $DB_NAME;"
        mysql -u root -p"$DB_PASS" -e "CREATE DATABASE $DB_NAME CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"

        # 恢复数据库
        gunzip < "$BACKUP_DIR/database/nextcloud.sql.gz" | mysql -u "$DB_USER" -p"$DB_PASS" "$DB_NAME"
        ;;
    pgsql)
        dropdb -U "$DB_USER" "$DB_NAME"
        createdb -U "$DB_USER" -O "$DB_USER" "$DB_NAME"
        PGPASSWORD="$DB_PASS" pg_restore -U "$DB_USER" -d "$DB_NAME" "$BACKUP_DIR/database/nextcloud.dump"
        ;;
esac

# 7. 修复权限
echo "7. 修复权限..."
sudo chown -R www-data:www-data "$NC_ROOT"
sudo chown -R www-data:www-data "$NC_DATA"
sudo chmod 750 "$NC_DATA"

# 8. 运行修复命令
echo "8. 运行修复命令..."
sudo -u www-data php "$NC_ROOT/occ" maintenance:repair
sudo -u www-data php "$NC_ROOT/occ" db:add-missing-indices
sudo -u www-data php "$NC_ROOT/occ" db:add-missing-columns

# 9. 关闭维护模式
echo "9. 关闭维护模式..."
sudo -u www-data php "$NC_ROOT/occ" maintenance:mode --off

# 10. 启动 Web 服务器
echo "10. 启动 Web 服务器..."
sudo systemctl start nginx

# 11. 扫描文件
echo "11. 扫描文件..."
sudo -u www-data php "$NC_ROOT/occ" files:scan --all

# 12. 清理临时文件
rm -rf "$RESTORE_DIR"

echo ""
echo "=== 恢复完成 ==="

12.6 异地备份

使用 rclone 同步到云存储

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

# 配置远程存储(如 S3、Backblaze B2、Google Drive 等)
rclone config

# 同步备份到远程
rclone sync /backup/nextcloud remote:nextcloud-backup/ \
    --progress \
    --transfers 4 \
    --checkers 8

# 自动化(cron)
# 0 4 * * * rclone sync /backup/nextcloud remote:nextcloud-backup/ --log-file /var/log/rclone.log

使用 rsync 同步到远程服务器

# SSH 密钥认证
ssh-keygen -t ed25519 -f ~/.ssh/nextcloud-backup
ssh-copy-id -i ~/.ssh/nextcloud-backup backup@remote-server

# 同步备份
rsync -avz --delete \
    -e "ssh -i ~/.ssh/nextcloud-backup" \
    /backup/nextcloud/ \
    backup@remote-server:/backup/nextcloud/

12.7 备份验证

定期恢复测试

#!/bin/bash
# backup-verify.sh - 备份验证脚本

BACKUP_FILE="$1"
VERIFY_DIR="/tmp/nextcloud-verify"

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

# 1. 检查文件完整性
echo "1. 检查文件完整性..."
if ! tar tzf "$BACKUP_FILE" > /dev/null 2>&1; then
    echo "ERROR: 备份文件损坏!"
    exit 1
fi

# 2. 解压并检查关键文件
echo "2. 检查关键文件..."
mkdir -p "$VERIFY_DIR"
tar xzf "$BACKUP_FILE" -C "$VERIFY_DIR"
BACKUP_DIR="$VERIFY_DIR/$(ls $VERIFY_DIR)"

# 检查必要文件
for f in config/config.php manifest.txt; do
    if [ ! -f "$BACKUP_DIR/$f" ]; then
        echo "ERROR: 缺少关键文件: $f"
        exit 1
    fi
done

# 3. 检查数据库备份
echo "3. 检查数据库备份..."
if [ -f "$BACKUP_DIR/database/nextcloud.sql.gz" ]; then
    if ! gunzip -t "$BACKUP_DIR/database/nextcloud.sql.gz"; then
        echo "ERROR: 数据库备份损坏!"
        exit 1
    fi
fi

# 4. 检查数据目录
echo "4. 检查数据目录..."
DATA_COUNT=$(find "$BACKUP_DIR/data" -type f | wc -l)
echo "数据文件数量: $DATA_COUNT"

# 清理
rm -rf "$VERIFY_DIR"
echo "备份验证通过 ✓"

12.8 数据迁移

迁移到新服务器

迁移步骤:
1. 旧服务器: 完整备份(数据 + 数据库 + 配置)
2. 新服务器: 安装相同版本的 Nextcloud
3. 新服务器: 恢复备份
4. 新服务器: 修改 config.php 中的域名和路径
5. DNS 切换: 将域名指向新服务器 IP
6. 验证: 确认所有功能正常
# 迁移检查清单
# 1. Nextcloud 版本一致
# 2. PHP 版本一致
# 3. 数据库版本一致
# 4. 文件权限正确
# 5. 数据目录路径正确
# 6. 可信域名更新
# 7. SSL 证书配置
# 8. Cron 任务配置
# 9. Redis 连接配置

12.9 注意事项

  1. 备份一致性: 备份前必须开启维护模式,确保数据一致性
  2. 密钥备份: config.php 中的 secret 和加密密钥必须安全备份
  3. 定期验证: 每月至少进行一次备份恢复测试
  4. 异地备份: 至少保留一份异地备份,防范物理灾难
  5. 备份加密: 异地备份建议加密后再传输
  6. 恢复时间: 记录恢复所需时间,确保满足 RTO 要求

12.10 扩展阅读


上一章: 11 - 性能优化 下一章: 13 - Docker 部署 — Docker/Docker Compose 部署与 AIO 集成。