用 crontab 给云服务器做自动备份:网站文件与 MySQL 每日备份实战
云服务器上跑着网站或小项目,最怕的不是宕机,而是误删文件、数据库被写坏之后发现没有备份。本文以 Flexus L 这类单机云服务器为例,用系统自带的 cron + tar + mysqldump,搭一套“每天自动备份、自动清理旧备份、出错能看到日志”的方案,全程不依赖第三方工具。
一、规划备份目录
先约定好目录,后面的脚本和清理逻辑都围绕它:
sudo mkdir -p /data/backup/{site,mysql,logs}
sudo chmod 700 /data/backup
/data/backup/site:网站文件压缩包/data/backup/mysql:数据库导出文件/data/backup/logs:备份脚本的运行日志
权限设为 700,避免其他用户读到数据库导出内容。
二、编写备份脚本
新建 /usr/local/bin/daily_backup.sh:
#!/usr/bin/env bash
set -euo pipefail
DATE=$(date +%F_%H%M)
BASE=/data/backup
SITE_DIR=/var/www/html
KEEP_DAYS=7
# 1. 打包网站文件
tar -czf "$BASE/site/site_$DATE.tar.gz" -C "$(dirname $SITE_DIR)" "$(basename $SITE_DIR)"
# 2. 导出数据库(账号信息放在 ~/.my.cnf,不写进脚本)
mysqldump --single-transaction --routines --all-databases | gzip > "$BASE/mysql/db_$DATE.sql.gz"
# 3. 清理超过 KEEP_DAYS 天的旧备份
find "$BASE/site" -name '*.tar.gz' -mtime +$KEEP_DAYS -delete
find "$BASE/mysql" -name '*.sql.gz' -mtime +$KEEP_DAYS -delete
echo "[$(date '+%F %T')] backup ok"
几个要点:
set -euo pipefail让任何一步出错就立即退出,避免“前面失败了还继续清理旧备份”这种最糟糕的情况。--single-transaction对 InnoDB 表做一致性快照,导出时不锁表,网站可以照常访问。- 数据库密码不要写进脚本,放在执行用户的
~/.my.cnf中,并chmod 600:
[client]
user=backup
password=请替换为你自己的密码
建议单独建一个只有 SELECT、LOCK TABLES、SHOW VIEW、TRIGGER 权限的 backup 账号,不要直接用 root。
赋予执行权限并手动跑一次:
sudo chmod +x /usr/local/bin/daily_backup.sh
sudo /usr/local/bin/daily_backup.sh
ls -lh /data/backup/site /data/backup/mysql
三、交给 cron 定时执行
sudo crontab -e 添加一行,每天凌晨 3:30 执行:
30 3 * * * /usr/local/bin/daily_backup.sh >> /data/backup/logs/backup.log 2>&1
cron 表达式五个字段依次是:分、时、日、月、星期。常见写法:
| 表达式 | 含义 |
|---|---|
30 3 * * * |
每天 03:30 |
0 */6 * * * |
每 6 小时整点 |
0 2 * * 0 |
每周日 02:00 |
*/10 * * * * |
每 10 分钟 |
四、cron 常见的三个坑
1. 环境变量不同。 cron 运行时 PATH 很短,手动能跑的脚本在 cron 里可能报 command not found。解决办法是在脚本开头写上 export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin,或者命令一律写绝对路径。
2. 时区不对。 云服务器默认可能是 UTC,凌晨 3 点会变成北京时间上午 11 点,正好是访问高峰。用 timedatectl 查看,必要时执行 sudo timedatectl set-timezone Asia/Shanghai,然后 sudo systemctl restart cron(CentOS 系为 crond)。
3. 静默失败。 不重定向输出的话,出错信息会被丢弃或发到本地邮箱,很难发现。上面的 >> backup.log 2>&1 就是为了把每次运行结果都留在日志里。可以用 grep -c "backup ok" /data/backup/logs/backup.log 快速核对成功次数,用 grep /usr/local/bin/daily_backup.sh /var/log/syslog(或 /var/log/cron)确认 cron 是否真的触发了。
五、备份要能恢复才算数
定期做一次恢复演练,确认备份文件不是空壳:
# 检查压缩包完整性
tar -tzf /data/backup/site/site_最新日期.tar.gz > /dev/null && echo site ok
gunzip -t /data/backup/mysql/db_最新日期.sql.gz && echo db ok
# 恢复数据库(谨慎操作,最好先在测试库上验证)
gunzip < /data/backup/mysql/db_最新日期.sql.gz | mysql
六、再进一步:异地保存
备份和网站放在同一块云盘上,一旦实例被误删或磁盘故障,备份也会一起丢失。条件允许的话,可以把每天的备份再同步到对象存储 OBS 或另一台机器上(例如用 rsync -az 推送到另一台服务器),形成“本机保留 7 天 + 异地保留 30 天”的两层策略。同时留意磁盘占用,可以用 du -sh /data/backup 定期查看,避免备份把系统盘写满。
小结
一个 20 行左右的脚本加一行 crontab,就能让云服务器拥有每日自动备份能力。关键是三件事:脚本出错立即停止、日志一定要留、定期做恢复演练。把这套流程配好,误删文件时就不会手足无措了。
- 点赞
- 收藏
- 关注作者
评论(0)