建站问答(八):数据库与站点文件的备份与恢复实战指南

2次阅读
没有评论

共计 4363 个字符,预计需要花费 11 分钟才能阅读完成。

核心原则:数据库备份和文件备份必须在同一时间点进行,否则可能出现数据不一致。

一、数据库备份

1.1 逻辑备份(推荐)

逻辑备份导出的是 SQL 语句,跨版本兼容性最好,也是官方推荐方式。

# ─── 无压缩备份 ───
cd /web && set -a && source .env && set +a && \
docker exec wpdb mariadb-dump \
  -u root \
  -p"${DB_ROOT_PASSWORD}" \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --add-drop-table \
  wordpress > /web/backup/wp-db-backup-$(date +%Y%m%d-%H%M%S).sql

# ─── 压缩备份 ───
cd /web && set -a && source .env && set +a && \
docker exec wpdb mariadb-dump \
  -u root \
  -p"${DB_ROOT_PASSWORD}" \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --add-drop-table \
  wordpress | gzip > /web/backup/wp-db-backup-$(date +%Y%m%d-%H%M%S).sql.gz

参数逐条解释:

参数 作用
-u root 使用 root 用户(拥有全部权限)
-p"${DB_ROOT_PASSWORD}" 从环境变量读取密码,避免硬编码
--single-transaction 最关键。在事务中执行备份,保证数据一致性,不锁表(InnoDB)
--routines 包含存储过程和函数
--triggers 包含触发器
--events 包含事件调度器
--add-drop-table 恢复时先 DROP 再 CREATE,避免冲突

⚠️ --single-transaction 只对 InnoDB 有效。 如果数据库中有 MyISAM 表(极少见),需要加 --lock-tables。WordPress 默认全部使用 InnoDB,所以没问题。

1.2 全库备份(含系统表)

如果需要完整备份所有数据库(包括 mysqlperformance_schema 等):

cd /web && set -a && source .env && set +a && \
docker exec wpdb mariadb-dump \
  -u root \
  -p"${DB_ROOT_PASSWORD}" \
  --single-transaction \
  --all-databases \
  --routines --triggers --events \
  | gzip > /web/backup/all-databases-$(date +%Y%m%d-%H%M%S).sql.gz

1.3 验证备份文件完整性

备份完一定要验证,否则等于没备份。

# 检查 gzip 文件是否完整
gzip -t /web/backup/wp-db-backup-20260904-095533.sql.gz
# 无输出 = 正常;报错 = 文件损坏

# 检查 SQL 文件末尾是否有完成标记
zcat /web/backup/wp-db-backup-20260904-095533.sql.gz | tail -5
# 期望看到:
# -- Dump completed on 2026-09-04 09:55:33

# 检查文件大小是否合理(不应为 0 或异常小)
ls -lh /web/backup/wp-db-backup-*.sql.gz

二、WordPress 文件备份

2.1 备份站点文件

# /web/wp 包含:核心代码、主题、插件、上传文件、配置文件
tar czvf /web/backup/wp-files-$(date +%Y%m%d-%H%M%S).tar.gz \
  -C /web wp

# 查看大小
ls -lh /backup/wp-files-*.tar.gz

2.2 排除不需要的文件(可选)

# 排除缓存文件(如果安装了缓存插件)
tar /web/backup/wp-files-$(date +%Y%m%d-%H%M%S).tar.gz \
  --exclude='wp/cache/*' \
  --exclude='wp-content/cache/*' \
  --exclude='wp-content/uploads/tmp/*' \
  -C /web wp

三、一键备份脚本

可以将上述步骤整合为一个可定时执行的脚本

#!/bin/bash
# /web/backup.sh — WordPress 全站备份脚本

set -euo pipefail

# ─── 配置 ───
BACKUP_DIR="/web/backup"
DATE=$(date +%Y%m%d-%H%M%S)
RETENTION_DAYS=14
COMPOSE_DIR="/web"

# 加载环境变量(获取数据库密码)
cd "$COMPOSE_DIR"
set -a && source ${COMPOSE_DIR}/.env && set +a

# ─── 创建备份目录 ───
# mkdir -p ${BACKUP_DIR}

echo "[$(date)] 开始备份..."

