bash脚本打包网站web目录及MySQL数据库并复制到异地备份

一个简单的备份脚本,适合小型站点的使用,主要功能

  1. 使用 tar 打包web目录。有两种工作模式,整个目录全量打包、排除某些目录的快速打包;
  2. 通过 mysqldump 备份mysql数据库并压缩;
  3. 把备份文件通过 ssh/scp 传送到远程服务器上(异地备份);
  4. 本服务器保留最近的数个备份,超过指定数量的备份自动删除;
  5. 备份后查询远程服务器磁盘使用情况,并写入日志;
  6. 把整个日志邮件内容发送给指定的邮箱;

脚本内容及使用

正式脚本见后文附件。下面是需要主要要重点关注的部分

#!/bin/bash
set -euo pipefail

# usage: 
# bash <this-script.bash> to archive web folder, 
#
# bash <this-script.bash> --full to ignore --exclude xxx 
#
# notice: 
# require bash, and sh will NOT work
#
# Written with the assistance of ChatGPT and Gemini. 
# 2025/12/18
#
#


#######################################
# 全局配置
#######################################
TZ=Asia/Shanghai

NOW=$(TZ=${TZ} date +%Y%m%d-%H%M%S)

LOG_FILE=/home/username/auto_backup/log_${NOW}.log
LOCAL_SAVE=/home/username/auto_backup/save

# archive file kept limitation
KEEP_FULL=1
KEEP_BRF=5

# remote via ssh
REMOTE_USER=loginname
REMOTE_HOST=backup.path8.net
REMOTE_DIR='~/auto_backup_store'
SSH_KEY='/home/username/.ssh/id_rsa_auth_ssl'

# 自动通知到指定的邮件,每行一个,不需要任何分隔符号
MAIL_TO=(
    username@gmail.com
)

# 是否启用排除
ENABLE_EXCLUDE=1 # 1=启用排除,0=完整备份

while [ "$#" -gt 0 ]; do
    case "$1" in
        --exclude) ENABLE_EXCLUDE=1 ;;
        --full) ENABLE_EXCLUDE=0 ;;
        *) ;;
    esac
    shift
done

touch $LOG_FILE
mkdir -p $LOCAL_SAVE

#######################################
# 工具函数
#######################################
log() {
    echo "[$(date '+%F %T')] $*" >> "$LOG_FILE"
}

remote_df() {
    ssh -4 -i "$SSH_KEY" "${REMOTE_USER}@${REMOTE_HOST}" df -h -x tmpfs -x devtmpfs >> "$LOG_FILE" \
    || log "WARN: ssh failed to retrieve remote disk usage"
}

send_report_mail() {
    {
    echo "Subject: auto backup report ${NOW}"
        echo
        cat "$LOG_FILE"
    } | msmtp "${MAIL_TO[@]}"
}

#######################################
# 核心备份函数

backup_do() {
    ......
}

# 清理旧备份
cleanup_old() {
    ......
}

#######################################
# suit for your web root 
# --------
# 待执行的备份项,及调用执行
# 
# each backup execution is called by backup_do(...) with the following 5 args:
#
# site_name="blog.path8.net" # also used as prefix of ...tar.gz file-name
# site_src="/var/www/html/blog.path8.net" # path your web
# site_dir="./html" # the dir in site_src to be archived
# cfg_excludes=( # exclude patterns
# './html/upload'
# )
# savedir=$LOCAL_SAVE # save tar.gz to
# backup_do "$site_name" "$site_src" "$site_dir" "$savedir" cfg_excludes[@]
#######################################

#
site_name="blog.path8.net"
site_src="/var/www/html/blog.path8.net"
site_dir="./html"
cfg_excludes=(
    './html/wp-content/upgrade'
    './html/wp-content/wflogs'
    './html/wp-content/uploads/20[01]*'
    './html/wp-content/uploads/202[0-4]'
    './html/wp-content/uploads/2025/0[0-9]'
)
savedir=$LOCAL_SAVE
backup_do "$site_name" "$site_src" "$site_dir" "$savedir" cfg_excludes[@]

#
site_name="www.path8.net"
site_src="/var/www/html/www.path8.net"
site_dir="./html"
cfg_excludes=(
    './html/wp-content/upgrade'
    './html/wp-content/wflogs'
    './html/wp-content/uploads/20[01]*'
    './html/wp-content/uploads/202[0-4]'
    './html/wp-content/uploads/2025/0[0-9]'
)
savedir=$LOCAL_SAVE
backup_do "$site_name" "$site_src" "$site_dir" "$savedir" cfg_excludes[@]


