新增firefly引用部署

优化clash verge的DNS问题-极致优化
This commit is contained in:
zeaslity
2026-01-07 10:47:52 +08:00
parent 837bdb4a91
commit 87c9529a2f
30 changed files with 1853 additions and 4991 deletions

View File

@@ -1,264 +0,0 @@
#!/usr/bin/env bash
#
# Gitea 远程备份脚本
# Author: System Administrator
# Version: 1.0.0
# License: MIT
#
# 功能描述通过SSH远程执行Gitea备份操作并将备份文件同步到本地
# 依赖要求ssh, rsync, docker, date, grep, awk 等基础工具
set -euo pipefail
IFS=$'\n\t'
################################################################################
# 全局常量定义区
################################################################################
readonly REMOTE_PORT="22333"
readonly REMOTE_HOST="t0"
readonly SCRIPT_DIR="/root/wdd/backup"
readonly REMOTE_GITEA_CONTAINER="gitea-gitea-1"
readonly REMOTE_GITEA_CONFIG="/bitnami/gitea/custom/conf/app.ini"
readonly REMOTE_BACKUP_SOURCE="/data/gitea/gitea_data/data/tmp/gitea-dump-*.zip"
readonly LOCAL_BACKUP_TARGET="/data/t0_150_230_198_103/gitea/"
# > 日志配置
readonly LOG_DIR="${SCRIPT_DIR}/logs"
readonly LOG_FILE="${LOG_DIR}/gitea_backup_$(date +%Y%m%d).log"
# 日志级别常量
readonly LOG_LEVEL_DEBUG=0
readonly LOG_LEVEL_INFO=1
readonly LOG_LEVEL_WARN=2
readonly LOG_LEVEL_ERROR=3
# 当前日志级别默认INFO
CURRENT_LOG_LEVEL=${LOG_LEVEL_INFO}
################################################################################
# 函数声明区
################################################################################
# 输出格式化日志信息(同时输出到控制台和日志文件)
# @param level string 日志级别DEBUG/INFO/WARN/ERROR
# @param message string 日志消息内容
# @return void
# @require CURRENT_LOG_LEVEL, LOG_FILE
log_message() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local log_entry=""
case "$level" in
"DEBUG")
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_DEBUG} ]; then
log_entry="[DEBUG][${timestamp}] ${message}"
echo "${log_entry}"
echo "${log_entry}" >> "${LOG_FILE}"
fi
;;
"INFO")
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_INFO} ]; then
log_entry="[INFO][${timestamp}] ${message}"
echo "${log_entry}"
echo "${log_entry}" >> "${LOG_FILE}"
fi
;;
"WARN")
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_WARN} ]; then
log_entry="[WARN][${timestamp}] ${message}"
echo "${log_entry}" >&2
echo "${log_entry}" >> "${LOG_FILE}"
fi
;;
"ERROR")
if [ "${CURRENT_LOG_LEVEL}" -le ${LOG_LEVEL_ERROR} ]; then
log_entry="[ERROR][${timestamp}] ${message}"
echo "${log_entry}" >&2
echo "${log_entry}" >> "${LOG_FILE}"
fi
;;
*)
log_entry="[UNKNOWN][${timestamp}] ${message}"
echo "${log_entry}" >&2
echo "${log_entry}" >> "${LOG_FILE}"
;;
esac
}
###
# 执行远程SSH命令
# @param command string 需要执行的远程命令
# @return int 命令执行退出码
# @require REMOTE_HOST, REMOTE_PORT
execute_remote_command() {
local command="$1"
local exit_code
log_message "DEBUG" "执行远程命令: ${command}"
# > 通过SSH连接到远程主机执行命令
ssh -p "${REMOTE_PORT}" "${REMOTE_HOST}" "${command}"
exit_code=$?
if [ ${exit_code} -ne 0 ]; then
log_message "ERROR" "远程命令执行失败,退出码: ${exit_code}"
return ${exit_code}
fi
return 0
}
###
# 执行Gitea备份操作
# @return int 操作执行状态码
# @require REMOTE_GITEA_CONTAINER, REMOTE_GITEA_CONFIG
perform_gitea_backup() {
local backup_command="docker exec -i ${REMOTE_GITEA_CONTAINER} /opt/bitnami/gitea/bin/gitea dump -c ${REMOTE_GITEA_CONFIG}"
log_message "INFO" "开始执行Gitea备份..."
# > 执行Gitea dump命令生成备份文件
if ! execute_remote_command "${backup_command}"; then
log_message "ERROR" "Gitea备份命令执行失败"
return 1
fi
log_message "INFO" "Gitea备份命令执行成功"
return 0
}
###
# 重命名备份文件(添加时间戳)
# @return int 操作执行状态码
# @require REMOTE_GITEA_CONTAINER
rename_backup_file() {
local rename_command="docker exec -i ${REMOTE_GITEA_CONTAINER} /bin/sh -c \"mv /opt/bitnami/gitea/gitea-dump-*.zip /opt/bitnami/gitea/data/tmp/gitea-dump-\$(date +%Y%m%d-%H%M%S).zip\""
log_message "INFO" "开始重命名备份文件..."
# > 在容器内重命名备份文件,添加时间戳
if ! execute_remote_command "${rename_command}"; then
log_message "ERROR" "备份文件重命名失败"
return 1
fi
log_message "INFO" "备份文件重命名成功"
return 0
}
###
# 同步备份文件到本地
# @return int 操作执行状态码
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_BACKUP_SOURCE, LOCAL_BACKUP_TARGET
sync_backup_to_local() {
log_message "INFO" "开始同步备份文件到本地..."
# > 创建本地目标目录(如果不存在)
if [ ! -d "${LOCAL_BACKUP_TARGET}" ]; then
mkdir -p "${LOCAL_BACKUP_TARGET}"
log_message "DEBUG" "创建本地目录: ${LOCAL_BACKUP_TARGET}"
fi
# > 使用rsync同步文件保留关键属性
rsync -avz -e "ssh -p ${REMOTE_PORT}" \
"${REMOTE_HOST}:${REMOTE_BACKUP_SOURCE}" \
"${LOCAL_BACKUP_TARGET}"
local exit_code=$?
if [ ${exit_code} -ne 0 ]; then
log_message "ERROR" "rsync同步失败退出码: ${exit_code}"
return ${exit_code}
fi
log_message "INFO" "备份文件同步成功"
return 0
}
###
# 清理远程备份文件
# @return int 操作执行状态码
# @require REMOTE_BACKUP_SOURCE
cleanup_remote_backup() {
local cleanup_command="rm -f ${REMOTE_BACKUP_SOURCE}"
log_message "INFO" "开始清理远程备份文件..."
# > 删除远程主机上的临时备份文件
if ! execute_remote_command "${cleanup_command}"; then
log_message "ERROR" "远程备份文件清理失败"
return 1
fi
log_message "INFO" "远程备份文件清理成功"
return 0
}
###
# 主执行函数 - 协调整个备份流程
# @return int 脚本执行最终状态码
main() {
local overall_success=true
log_message "INFO" "=== Gitea备份流程开始 ==="
# 切换到工作目录
cd "${SCRIPT_DIR}" || {
log_message "ERROR" "无法切换到工作目录: ${SCRIPT_DIR}"
return 1
}
# 执行备份流程
if ! perform_gitea_backup; then
overall_success=false
fi
if ! rename_backup_file; then
overall_success=false
fi
if ! sync_backup_to_local; then
overall_success=false
fi
if ! cleanup_remote_backup; then
overall_success=false
fi
# 汇总执行结果
if [ "${overall_success}" = true ]; then
log_message "INFO" "=== Gitea备份流程完成 ==="
return 0
else
log_message "ERROR" "=== Gitea备份流程部分失败 ==="
return 1
fi
}
################################################################################
# 异常处理设置
################################################################################
# 设置trap捕获信号
trap 'log_message "ERROR" "脚本被中断"; exit 1' INT TERM
################################################################################
# 主执行流程
################################################################################
# 函数调用关系:
# main -> perform_gitea_backup -> execute_remote_command
# -> rename_backup_file -> execute_remote_command
# -> sync_backup_to_local
# -> cleanup_remote_backup -> execute_remote_command
# 执行主函数
if main; then
log_message "INFO" "脚本执行成功"
exit 0
else
log_message "ERROR" "脚本执行失败"
exit 1
fi

