一.在 Linux 本机安装 lftp
# CentOS / RHEL
yum install lftp -y
# Debian / Ubuntu
apt update && apt install lftp -y
二.创建配置文件 /etc/backup_ftp.conf:
vi /etc/backup_ftp.conf
1.确认要写入的内容
FTP_HOST=你的Windows_IP
FTP_USER=backup_user
FTP_PASS=你的密码
FTP_PORT=21
DING_WEBHOOK=https://oapi.dingtalk.com/robot/send?access_token=你的token
DING_KEYWORD=宝塔面板
DING_TITLE=备份异常
使用 vi 的操作流程:
进入插入模式
按一下键盘字母 i(左下角出现 -- INSERT -- 表示可以输入/粘贴)。
粘贴内容
直接把上面 4 行内容复制(Ctrl+C),然后到终端里右键 → 粘贴,或者 Shift+Insert 粘贴。
终端里会显示刚才的四行内容。
退出插入模式
按一下键盘 Esc 键(左下角 -- INSERT -- 消失)。
保存并退出
输入英文冒号 :,再输入 wq,然后回车。
完整命令是 :wq → 回车。
文件保存成功后会回到命令提示符。
如果想放弃编辑,按 Esc 后输入 :q! 回车。
2.设置文件权限(重要)
chmod 600 /etc/backup_ftp.conf
3.检查文件是否写入成功
cat /etc/backup_ftp.conf
三.备份脚本:
#!/bin/bash
source /etc/backup_ftp.conf
SRC1="/www/backup/database/mysql/crontab_backup/www_itingshu_net"
DST1="/mysql/www_itingshu_net"
SRC2="/www/backup/site/api.itingshu.iiisss.top"
DST2="/site/www_itingshu_net"
LOGFILE="/var/log/backup_to_win.log"
LOCKFILE="/var/run/backup_to_win.lock"
# ---- 每月清空一次日志 ----
THIS_MONTH=$(date +%Y%m)
LAST_CLEAN_FILE="/var/run/backup_to_win.clean_date"
if [ -f "$LAST_CLEAN_FILE" ]; then
LAST_MONTH=$(cat "$LAST_CLEAN_FILE")
else
LAST_MONTH="none"
fi
if [ "$THIS_MONTH" != "$LAST_MONTH" ]; then
: > "$LOGFILE"
echo "$THIS_MONTH" > "$LAST_CLEAN_FILE"
fi
exec 200>"$LOCKFILE"
flock -n 200 || {
echo "$(date '+%F %T') - 备份任务已在运行,跳过。" | tee -a "$LOGFILE"
exit 1
}
# 钉钉通知函数
ding_talk() {
local message="$1"
local title="${2:-${DING_TITLE}}"
local full_title="${DING_KEYWORD}${title}"
curl -s -X POST "$DING_WEBHOOK" \
-H "Content-Type: application/json" \
-d '{"msgtype":"actionCard","actionCard":{"title":"'"${full_title}"'","text":"'"${message}"'"}}' >/dev/null 2>&1
}
echo "$(date '+%F %T') - 开始 FTP 每日备份(仅上传最新 .sql.gz / .tar.gz)..." | tee -a "$LOGFILE"
# 上传每个本地目录中最新的一个符合条件的文件
upload_latest() {
local local_dir="$1"
local remote_dir="$2"
echo "[$(date '+%F %T')] 正在处理: $local_dir" | tee -a "$LOGFILE"
# 找出最新的 .sql.gz 或 .tar.gz 文件(按修改时间倒序,取第一个)
local latest_file
latest_file=$(find "$local_dir" -maxdepth 1 -type f \( -name "*.sql.gz" -o -name "*.tar.gz" \) -printf "%T@ %p\n" 2>/dev/null | sort -rn | head -1 | awk '{print $2}')
if [ -z "$latest_file" ]; then
echo "[$(date '+%F %T')] 未找到 .sql.gz 或 .tar.gz 文件,跳过: $local_dir" | tee -a "$LOGFILE"
return 0 # 不视作失败
fi
local fname
fname=$(basename "$latest_file")
echo "[$(date '+%F %T')] 准备上传: $fname -> $remote_dir/" | tee -a "$LOGFILE"
lftp -u "$FTP_USER","$FTP_PASS" -p "$FTP_PORT" "$FTP_HOST" <&1 | tee -a "$LOGFILE"
set ftp:ssl-allow no
mkdir -p "$remote_dir"
put "$latest_file" -o "$remote_dir/$fname"
quit
EOF
if [ ${PIPESTATUS[0]} -eq 0 ]; then
echo "[$(date '+%F %T')] 上传成功: $fname" | tee -a "$LOGFILE"
else
echo "[$(date '+%F %T')] 上传失败: $fname" | tee -a "$LOGFILE"
return 1
fi
}
FAIL=0
upload_latest "$SRC1" "$DST1" || FAIL=1
upload_latest "$SRC2" "$DST2" || FAIL=1
if [ $FAIL -eq 0 ]; then
echo "$(date '+%F %T') - 所有备份完成" | tee -a "$LOGFILE"
else
echo "$(date '+%F %T') - 部分备份失败,请检查日志" | tee -a "$LOGFILE"
ding_talk "备份任务执行异常,请登录服务器检查 /var/log/backup_to_win.log"
fi
exit $FAIL
四.宝塔计划任务设置:
类型:Shell 脚本
周期:每天(比如凌晨 3 点执行一次)
在计划任务里选择 “N 天” → 1 天,时间自定义。
脚本内容:
bash /www/backup_to_win.sh