##############################################################################
# 
# /etc/my.cnf.d/backup_user.cnf
# user to run mysqldump,(at least: SELECT, LOCK TABLES, SHOW VIEW ) , eg.
# [client]
# user=db_backup
# password=backup-user-passwd
# host=localhost
# port=3306
#
#######################################

cleanup_mysqldump() {
    ...
}

mysqldump_do() {
    ...
}

# 调用部分
site="site1_db"
dbs="blog"
outdir=$LOCAL_SAVE
mysqldump_do "$outdir" "$site" "$dbs"


site="site8_db"
dbs="mydb1 mydb2 mydb3"
outdir=$LOCAL_SAVE
mysqldump_do "$outdir" "$site" "$dbs"



#######################################
# retrieving remote disk usage
#######################################

log ""
log "retrieve remote disk usage"
remote_df
log ""


send_report_mail

log "All done."

使用

要求必须使用 bash 调用本脚本, 不再参数调用,是快速备份,即排除指定的路径;加 –full 参数则是忽略排除路径

bash <this-script.bash>
bash <this-script.bash> --full

基础配置

设置时区TZ,生成日期字符串,用于,备份文件名、日志等。

配置日志文件路径 LOG_FILE, 本地备份文件存储位置 LOCAL_SAVE

KEEP_FULL, KEEP_BRF 完整备份、快速备份,两者各自最多保留个数

异地存储服务器 ssh 用户

备份文件传送到远程服务器上实现异地备份,需要指定一个 ssh 用户(REMOTE_xxx 的参数),通过 ssh-key 登录 (SSH_KEY 的路径)。这里要通过 ssh-key 免密码登录。

MySQL备份用户

给MySQL配置一个用于备份的用户,至少需要 SELECT, LOCK TABLES, SHOW VIEW 三个权限,用户登录信息写到 /etc/my.cnf.d/backup_user.cnf 文件(它就是 mysql 配置文件格式,很直观),mysqldump 命令会读取这个文件里的配置;而不要把用户名、密码写到脚本里。

基于 msmtp 的邮件接口

配置 MAIL_TO 变量,备份完成后,脚本会把日志文件发的内容邮件给这个邮箱。邮件由脚本里的 send_report_mail 函数发送,调用的是  msmtp ,这是个第三方工具,通过其他的 smtp 服务(如 Gmail)发送邮件,要另外安装并配置好,在这里直接调用。

接收可以与发送邮箱相同,对于小规模应用本来也没必要专门开设一个发邮件的账户。

完整脚本

backup_web_html_db.v251224.bash.txt

编写历程

这一节只是随手杂记,可以无视忽略。

脚本的初稿为手工所写,只是使用 tar 打包 web目录(带 –exclude 参数),并调用 scp 传送备份文件 的极其简陋的脚本,因为包含了多个站点,逻辑是完全重复的,所以通过 chatGPT 重构一下,然后再做了些进一步细节改进。

重构要求的提示词如下

评估并重构 bash 脚本,要求

1 使用 tar 打包目录,一个脚本中会有多条打包命令,要封装成函数,方便复用
2 使用 tar 的 --exclude 参数,排除一系列目录,排除的路径以 ./ 开头
3 脚本要同时支持排除或不排除,通过开关变量指定是否开启排除功能
4 打包的 tar 包文件与源文件一致,不做排除的备份文件名后带不同的后缀,以方便区分
5 打包的 tar 包文件默认存储在一个指定的目录中,对每个备份目录做调用时,允许修改该目录的定义
6 每个目录备份完成后通过 scp 复制到远程服务器上,然后本地目录最多只保留最近一个完整备份、及若干个有排除目录的简化备份,删除超过允许数量的旧备份
7 把备份过程中的简报写入本地日志文件,同时使用 ssh 远程调用 df -h 命令,把远程服务器的磁盘使用报告写入本地日志,

把重构结果交给 gemini 做检查验证,再针对性修改,主要是日志格式、内容,文件统计,核实一些细节风险等,增加邮件通知方案等。大体成型后,复用相关函数,改写了个 mysqldump 备份的逻辑,并进一步打磨了结节。再整理脚本,写为此文。

 

 

Last Updated on 2025/12/24

发表评论

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理