# ─── 1. 数据库逻辑备份 ───
echo "  → 备份数据库..."
docker exec wpdb mariadb-dump \
  -u root \
  -p"${DB_ROOT_PASSWORD}" \
  --single-transaction \
  --routines --triggers --events \
  --add-drop-table \
  wordpress | gzip > ${BACKUP_DIR}/wp-db-backup-${DATE}.sql.gz

# 验证
gzip -t ${BACKUP_DIR}/wp-db-backup-${DATE}.sql.gz
echo "  → 数据库备份完成: $(du -h ${BACKUP_DIR}/wp-db-backup-${DATE}.sql.gz | cut -f1)"

# ─── 2. WordPress 文件备份 ───
echo "  → 备份站点文件..."
tar czvf ${BACKUP_DIR}/wp-files-${DATE}.tar.gz -C ${COMPOSE_DIR} wp
echo "  → 站点文件备份完成: $(du -h ${BACKUP_DIR}/wp-files-${DATE}.tar.gz | cut -f1)"

# ─── 3. 清理过期备份 ───
echo "  → 清理 ${RETENTION_DAYS} 天前的备份..."
find ${BACKUP_DIR} -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete
find ${BACKUP_DIR} -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete

echo "[$(date)] 备份全部完成 ✅"
ls -lh ${BACKUP_DIR}/*-${DATE}*

设置定时任务

# 赋予执行权限
chmod +x /web/backup.sh

# 手动执行一次测试
/web/backup.sh

# 设置定时任务(每天凌晨 3 点)
crontab -e
# 添加:
# 0 3 * * * /web/backup.sh >> /var/log/wp-backup.log 2>&1

四、数据库恢复

4.1 从逻辑备份恢复

# ─── 恢复到运行中的数据库(覆盖) ───

# 先备份当前数据(以防恢复出错还能回退)
cd /web && set -a && source .env && set +a && \
docker exec wpdb mariadb-dump \
  -u root \
  -p"${DB_ROOT_PASSWORD}" \
  --single-transaction \
  --routines --triggers --events \
  --add-drop-table \
  wordpress | gzip > /web/backup/pre-restore-$(date +%Y%m%d-%H%M%S).sql.gz

# 解压并导入
zcat /web/backup/wp-db-backup-20260904-095533.sql.gz | \
  docker exec -i wpdb mysql \
  -u root \
  -p"${DB_ROOT_PASSWORD}" \
  wordpress

echo "数据库恢复完成"

4.2 恢复后验证

# 检查文章数量
docker exec wpdb mysql -u root -p"${DB_ROOT_PASSWORD}" -e "
  SELECT COUNT(*) AS posts FROM wordpress.wp_posts WHERE post_type='post';
  SELECT COUNT(*) AS users FROM wordpress.wp_users;
  SELECT option_value FROM wordpress.wp_options WHERE option_name='siteurl';
"

# 检查 WordPress 是否能正常连接数据库
docker exec wp php -r "
  \$conn = new mysqli('mysql', 'wpuser', getenv('WORDPRESS_DB_PASSWORD'), 'wordpress');
  echo \$conn->connect_error ? 'FAIL: '.\$conn->connect_error : 'OK';
"

五、WordPress 文件恢复

5.1 恢复站点文件

# 1. 停止 WordPress 容器(避免写入冲突)
docker compose stop wordpress

# 2. 备份当前文件(以防万一)
mv /web/wp /web/wp_broken_$(date +%Y%m%d-%H%M%S)

# 3. 从备份恢复
tar xzf /web/backup/wp-files-20260904-095533.tar.gz -C /web

# 4. 修复权限(关键!)
chown -R 33:33 /web/wp
find /web/wp -type d -exec chmod 755 {} \;
find /web/wp -type f -exec chmod 644 {} \;

# 5. 重启
docker compose start wordpress

5.2 权限详解

WordPress 容器(wordpress:7.0.2-php8.4-apache)内以 www-data(UID 33)运行:

# 确认容器内的用户
docker exec wp id www-data
# uid=33(www-data) gid=33(www-data)

# 所以宿主机上 /web/wp 的所有者必须是 33:33
chown -R 33:33 /web/wp

上传目录需要额外写权限

# wp-content/uploads 需要 www-data 可写
chmod -R 755 /web/wp/wp-content/uploads
正文完
 0
评论(没有评论)