View File

@@ -1,361 +0,0 @@
#!/bin/bash
# =============================================================================
# nextcloud备份脚本
# 功能远程Nextcloud维护模式切换、数据库备份、文件同步及清理
# 版本1.0.0
# 作者Shell脚本工程师
# 许可证MIT License
# 依赖ssh, rsync, docker (远程主机), mariadb-client (远程主机)
# =============================================================================
set -euo pipefail
IFS=$'\n\t'
# > 全局常量定义
readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="/root/wdd/backup"
readonly LOCK_FILE="/root/wdd/backup/${SCRIPT_NAME}.lock"
# > 远程主机配置
readonly REMOTE_HOST="s5"
readonly REMOTE_PORT="22333"
readonly REMOTE_USER="root"
readonly REMOTE_NEXTCLOUD_DIR="/data/nextcloud"
readonly REMOTE_DB_CONTAINER="nextcloud-db"
readonly REMOTE_WEB_CONTAINER="nextcloud_web"
# > 数据库配置
readonly DB_NAME="nextcloud"
readonly DB_USER="nextcloud"
readonly DB_PASSWORD="boge14@Level5"
# > 本地配置
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/nextcloud"
# > 日志配置
readonly LOG_DIR="${SCRIPT_DIR}/logs"
readonly LOG_FILE="${LOG_DIR}/nextcloud_backup_$(date +%Y%m%d).log"
# > 颜色输出定义
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'
# =============================================================================
# 日志函数集
# =============================================================================
###
# 初始化日志系统
# @require 无
# @return 0 成功 | >0 失败
###
init_log_system() {
mkdir -p "${LOG_DIR}" || return 1
touch "${LOG_FILE}" || return 1
return 0
}
###
# 记录日志消息
# @param level string 日志级别DEBUG/INFO/WARN/ERROR
# @param message string 日志消息
# @require LOG_FILE
# @return 0 成功
###
log_message() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case "${level}" in
"DEBUG") echo -e "${BLUE}[DEBUG]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
"INFO") echo -e "${GREEN}[INFO]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
"WARN") echo -e "${YELLOW}[WARN]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
"ERROR") echo -e "${RED}[ERROR]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
*) echo "${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
esac
return 0
}
# =============================================================================
# 工具函数集
# =============================================================================
###
# 检查命令是否存在
# @param command_name string 命令名称
# @require 无
# @return 0 存在 | 1 不存在
###
check_command() {
local command_name="$1"
if ! command -v "${command_name}" >/dev/null 2>&1; then
log_message "ERROR" "命令不存在: ${command_name}"
return 1
fi
return 0
}
###
# 执行远程SSH命令
# @param command string 要执行的命令
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER
# @return 远程命令的退出码
###
execute_remote_command() {
local command="$1"
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "${command}"
return $?
}
###
# 创建锁文件防止并发执行
# @require LOCK_FILE
# @return 0 成功获取锁 | 1 锁已存在
###
acquire_lock() {
if [ -e "${LOCK_FILE}" ]; then
log_message "ERROR" "备份任务正在运行或异常退出,请检查锁文件: ${LOCK_FILE}"
return 1
fi
echo "$$" > "${LOCK_FILE}"
trap 'release_lock' EXIT
return 0
}
###
# 释放锁文件
# @require LOCK_FILE
# @return 0 成功
###
release_lock() {
[ -e "${LOCK_FILE}" ] && rm -f "${LOCK_FILE}"
return 0
}
# =============================================================================
# Nextcloud核心备份函数
# =============================================================================
###
# 启用Nextcloud维护模式
# @require execute_remote_command, REMOTE_WEB_CONTAINER
# @return 0 成功 | >0 失败
###
enable_maintenance_mode() {
log_message "INFO" "启用Nextcloud维护模式..."
local maintenance_cmd="docker exec -u www-data ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --on"
if ! execute_remote_command "${maintenance_cmd}"; then
log_message "ERROR" "启用维护模式失败"
return 1
fi
log_message "INFO" "维护模式已启用"
return 0
}
###
# 禁用Nextcloud维护模式
# @require execute_remote_command, REMOTE_WEB_CONTAINER
# @return 0 成功 | >0 失败
###
disable_maintenance_mode() {
log_message "INFO" "禁用Nextcloud维护模式..."
local maintenance_cmd="docker exec -u www-data ${REMOTE_WEB_CONTAINER} php occ maintenance:mode --off"
if ! execute_remote_command "${maintenance_cmd}"; then
log_message "ERROR" "禁用维护模式失败"
return 1
fi
log_message "INFO" "维护模式已禁用"
return 0
}
###
# 远程执行MariaDB数据库备份
# @require execute_remote_command, REMOTE_DB_CONTAINER, DB_NAME, DB_USER, DB_PASSWORD, REMOTE_NEXTCLOUD_DIR
# @return 0 成功 | >0 失败
###
backup_database() {
log_message "INFO" "开始数据库备份..."
local backup_file="${REMOTE_NEXTCLOUD_DIR}/nextcloud-db_backup_$(date +%Y%m%d-%H%M%S).sql"
local backup_cmd="docker exec ${REMOTE_DB_CONTAINER} mariadb-dump --single-transaction -h localhost -u ${DB_USER} -p'${DB_PASSWORD}' ${DB_NAME} > ${backup_file}"
if ! execute_remote_command "${backup_cmd}"; then
log_message "ERROR" "数据库备份失败"
return 1
fi
# > 验证备份文件是否创建成功
local verify_cmd="[ -f \"${backup_file}\" ] && echo \"exists\" || echo \"missing\""
if [ "$(execute_remote_command "${verify_cmd}")" != "exists" ]; then
log_message "ERROR" "数据库备份文件创建失败"
return 1
fi
log_message "INFO" "数据库备份完成: ${backup_file}"
return 0
}
###
# 使用rsync同步Nextcloud文件到本地
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_NEXTCLOUD_DIR, LOCAL_BACKUP_DIR
# @return 0 成功 | >0 失败
###
sync_nextcloud_files() {
log_message "INFO" "开始同步Nextcloud文件到本地..."
# > 创建本地暂存目录
mkdir -p "${LOCAL_BACKUP_DIR}" || {
log_message "ERROR" "创建本地暂存目录失败: ${LOCAL_BACKUP_DIR}"
return 1
}
# > 构建rsync命令
local rsync_cmd="rsync -avz --progress -e 'ssh -p ${REMOTE_PORT}'"
rsync_cmd+=" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_NEXTCLOUD_DIR}/"
rsync_cmd+=" ${LOCAL_BACKUP_DIR}/"
# > 执行rsync同步
if ! eval "${rsync_cmd}"; then
log_message "ERROR" "Nextcloud文件同步失败"
return 1
fi
log_message "INFO" "Nextcloud文件同步完成"
return 0
}
###
# 远程删除数据库备份文件
# @require execute_remote_command, REMOTE_NEXTCLOUD_DIR
# @return 0 成功 | >0 失败
###
remote_cleanup_backup() {
log_message "INFO" "清理远程数据库备份文件..."
local cleanup_cmd="rm -f ${REMOTE_NEXTCLOUD_DIR}/nextcloud-db_backup_*.sql"
if ! execute_remote_command "${cleanup_cmd}"; then
log_message "ERROR" "远程清理失败"
return 1
fi
log_message "INFO" "远程清理完成"
return 0
}
###
# 清理本地暂存目录
# @require LOCAL_BACKUP_DIR
# @return 0 成功
###
local_cleanup() {
log_message "INFO" "清理本地暂存目录..."
[ -d "${LOCAL_BACKUP_DIR}" ] && rm -rf "${LOCAL_BACKUP_DIR}"
return 0
}
# =============================================================================
# 主执行流程
# =============================================================================
###
# 主备份流程
# @require 所有上述函数
# @return 0 成功 | >0 失败
###
main_backup_process() {
log_message "INFO" "=== 开始Nextcloud备份任务 ==="
# > 检查依赖命令
local required_commands=("ssh" "rsync")
for cmd in "${required_commands[@]}"; do
if ! check_command "${cmd}"; then
return 1
fi
done
# > 执行备份流程
local steps=(
enable_maintenance_mode
backup_database
sync_nextcloud_files
remote_cleanup_backup
disable_maintenance_mode
# local_cleanup
)
for step in "${steps[@]}"; do
if ! "${step}"; then
log_message "ERROR" "备份任务失败,正在尝试恢复..."
# > 尝试禁用维护模式
disable_maintenance_mode || true
return 1
fi
done
log_message "INFO" "=== Nextcloud备份任务完成 ==="
return 0
}
# =============================================================================
# 脚本入口点
# =============================================================================
# > 设置错误处理
trap 'log_message "ERROR" "脚本异常退出"; disable_maintenance_mode || true; release_lock; exit 1' ERR
# > 主执行块
main() {
if ! acquire_lock; then
exit 1
fi
if ! init_log_system; then
log_message "ERROR" "日志系统初始化失败"
exit 1
fi
if ! main_backup_process; then
log_message "ERROR" "备份任务执行失败"
exit 1
fi
release_lock
exit 0
}
# > 脚本执行入口
main "$@"
# =============================================================================
# 函数调用关系图
# =============================================================================
# main
# ├── acquire_lock
# ├── init_log_system
# └── main_backup_process
# ├── check_command (多次调用)
# ├── enable_maintenance_mode
# │ └── execute_remote_command
# ├── backup_database
# │ └── execute_remote_command
# ├── sync_nextcloud_files
# ├── move_to_backup_dir
# ├── remote_cleanup_backup
# │ └── execute_remote_command
# ├── disable_maintenance_mode
# │ └── execute_remote_command
# └── local_cleanup

