利用树莓派搭建VPS异地备份系统(18/03/10更新修复Bug)
前言
本来入手树莓派的初衷就是用来做VPS的异地备份系统,经过一(ji)段(tian)时间的测试,总算是比较正常的工作了。
于是放出来给想用的朋友玩玩,如果遇到什么问题可以在本文评论。
整套系统基于Linux+Crontab+vsftp+lftp来构建。
注:本文脚本内包含大量压缩、下载、删除、计算MD5等操作,若您使用的VPS对CPU占用、磁盘占用、网络占用有要求,请酌情使用。
另注:建议在不了解Shell的情况下谨慎修改,以防数据丢失。在您使用前,大D建议您备份好VPS/云主机及运行本文所提到的脚本的所有主机,以免由于环境差异导致数据丢失/数据被意外删除等情况。若出现问题,一切后果与责任自行承担,大D不承担任何相关责任。
本文所用代码,除本文外,均在Github开源。项目地址:https://github.com/derek-s/VPSBackup-Shell
正文
0.简述工作原理
先对数据库和全站数据进行压缩,每周一全站压缩时会创建一个快照,周二会根据周一快照压缩新文件,以此类推。
压缩完毕之后,会向网站所在目录写入一个可访问文件,用于树莓派联网检测压缩数据是否压缩完毕可以下载。
当运行在树莓派上的定时任务检测到网站网页上的信息之后,则启动下载,下载完成之后比对MD5值,比对成功则删除VPS上的对应文件,当全部文件下载完毕,比对正确后向VPS主机上传文件,VPS主机上另外开一个定时任务,检测标志着树莓派下载完毕的文件是否存在,存在时则将显示压缩状态的网页重置,则下载脚本检测不到,不会重复下载,也不会重复运行lftp进行连接,最大程度节省资源。
如果您有其他更简便的备份思路,欢迎本页评论区留言。
1.环境搭建
由于树莓派是在家中内网放置,没有固定IP,思来想去,还是把ftp架在服务器上。
加密ftp搭建可以参考大D以前写的文章 Vsftpd搭建SSL/TLS安全FTP
2.配置VPS端备份脚本
搭建完毕之后,将备份脚本根据自己的实际情况进行修改,同时加入Crontab定时任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
#!/bin/sh #####树莓派异地备份服务器端脚本 V0.4##### #2018-03-06 #基础数据 MYSQL_USER=#数据库用户名 例:dbuser MYSQL_PASS=#数据库密码 例:123456 WEB_DATA=#Web文件目录 例:/var/www PCH_DATA=#如果需要排除备份某文件夹(例如缓存文件夹等) 例:/var/www/wp-content/cache Backup_local_DIR=#备份文件存储位置 例:/home/backup #增量备份快照文件 Backup_snap=${Backup_local_DIR}/Backup.snap #输出运行时间到log文件 date >> ${Backup_local_DIR}/hk_backup_run.log #备份文件文件名 DataBakName=Data_$(date +%Y%m%d).tar.gz WebBakName=Web_$(date +%Y%m%d).tar.gz MD5File=MD5_$(date +%Y%m%d).md5 #备份开始时将备份状态标志置为False echo "False" > #备份状态标志位置 必须是可访问地址 该行示例:echo "False" > /var/www/status.html rm -f ${Backup_local_DIR}/FileName #每周一进行整体备份 if [ $( date +%u ) -eq "1" ] then echo "\033[03m Monday delete Snap File \033[0m" rm -f ${Backup_snap} echo "$(date +%Y%m%d) rm SnapFile" >> ${Logfile} fi #压缩备份数据库 cd ${Backup_local_DIR} echo "\033[31m Export database \033[0m" for db in `/usr/local/mysql/bin/mysql -u$MYSQL_USER -p$MYSQL_PASS -B -N -e 'SHOW DATABASES' | xargs`; do (/usr/local/mysql/bin/mysqldump -u$MYSQL_USER -p$MYSQL_PASS ${db} | gzip -9 - > ${db}.sql.gz) done echo "\033[31m Compressed database \033[0m" tar vzcf $Backup_local_DIR/$DataBakName $Backup_local_DIR/*.sql.gz rm -f $Backup_local_DIR/*.sql.gz #压缩全站文件 echo "\033[31m Compressed Files \033[0m" tar -g ${Backup_snap} -pzcf $Backup_local_DIR/$WebBakName --exclude=$PCH_DATA $WEB_DATA #如果不需要排除路径,将 --exclude=$PCH_DATA 删除 #每周一进行全站备份时对备份文件进行分卷 if [ $( date +%u ) -eq "1" ] then echo "\033[03m Split File \033[03m" BackupFileSize=`ls -l $Backup_local_DIR/$WebBakName | awk '{ print $5 }'` SplitMB=500 #分卷大小 单位MB SplitBype=`expr $SplitMB \* 1024` SplitBit=`expr $SplitBype \* 1024` SplitFileNum=`expr $BackupFileSize / $SplitBit` if [ `expr $BackupFileSize % $SplitBit` -ne 0 ] then SplitFileNum=`expr $SplitFileNum + 1` fi i=1 SkipBype=0 while [ $i -le $SplitFileNum ] do echo "$WebBakName"_"$i" >> FileName dd if=$WebBakName of="$WebBakName"_"$i" bs=1024 count=$SplitBype skip=$SkipBype md5sum "$WebBakName"_"$i" >> $MD5File i=`expr $i + 1` SkipBype=`expr $SkipBype + $SplitBype` done md5sum $DataBakName >> $MD5File echo $DataBakName >> FileName rm -f $WebBakName fi rm -f ${Backup_local_DIR}/BackupDone if [ $( date +%u ) -ne "1" ] then echo ${DataBakName} >> FileName echo ${WebBakName} >> FileName md5sum ${DataBakName} ${WebBakName} > ${MD5File} fi echo ${MD5File} >> FileName chown vpsback:ftpgroup -R ${Backup_local_DIR} #使用时将 vpsback:ftpgroup 替换成自己的FTP用户名和用户组 用户名:用户组 echo "ok" > #将标志位设置为ok 必须是可访问地址 该行示例:echo "ok" > /var/www/status.html echo "Backup complete" |
简单说明:
1.该脚本会导出并压缩数据库数据,网站文件数据是每周一进行全体备份,周二-周日增量备份。网站文件备份会分卷,以避免网络波动下载失败长时间重复下载占用带宽。
2.数据库及网站文件数据均在压缩后计算MD5,下载到树莓派挂载硬盘上后也对文件计算MD5,以确定文件是否损坏。如遇损坏,则重新下载(损坏下载重试限制为10次)。
3.由于目前大D自己的VPS数据库压缩体积过大,不适用邮箱备份,就没有添加将数据库文件发送到邮箱的功能。
4.有排除目录压缩,如果不需要对缓存目录等进行排除,需要注意修改备份脚本的代码。
5.其他修改的地方都备注在脚本内了。
1 2 3 4 5 6 7 8 9 10 11 |
#!/bin/bash BackPath=#备份文件地址 需与backup-pai内一致 date >> ${BackPath}/hk_check_log.log backstatus=`cat ${BackPath}/BackupDone` if [ "$backstatus" == done ] then echo "False" > #备份状态标志位置 必须是可访问地址 该行示例:echo "False" > /var/www/backstatus.html 需与backup-pai内一致 fi |
VPS端脚本修改完之后,增加计划任务。
终端下执行:crontab -e
1 2 |
0 0 * * * backup-pai.sh 0,30 * * * * check.sh |
根据脚本位置自行修改。
3.配置树莓派
在测试脚本的过程中,经常出现lftp在下载到100%且文件实际已经下载完成之后,仍然持续连接且在debug 3
模式下持续报错,为了解决这个问题花了一点时间。
最后发现,是树莓派上运行的OMV的软件源内lftp 4.6.0的bug,这个bug在lftp的github上也找到了相关的issues,就不具体贴出来了。
首先第一点就是要确定你使用的lftp的版本,请安装新版。
如何检查lftp版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# lftp --version LFTP | Version 4.8.3 | Copyright (c) 1996-2017 Alexander V. Lukyanov LFTP is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with LFTP. If not, see <http://www.gnu.org/licenses/>. Send bug reports and questions to the mailing list <lftp@uniyar.ac.ru>. Libraries used: GnuTLS 3.3.8, Readline 6.3, zlib 1.2.8 |
3.1 编译安装新版lftp
大D自用的树莓派安装了OpenMediaVault(以下简称OMV),如果也是使用OMV的,则需要自行编译安装新版本的lftp,且在配置过程中,使用apt进行软件包安装时,一定要注意是否由于包关联而导致OMV被自动卸载。
下载新版lftp源码
1 2 3 4 5 6 7 |
wget http://lftp.yar.ru/ftp/lftp-4.8.3.tar.gz tar -xvf lftp-4.8.3.tar.gz cd lftp-4.8.3 ./configure make make install ln -s /usr/local/bin/lftp /usr/bin/lftp |
可能遇到的错误:configure: error: No terminfo, termcap or curses library found. Install ncurses-devel.
解决方法:
1 |
apt install libncurses5-dev |
可能遇到的错误:configure: error: cannot find readline library, install readline-devel package
The following packages have unmet dependencies:
libreadline6-dev : Depends: libreadline6 (= 6.3-8) but 6.3-8+b3 is to be installed
E: Unable to correct problems, you have held broken packages.
这个需要注意看一下具体的报错信息,可能会跟环境不同而需要不同的版本。
解决方法:
1 |
apt install libreadline6=6.3-8 libreadlin6-dev |
可能遇到的错误:configure: error: Package requirements (gnutls >= 1.0.0) were not met:
No package 'gnutls' found
解决方法:
1 |
apt install libgnutls28-dev |
配置lftp
1 2 3 4 5 6 7 8 9 10 11 12 |
vim /usr/local/etc/lftp.conf #插入以下配置 set net:limit-rate 102400:102400 set ftp:ssl-auth TLS-P set ftp:use-feat no set ssl:verify-certificate no set net:timeout 2 set net:max-retries 2 set net:reconnect-interval-base 1 set net:reconnect-interval-max 3 set net:reconnect-interval-multiplier 4 |
这里需要更改的只有第一项关于限速的。
1 2 3 4 5 6 |
set net:limit-rate 下行速度:上行速度 #例如需要将下载速度设置成 10k,下行20k #则 set net:limit-rate 10240:20480 #这里的限速只针对单线程,如果使用lftp的pget等多线程下载模式,则最大下载速度=线程数*限速值 |
3.2安装mutt及mstmp并配置邮件
安装mutt+mstmp
第一次直接使用apt安装mutt的时候,导致OMV被apt自动卸载。
所以如果你也使用OMV,则需要注意是否会导致自动卸载。
1 |
apt install mutt msmtp |
配置msmtp
1 2 3 4 5 6 7 8 9 10 |
vim ./.msmtprc #输入以下内容 account default host 你是用的邮箱smtp服务器地址 from 你的邮箱地址 auth plain user 你的邮箱地址 password 你的邮箱密码 logfile /var/log/msmtp.log |
大D使用了一个新注册的阿里邮箱来发送,一开始是使用QQ邮箱来发送的,极有可能会因为是代发邮件/邮件内容问题导致卡在QQ邮箱的草稿箱内无法发送。
由于密码明文保存,所以msmtp
对.msmtprc
文件权限有要求,所以编辑完之后,将文件权限修改为600 chmod 600 .msmtprc
配置完成之后,继续配置mutt
配置mutt
mutt需要配置的地方不多,只需要配置一个代发服务器即可。
1 2 3 4 5 |
vim ./.muttrc set sendmail="/usr/bin/msmtp" set use_from=yes set realname="RPi" set editor="vim" |
这个配置文件需要解释和修改的地方不多,一个是realname随便改一个名字,editor就是编辑器,根据个人喜好来修改即可。
3.3配置客户端脚本
下载脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#!/bin/bash #树莓派下载备份、验证、删除数据 #FTP工作信息 FTPServer=#vps地址,IP/域名 FTPUser=#ftp登陆用户名 FTPPass=#ftp登录密码 #工作路径 BackPath=#备份文件在树莓派上的存储路径 例:/mnt/vpsback date >> ${BackPath}/run_log.log rm -f ${BackPath}/FileName rm -f ${BackPath}/BackupDone #IDCName 用于邮件标题,可以自行更改 IDCName=VPSBackup_$(date +%Y%m%d) mailcontent=Mail_$(date +%Y%m%d) DataBakName=Data_$(date +%Y%m%d).tar.gz WebBakName=Web_$(date +%Y%m%d).tar.gz MD5FileName=MD5_$(date +%Y%m%d).md5 MAIL_TO=#邮箱地址 用于接收本脚本运行日志 date >> $mailcontent rm -f ${BackPath}/${MD5FileName} #获取远程服务器状态 backstatus=`curl ` #curl后跟backup-pai内设置的标志位访问位置,例如 curl http://www.abc.com/status.html cd ${BackPath} echo $backstatus echo $backstatus >> $mailcontent if [ "$backstatus" = "ok" ] then echo "Download FileName File" lftp "$FTPUser:$FTPPass"@"$FTPServer" << END get FileName quit END echo "download BackupFileName File done" >> $mailcontent for line in `cat FileName` do echo $line lftp "$FTPUser:$FTPPass"@"$FTPServer" << END get "$line" quit END done #rm -rf FileName cat $MD5FileName | while read -r line do ren=0 while [[ $ren -lt 10 ]] do MD5_Checkline=$(echo "$line" | md5sum -c) MD5_FileName=$(echo "$MD5_Checkline" | cut -d":" -f1) MD5_Status=$(echo "$MD5_Checkline" | awk '{print $2}') if [ "$MD5_Status" = OK ] then echo $MD5_Checkline >> $mailcontent lftp "$FTPUser:$FTPPass"@"$FTPServer" << END rm "$MD5_FileName" quit END break fi if [ "$MD5_Status" != OK ] rm -rf ${MD5_FileName} echo "delete $MD5_FileName" >> $mailcontent then echo "redownload $MD5_FileName" >> $mailcontent lftp "$FTPUser:$FTPPass"@"$FTPServer" << END get "$MD5_FileName" quit END fi ren=`expr $ren + 1` done done echo "done" > "$BackPath"/BackupDone date +%Y/%m/%d-%H:%M:%S >> $mailcontent echo "Backup complete" >> $mailcontent lftp "$FTPUser:$FTPPass"@"$FTPServer" << END put BackupDone rm "$MD5FileName" END echo "磁盘使用情况" >> $mailcontent df -lh $BackPath >> $mailcontent mutt $MAIL_TO -i $mailcontent -s "$IDCName 树莓派备份报告" rm -f $mailcontent fi |
根据注释内容修改即可。
启动脚本
由于下载脚本依赖系统计划任务,所以可能会出现下载较大备份文件超过计划任务间隔时间,导致重复启动脚本下载文件,VPS带宽被占满这种情况。
所以需要加一个启动脚本来使下载脚本始终是单例运行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#!/bin/bash LOCKFILE=#设置一个锁文件 路径需要带引号 例如 "/home/pi/vpsback/verify.tmp" trap 'echo "rm lockfile!";rm -f ${LOCKFILE}; exit' 1 2 3 9 15 if [ -f $LOCKFILE ] then echo "verify-pai.sh is Running!" exit 0 else touch $LOCKFILE chmod 600 $LOCKFILE echo "touch successed" verify-pai.sh #执行下载脚本 带路径 例如/home/pi/vpsback/verify-pai.sh echo "download complete" fi rm -f $LOCKFILE |
配置计划任务
1 |
0 */1 * * * start.sh > verify.log |
每间隔一小时运行一次。
结语
到这里就可以正常运行每天自动下载备份了。
邮件内包含部分节点操作的内容,同时还增加了备份路径所在磁盘的使用情况报告,可以根据情况来选择手动删除老旧备份或刻录光盘等方式来进行数据备份。
版本信息
2018-03-09 1.0版
2018-03-10 测试中发现频繁发送邮件,对发送邮件部分做了修改。1.1版
已有 7 条评论
发表评论
电子邮件地址不会被公开。 必填项已标注。
点赞大D!
一个完整的自运维系统了,很赞。
招聘时,这就是经验,从头到尾都是自己设计的。
以前依赖一台美帝VPS备份,后来不是忘记续费GG了,就入了树莓派。花了点时间搞了这个一整套备份系统。
这段时间自己用下来感觉还是可以,也挺稳定的。
不错不错,可以考虑把数据存在网盘上,现在存储也是便宜
网盘就算了,当年用过快盘,现在快盘已经GG了。
用过度娘盘,现在api接口限制的很死。能用网盘的话,也就不会搞自建的事儿了。
用谷大大盘,路由器架个楼梯
免费15G还和Mail共享,算了吧。升级到1T,每年99.99
还是1T硬盘更便宜。