共计 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 全库备份(含系统表)
如果需要完整备份所有数据库(包括 mysql、performance_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
正文完