rsync 是最稳的小型备份方案:传输层 SSH 已加密,增量算法只传 delta,
配合 --link-dest 可以在目标侧做"硬链接快照"——每个快照看起来像
完整目录,磁盘占用却只算改动量。
适用场景:单机或少量机器的备份目标是另一台 Linux 主机 / NAS。
量大或对 dedup 要求高时换 Restic / Borg。
备份脚本
#!/usr/bin/env bash
# /usr/local/sbin/snap-backup.sh
set -euo pipefail
SRC="/srv/app /var/log /etc"
DEST_HOST="[email protected]"
DEST_BASE="/volume1/backups/$(hostname -s)"
STAMP="$(date +%Y%m%d-%H%M%S)"
LATEST="${DEST_BASE}/latest"
NEW="${DEST_BASE}/${STAMP}"
ssh "${DEST_HOST}" "mkdir -p '${DEST_BASE}'"
rsync -aAXH --delete --numeric-ids \
--link-dest="${LATEST}" \
--rsync-path="ionice -c 3 rsync" \
--info=stats2,progress2 \
${SRC} "${DEST_HOST}:${NEW}/"
ssh "${DEST_HOST}" "rm -f '${LATEST}' && ln -sfn '${STAMP}' '${LATEST}'"
# 保留最近 14 个快照
ssh "${DEST_HOST}" "
cd '${DEST_BASE}' \
&& ls -1 | grep -E '^[0-9]{8}-[0-9]{6}\$' | sort | head -n -14 \
| xargs -r -I{} rm -rf -- {}
"
关键参数:
-aAXH:等价于-rlptgoD+ 保留 ACL、xattr、硬链接关系--numeric-ids:用数字 UID/GID 而不是名字,跨机器一致性更好--link-dest:与上一次快照做硬链接,未改的文件几乎不占空间--rsync-path="ionice -c 3 rsync":远端 rsync 进程降到 idle I/O,
备份时段不影响其它服务
校验
# 远端校验 checksum 是否匹配(慢,每月一次足够)
rsync -aAXH --dry-run --checksum --itemize-changes \
${SRC} "${DEST_HOST}:${LATEST}/" | head -20
# 任何输出都意味着源 vs 备份不一致,需要排查
SSH 配置
避免脚本里硬编码密钥路径,统一在 SSH config:
# ~/.ssh/config(或 /root/.ssh/config)
Host nas.example.com
User backup
IdentityFile ~/.ssh/id_backup_ed25519
IdentitiesOnly yes
NAS 上限制这个 key 只能跑 rsync:
# 远端 ~backup/.ssh/authorized_keys
command="rsync --server -vlogDtprAXe.iLsfxC --numeric-ids --delete --link-dest=* . /volume1/backups/*",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA...
systemd timer
# /etc/systemd/system/snap-backup.timer
[Timer]
OnCalendar=*-*-* 02:00:00
RandomizedDelaySec=30m
Persistent=true
[Install]
WantedBy=timers.target
踩过的坑
--link-dest路径必须是 目标侧 的绝对路径,而且当时已存在
上一次快照目录;第一次跑没快照时 link-dest 自然失效,rsync 会回退到
完整拷贝,正常。- 备份
/etc不开-H时,sudoers / cron / 各种 symlink 容易脱钩,
恢复时一头雾水。 --delete是双刃剑:源被误删后下次备份会同步删掉目标。所以快照轮转
保留多个版本很重要。
登录后参与评论。