View File

@@ -1,342 +0,0 @@
#!/bin/bash
# =============================================================================
# b-vault-warden备份脚本
# 功能远程执行Vaultwarden备份、同步备份文件、加密压缩及清理
# 版本1.0.0
# 作者Shell脚本工程师
# 许可证MIT License
# 依赖ssh, rsync, 7zip, docker (远程主机)
# =============================================================================
set -euo pipefail
IFS=$'\n\t'
# > 全局常量定义
readonly SCRIPT_NAME="$(basename "$0")"
readonly SCRIPT_DIR="/root/wdd/backup"
readonly LOCK_FILE="/root/wdd/backup/${SCRIPT_NAME}.lock"
# > 配置参数(可根据需要调整为环境变量)
readonly REMOTE_HOST="s5"
readonly REMOTE_PORT="22333"
readonly REMOTE_USER="root"
readonly REMOTE_BACKUP_CMD="docker exec vault-warden /vaultwarden backup"
readonly REMOTE_DATA_DIR="/data/vault-warden/persist-data"
readonly LOCAL_BACKUP_DIR="/data/s5_146-56-159-175/vault_warden"
readonly BACKUP_PATTERNS=(
"config.json"
"rsa_key*"
"attachments"
"icon_cache"
"sends"
"db_*.sqlite3"
)
readonly ENCRYPTION_PASSWORD="SuperWdd.123" # > 请在实际使用时修改
# > 日志配置
readonly LOG_DIR="${SCRIPT_DIR}/logs"
readonly LOG_FILE="${LOG_DIR}/vault_warden_backup_$(date +%Y%m%d).log"
# > 颜色输出定义
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly NC='\033[0m'
# =============================================================================
# 日志函数集
# =============================================================================
###
# 初始化日志系统
# @require 无
# @return 0 成功 | >0 失败
###
init_log_system() {
mkdir -p "${LOG_DIR}" || return 1
touch "${LOG_FILE}" || return 1
return 0
}
###
# 记录日志消息
# @param level string 日志级别DEBUG/INFO/WARN/ERROR
# @param message string 日志消息
# @require LOG_FILE
# @return 0 成功
###
log_message() {
local level="$1"
local message="$2"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
case "${level}" in
"DEBUG") echo -e "${BLUE}[DEBUG]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
"INFO") echo -e "${GREEN}[INFO]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
"WARN") echo -e "${YELLOW}[WARN]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
"ERROR") echo -e "${RED}[ERROR]${NC} ${timestamp} - ${message}" | tee -a "${LOG_FILE}" >&2 ;;
*) echo "${timestamp} - ${message}" | tee -a "${LOG_FILE}" ;;
esac
return 0
}
# =============================================================================
# 工具函数集
# =============================================================================
###
# 检查命令是否存在
# @param command_name string 命令名称
# @require 无
# @return 0 存在 | 1 不存在
###
check_command() {
local command_name="$1"
if ! command -v "${command_name}" >/dev/null 2>&1; then
log_message "ERROR" "命令不存在: ${command_name}"
return 1
fi
return 0
}
###
# 执行远程SSH命令
# @param command string 要执行的命令
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER
# @return 远程命令的退出码
###
execute_remote_command() {
local command="$1"
ssh -p "${REMOTE_PORT}" "${REMOTE_USER}@${REMOTE_HOST}" "${command}"
return $?
}
###
# 创建锁文件防止并发执行
# @require LOCK_FILE
# @return 0 成功获取锁 | 1 锁已存在
###
acquire_lock() {
if [ -e "${LOCK_FILE}" ]; then
log_message "ERROR" "备份任务正在运行或异常退出,请检查锁文件: ${LOCK_FILE}"
return 1
fi
echo "$$" > "${LOCK_FILE}"
trap 'release_lock' EXIT
return 0
}
###
# 释放锁文件
# @require LOCK_FILE
# @return 0 成功
###
release_lock() {
[ -e "${LOCK_FILE}" ] && rm -f "${LOCK_FILE}"
return 0
}
# =============================================================================
# 核心备份函数
# =============================================================================
###
# 远程执行Vaultwarden备份命令
# @require execute_remote_command, REMOTE_BACKUP_CMD
# @return 0 成功 | >0 失败
###
remote_execute_backup() {
log_message "INFO" "开始在远程主机执行Vaultwarden备份..."
if ! execute_remote_command "${REMOTE_BACKUP_CMD}"; then
log_message "ERROR" "远程备份命令执行失败"
return 1
fi
log_message "INFO" "远程备份命令执行成功"
return 0
}
###
# 使用rsync同步备份文件到本地
# @require REMOTE_HOST, REMOTE_PORT, REMOTE_USER, REMOTE_DATA_DIR, LOCAL_BACKUP_DIR, BACKUP_PATTERNS
# @return 0 成功 | >0 失败
###
sync_backup_files() {
log_message "INFO" "开始同步备份文件到本地..."
# > 创建本地暂存目录
mkdir -p "${LOCAL_BACKUP_DIR}" || {
log_message "ERROR" "创建本地暂存目录失败: ${LOCAL_BACKUP_DIR}"
return 1
}
# > 构建rsync命令
local rsync_cmd="rsync -avz --progress -e 'ssh -p ${REMOTE_PORT}'"
for pattern in "${BACKUP_PATTERNS[@]}"; do
rsync_cmd+=" ${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_DATA_DIR}/${pattern}"
done
rsync_cmd+=" ${LOCAL_BACKUP_DIR}/"
# > 执行rsync同步
if ! eval "${rsync_cmd}"; then
log_message "ERROR" "文件同步失败"
return 1
fi
log_message "INFO" "文件同步完成"
return 0
}
###
# 使用7zip加密压缩备份文件
# @require LOCAL_BACKUP_DIR, LOCAL_BACKUP_DIR, ENCRYPTION_PASSWORD
# @return 0 成功 | >0 失败
###
encrypt_and_compress() {
log_message "INFO" "开始加密压缩备份文件..."
# > 检查7zip命令
if ! check_command "7z"; then
log_message "ERROR" "7zip命令不存在请安装p7zip-full包"
return 1
fi
# > 创建备份目录
mkdir -p "${LOCAL_BACKUP_DIR}" || {
log_message "ERROR" "创建备份目录失败: ${LOCAL_BACKUP_DIR}"
return 1
}
local backup_file="${LOCAL_BACKUP_DIR}/vaultwarden-backup-$(date +%Y%m%d-%H%M%S).7z"
# > 执行加密压缩
if ! (cd "${LOCAL_BACKUP_DIR}" && 7z a -p"${ENCRYPTION_PASSWORD}" -mhe=on "${backup_file}" . >/dev/null); then
log_message "ERROR" "加密压缩失败"
return 1
fi
log_message "INFO" "加密压缩完成: ${backup_file}"
return 0
}
###
# 远程删除备份数据库文件
# @require execute_remote_command, REMOTE_DATA_DIR
# @return 0 成功 | >0 失败
###
remote_cleanup_backup() {
log_message "INFO" "开始清理远程备份文件..."
local cleanup_cmd="rm -rf ${REMOTE_DATA_DIR}/db_*.sqlite3"
if ! execute_remote_command "${cleanup_cmd}"; then
log_message "ERROR" "远程清理失败"
return 1
fi
log_message "INFO" "远程清理完成"
return 0
}
###
# 清理本地暂存目录
# @require LOCAL_BACKUP_DIR
# @return 0 成功
###
local_cleanup() {
log_message "INFO" "清理本地暂存目录..."
[ -d "${LOCAL_BACKUP_DIR}" ] && rm -rf "${LOCAL_BACKUP_DIR}"
return 0
}
# =============================================================================
# 主执行流程
# =============================================================================
###
# 主备份流程
# @require 所有上述函数
# @return 0 成功 | >0 失败
###
main_backup_process() {
log_message "INFO" "=== 开始Vaultwarden备份任务 ==="
# > 检查依赖命令
local required_commands=("ssh" "rsync" "7z")
for cmd in "${required_commands[@]}"; do
if ! check_command "${cmd}"; then
return 1
fi
done
# > 执行备份流程
local steps=(
remote_execute_backup
sync_backup_files
encrypt_and_compress
remote_cleanup_backup
# local_cleanup
)
for step in "${steps[@]}"; do
if ! "${step}"; then
log_message "ERROR" "备份任务在第 ${#steps[@]} 步失败"
return 1
fi
done
log_message "INFO" "=== Vaultwarden备份任务完成 ==="
return 0
}
# =============================================================================
# 脚本入口点
# =============================================================================
# > 设置错误处理
trap 'log_message "ERROR" "脚本异常退出"; release_lock; exit 1' ERR
# > 主执行块
main() {
if ! acquire_lock; then
exit 1
fi
if ! init_log_system; then
log_message "ERROR" "日志系统初始化失败"
exit 1
fi
if ! main_backup_process; then
log_message "ERROR" "备份任务执行失败"
exit 1
fi
release_lock
exit 0
}
# > 脚本执行入口
main "$@"
# =============================================================================
# 函数调用关系图
# =============================================================================
# main
# ├── acquire_lock
# ├── init_log_system
# └── main_backup_process
# ├── check_command (多次调用)
# ├── remote_execute_backup
# │ └── execute_remote_command
# ├── sync_backup_files
# ├── encrypt_and_compress
# │ └── check_command
# ├── remote_cleanup_backup
# │ └── execute_remote_command
# └── local_cleanup

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env bash
# =============================================================================
# Meta : Firefly III 备份执行脚本
# Version : 1.0.0
# Author : Bash Shell Senior Development Engineer
# License : MIT
# Description : 自动化执行 Firefly III 远程备份、同步、加密、上传及清理任务。
#
# 本脚本基于公司备份中心的通用框架,使用 common.sh 中定义的日志、远程执行、
# 加密与 rclone 函数实现。它假定 Firefly III 运行在名为 p3 的远程服务器
# 上,并且容器使用 MariaDB 作为数据库。由于 p3 的磁盘 I/O 性能较差,
# Firefly III 使用挂载在 /mnt/ramdisk 的 RAM 磁盘保存数据库和上传目录。
# 为保证数据持久性,本脚本会定期将数据拉取到备份中心并上传到异地存储。
# =============================================================================
set -euo pipefail
IFS=$'\n\t'
# -----------------------------------------------------------------------------
# 引入公共库
# -----------------------------------------------------------------------------
source "$(dirname "$0")/common.sh" || { echo "FATAL: common.sh not found." >&2; exit 1; }
# -----------------------------------------------------------------------------
# 配置区
# -----------------------------------------------------------------------------
readonly APP_NAME="FireflyIII"
readonly REMOTE_USER="root"
readonly REMOTE_HOST="p3"
# 远程主机的 SSH 端口继承自 common.sh 中的 REMOTE_SSH_PORT
readonly MAX_ENCRYPTED_REPLICAS=3 # 可根据需求调整远程保留的最大加密副本数
# MariaDB 容器名称及数据库凭据。建议通过环境变量传入,避免明文密码。
readonly REMOTE_DB_CONTAINER="firefly_iii_db"
# 从环境变量中读取数据库名称和凭据,默认值仅供示例使用。
readonly DB_USER="${FIREFLY_DB_USER:-firefly}" # 数据库用户名
readonly DB_PASSWORD="${FIREFLY_DB_PASSWORD:-ChangeThisPassword}" # 数据库密码
readonly DB_NAME="${FIREFLY_DB_NAME:-firefly}" # 数据库名
# 远程路径FireflyIII 在 p3 上的 RAM 磁盘挂载目录。
readonly REMOTE_UPLOAD_DIR="/mnt/ramdisk/firefly_iii_upload"
readonly REMOTE_DB_RAMDIR="/mnt/ramdisk/firefly_iii_db"
# 本地备份目录。根据备份中心目录结构自定义,用于暂存同步文件。
readonly LOCAL_BACKUP_DIR="/data/p3_firefly_iii"
# -----------------------------------------------------------------------------
# 主执行流程
# -----------------------------------------------------------------------------
main() {
trap 'log_message "ERROR" "${APP_NAME} 的备份任务出现错误! 终止"' ERR
log_message "INFO" "====== 开始 ${APP_NAME} 备份任务 ======"
# -------------------------------------------------------------------------
# 步骤 1: 在远程服务器中创建数据库转储
#
# 使用 mariadb-dump 从容器中导出数据库,并将结果重定向到 RAM 磁盘目录。
# 由于磁盘 IO 慢,转储文件直接写入 RAM 磁盘可以减少时间。
# 注意: 为防止密码泄露,请保证 DB_PASSWORD 不在 shell 历史中。
# -------------------------------------------------------------------------
log_message "INFO" "[Step 1/7] 在远程 p3 上导出 Firefly III 数据库..."
local dump_filename="firefly-db_backup_$(date +%Y%m%d-%H%M%S).sql"
local remote_dump_path="${REMOTE_DB_RAMDIR}/${dump_filename}"
local dump_cmd="docker exec ${REMOTE_DB_CONTAINER} mariadb-dump --single-transaction -h localhost -u ${DB_USER} -p'${DB_PASSWORD}' ${DB_NAME} > ${remote_dump_path}"
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "${dump_cmd}"
# -------------------------------------------------------------------------
# 步骤 2: Rsync 同步数据库转储和上传目录到备份中心
#
# 将远程的 RAM 磁盘数据复制到本地目录。这里创建子目录以避免命名冲突。
# -------------------------------------------------------------------------
log_message "INFO" "[Step 2/7] rsync 复制远程数据到备份中心..."
mkdir -p "${LOCAL_BACKUP_DIR}/upload"
# 同步上传目录
rsync -avz --delete --progress -e "ssh -p ${REMOTE_SSH_PORT}" \
"${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_UPLOAD_DIR}/" \
"${LOCAL_BACKUP_DIR}/upload/"
# 同步数据库转储
rsync -avz --progress -e "ssh -p ${REMOTE_SSH_PORT}" \
"${REMOTE_USER}@${REMOTE_HOST}:${remote_dump_path}" \
"${LOCAL_BACKUP_DIR}/"
# 可选: 若需备份配置文件,可在此加入 rsync 命令复制 .env 和 docker-compose.yml
# 例如rsync -avz "${REMOTE_USER}@${REMOTE_HOST}:/path/to/compose/.env" "${LOCAL_BACKUP_DIR}/"
# -------------------------------------------------------------------------
# 步骤 3: 远程清理数据库转储
#
# 删除 p3 上的临时 .sql 文件,防止 RAM 磁盘占用。
# -------------------------------------------------------------------------
log_message "INFO" "[Step 3/7] 清理远程数据库转储文件..."
execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "rm -f ${remote_dump_path}"
# -------------------------------------------------------------------------
# 步骤 4: 本地加密压缩
#
# 使用 7zip 加密并压缩整个本地备份目录。压缩包命名包含时间戳。
# -------------------------------------------------------------------------
log_message "INFO" "[Step 4/7] 使用 7zip 加密本地备份目录..."
local archive_file="${SCRIPT_RUN_DIR}/${APP_NAME}-backup-$(date +%Y%m%d-%H%M%S).7z"
encrypt_with_7zip "${LOCAL_BACKUP_DIR}" "${archive_file}"
# -------------------------------------------------------------------------
# 步骤 5: rclone 上传加密包
# -------------------------------------------------------------------------
log_message "INFO" "[Step 5/7] 上传加密压缩包至冷存储 => ${RCLONE_REMOTE_REPO}..."
rclone_copy "${archive_file}" "${RCLONE_REMOTE_REPO}"
# -------------------------------------------------------------------------
# 步骤 6: 控制远程仓库副本数
# -------------------------------------------------------------------------
log_message "INFO" "[Step 6/7] 控制远程备份副本数量为 ${MAX_ENCRYPTED_REPLICAS}..."
rclone_control_replicas "${RCLONE_REMOTE_REPO}" "${APP_NAME}-backup-" "${MAX_ENCRYPTED_REPLICAS}"
# -------------------------------------------------------------------------
# 步骤 7: 本地清理
#
# 删除本地生成的加密压缩包,以节省磁盘空间。可根据需要删除同步目录。
# -------------------------------------------------------------------------
log_message "INFO" "[Step 7/7] 清理本地加密压缩包..."
cleanup_local_encrypted_files "${SCRIPT_RUN_DIR}"
# 可选: rm -rf "${LOCAL_BACKUP_DIR}"
log_message "INFO" "====== ${APP_NAME} 备份任务已全部完成! ======"
}
main "$@"