#!/usr/bin/env bash set -euo pipefail # ============================================ # Vaultwarden 备份脚本 # 备份 SQLite 数据库 + 附件 + 配置 # ============================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # 加载配置 if [ -f .env ]; then set -a; source .env; set +a else echo "[ERROR] .env 文件不存在,请先运行 deploy.sh" >&2 exit 1 fi # ===== 配置 ===== DATA_DIR="${VAULTWARDEN_DATA_DIR:-/var/lib/vaultwarden}" BACKUP_BASE="${BACKUP_DIR:-/var/backups/vaultwarden}" TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_DIR_FULL="${BACKUP_BASE}/${TIMESTAMP}" RETENTION_DAYS=30 echo "========== Vaultwarden 备份 ==========" echo "时间: $(date '+%Y-%m-%d %H:%M:%S')" echo "数据目录: $DATA_DIR" echo "备份目录: $BACKUP_DIR_FULL" echo "" mkdir -p "$BACKUP_DIR_FULL" # ===== 备份 SQLite 数据库 ===== echo "[1/4] 备份 SQLite 数据库..." DB_FILE="$DATA_DIR/db.sqlite3" if [ -f "$DB_FILE" ]; then # 使用 sqlite3 .backup 命令进行在线安全备份 if command -v sqlite3 &> /dev/null; then sqlite3 "$DB_FILE" ".backup '$BACKUP_DIR_FULL/db.sqlite3'" echo " ✓ 数据库已安全备份 (sqlite3 .backup)" else # 降级:直接复制(建议先停止容器) cp "$DB_FILE" "$BACKUP_DIR_FULL/db.sqlite3" cp "${DB_FILE}-wal" "$BACKUP_DIR_FULL/db.sqlite3-wal" 2>/dev/null || true cp "${DB_FILE}-shm" "$BACKUP_DIR_FULL/db.sqlite3-shm" 2>/dev/null || true echo " ✓ 数据库已备份 (文件复制,建议安装 sqlite3 以支持在线备份)" fi else echo " ⚠ 数据库文件不存在: $DB_FILE" fi # ===== 备份附件和密钥 ===== echo "[2/4] 备份附件和密钥..." if [ -d "$DATA_DIR" ]; then tar czf "$BACKUP_DIR_FULL/vaultwarden-data.tar.gz" \ -C "$(dirname "$DATA_DIR")" "$(basename "$DATA_DIR")" \ --exclude="db.sqlite3" --exclude="db.sqlite3-wal" --exclude="db.sqlite3-shm" echo " ✓ 附件和密钥已备份" else echo " ⚠ 数据目录不存在: $DATA_DIR" fi # ===== 备份部署配置 ===== echo "[3/4] 备份部署配置..." tar czf "$BACKUP_DIR_FULL/vaultwarden-config.tar.gz" \ -C "$SCRIPT_DIR" \ docker-compose.yml .env nginx/ 2>/dev/null || true echo " ✓ 配置已备份" # ===== 清理旧备份 ===== echo "[4/4] 清理 ${RETENTION_DAYS} 天前的旧备份..." find "$BACKUP_BASE" -maxdepth 1 -type d -mtime +${RETENTION_DAYS} -exec rm -rf {} \; 2>/dev/null || true echo " ✓ 旧备份已清理" # ===== 汇总 ===== echo "" echo "========== 备份完成 ==========" TOTAL_SIZE=$(du -sh "$BACKUP_DIR_FULL" | cut -f1) echo "备份位置: $BACKUP_DIR_FULL" echo "备份大小: $TOTAL_SIZE" echo "" echo "备份内容:" ls -lh "$BACKUP_DIR_FULL/" echo "" echo "恢复方法:" echo " 1. 停止服务: cd $SCRIPT_DIR && docker compose down" echo " 2. 删除 WAL: rm -f $DATA_DIR/db.sqlite3-wal $DATA_DIR/db.sqlite3-shm" echo " 3. 恢复数据库: cp $BACKUP_DIR_FULL/db.sqlite3 $DATA_DIR/" echo " 4. 恢复附件: tar xzf $BACKUP_DIR_FULL/vaultwarden-data.tar.gz -C $(dirname "$DATA_DIR")" echo " 5. 启动服务: cd $SCRIPT_DIR && docker compose up -d"