想要插上 U 盘就自动把重大文件备份到服务器/ NAS?别再手动复制了——本篇教大家在 Linux 上用 udev + systemd + rsync 实现「插入即备份」:零交互、日志可查、安全可控。步骤清晰、命令可复制粘贴,适合家庭服务器或工作站自动化备份小方案。
一、方案概览(用一句话)
当系统检测到 USB 存储设备插入 时,udev 触发 systemd 模板服务,调用备份脚本把 U 盘内容增量 rsync 到服务器上的备份目录,并记录日志与状态。

二、适用场景与准备
适合:Linux 桌面、家庭 NAS、个人服务器(Ubuntu/Debian/CentOS/Alma 等)
必备:
- rsync、blkid、lsblk、mount(大多数发行版已自带)
- root 权限(写入 /etc/udev、/etc/systemd/system)
- 一个备份目标目录(例如 /srv/usb-backups 或挂载的网络磁盘 /mnt/backup)
- 推荐:为备份主机设置足够磁盘空间并定期清理

三、实现流程(文件会放在这些位置)
- 备份脚本:/usr/local/bin/usb-backup.sh
- systemd 模板单元:/etc/systemd/system/usb-backup@.service
- udev 规则:/etc/udev/rules.d/99-usb-backup.rules
- 日志查看:journalctl -u usb-backup@<DEV>.service
四、一步步部署(复制粘贴即可)
1)创建备份目标目录并设置权限
把备份放在服务器本地目录或已挂载的网络盘(例如 /mnt/backup)。示例用 /srv/usb-backups:
sudo mkdir -p /srv/usb-backups
sudo chown –reference=/root /srv/usb-backups # 可改为某个非 root 用户
sudo chmod 750 /srv/usb-backups
2)写备份脚本
/usr/local/bin/usb-backup.sh
把下面脚本保存为
/usr/local/bin/usb-backup.sh,并 chmod +x。脚本做事:拿到设备(例如 /dev/sdb1),读取 LABEL/UUID,临时挂载到 /tmp/usb-mount-<dev>.<ts>,用 rsync -aHAX –delete 增量同步到目标目录下以 LABEL || UUID || devname 命名的子目录,最后卸载并记录日志。脚本对异常做超时保护与返回码。
#!/usr/bin/env bash
# /usr/local/bin/usb-backup.sh
set -euo pipefail
DEVNAME=”$1″ # expect e.g. sdb1 (systemd will pass instance)
DEV=”/dev/${DEVNAME}”
LOGPREFIX=”[usb-backup ${DEV}]”
# Config
BACKUP_ROOT=”/srv/usb-backups”
MOUNT_BASE=”/tmp/usb-mount”
RSYNC_OPTS=(-aHAX –delete –info=progress2 –exclude 'lost+found' –partial –partial-dir=.rsync-partial)
# Timeout for mount/rsync operations (seconds)
OP_TIMEOUT=600
# Helper: get filesystem label or uuid fallback
get_label_or_uuid(){
local dev=”$1″
local label uuid
label=$(blkid -s LABEL -o value “$dev” 2>/dev/null || true)
uuid=$(blkid -s UUID -o value “$dev” 2>/dev/null || true)
if [[ -n “$label” ]]; then
echo “${label}”
elif [[ -n “$uuid” ]]; then
echo “${uuid}”
else
# fallback to device name
echo “${dev##*/}”
fi
}
# Ensure device exists and is a block device
if [[ ! -b “$DEV” ]]; then
echo “$LOGPREFIX device $DEV not found or not a block device” >&2
exit 2
fi
# Only handle removable USB filesystem partitions with type
id_bus=$(udevadm info –query=property –name=”$DEV” | awk -F= '/ID_BUS=/{print $2}')
id_fs_type=$(udevadm info –query=property –name=”$DEV” | awk -F= '/ID_FS_TYPE=/{print $2}')
if [[ “$id_bus” != “usb” ]] || [[ -z “$id_fs_type” ]]; then
echo “$LOGPREFIX skip device: bus=$id_bus fs_type=$id_fs_type” >&2
exit 3
fi
LABEL=$(get_label_or_uuid “$DEV”)
TS=$(date +%F_%H%M%S)
MOUNTPOINT=”${MOUNT_BASE}/${DEVNAME}_${TS}”
BACKUP_TARGET=”${BACKUP_ROOT}/${LABEL}_${TS}”
mkdir -p “$MOUNTPOINT”
chown root:root “$MOUNTPOINT”
chmod 700 “$MOUNTPOINT”
echo “$LOGPREFIX Mounting $DEV to $MOUNTPOINT”
# mount with timeout
if ! timeout “${OP_TIMEOUT}” mount -o ro,noexec,nodev,nosuid “$DEV” “$MOUNTPOINT”; then
echo “$LOGPREFIX Mount failed or timeout” >&2
rmdir “$MOUNTPOINT” 2>/dev/null || true
exit 4
fi
echo “$LOGPREFIX Starting rsync to $BACKUP_TARGET”
mkdir -p “$BACKUP_TARGET”
# Run rsync with timeout to avoid hung jobs
if ! timeout “${OP_TIMEOUT}” rsync “${RSYNC_OPTS[@]}” “$MOUNTPOINT/” “$BACKUP_TARGET/” ; then
echo “$LOGPREFIX rsync failed or timeout” >&2
# attempt umount
umount “$MOUNTPOINT” 2>/dev/null || true
rmdir “$MOUNTPOINT” 2>/dev/null || true
exit 5
fi
echo “$LOGPREFIX Sync complete. Unmounting”
umount “$MOUNTPOINT” || { echo “$LOGPREFIX umount failed, trying lazy umount”; umount -l “$MOUNTPOINT” || true; }
rmdir “$MOUNTPOINT” 2>/dev/null || true
# Optional: create a 'latest' symlink for easy access
ln -sfn “$BACKUP_TARGET” “${BACKUP_ROOT}/${LABEL}_latest”
echo “$LOGPREFIX Done. Backup at $BACKUP_TARGET”
exit 0
保存后:
sudo chmod +x /usr/local/bin/usb-backup.sh
说明:脚本以只读方式挂载 U 盘(-o ro)以防误写;rsync 用 –delete 做镜像(如需保留旧文件请去掉 –delete 或调整策略)。
3)创建 systemd 模板单元
/etc/systemd/system/usb-backup@.service
把下面文件写入,然后 reload systemd:
[Unit]
Description=USB Backup for %I
Requires=dev-%i.device
After=dev-%i.device
[Service]
Type=oneshot
# Pass instance name like sdb1; script expects device name without /dev/
ExecStart=/usr/local/bin/usb-backup.sh %i
TimeoutStartSec=900
Nice=10
# avoid running multiple simultaneous backups for same device
[Install]
WantedBy=multi-user.target
保存后:
sudo systemctl daemon-reload
4)写 udev 规则
/etc/udev/rules.d/99-usb-backup.rules
规则要筛选出 USB 总线且为分区且带文件系统 的情况,并使用 ENV{SYSTEMD_WANTS} 启动 systemd 模板服务(实例名是设备名如 sdb1):
# /etc/udev/rules.d/99-usb-backup.rules
# Trigger systemd service usb-backup@<dev>.service on USB partition add
SUBSYSTEM==”block”, ACTION==”add”, ENV{ID_BUS}==”usb”, ENV{ID_FS_TYPE}!=””, KERNEL==”sd?1″, ENV{SYSTEMD_WANTS}=”usb-backup@%k.service”
说明:
- KERNEL==”sd?1″:只匹配分区(如 sdb1),避免在原始盘(sdb)上触发。根据你的设备可能需要调整(列如 sd[a-z][0-9]*)。
- 若你的设备分区编号不同或多分区可调整 KERNEL==”sd*[0-9]*”。
写好后重载 udev:
sudo udevadm control –reload
sudo udevadm trigger –action=add
五、测试流程(安全步骤)
- 插入 U 盘(系统会识别分区,列如 /dev/sdb1)。
- 查看是否启动了服务:
sudo journalctl -f
# or
sudo systemctl status usb-backup@sdb1.service
- 日志里会显示挂载、rsync 进度与结果。也可查看 /srv/usb-backups/ 是否生成新目录。
- 若要人工触发(不插盘),可以直接运行:
sudo /usr/local/bin/usb-backup.sh sdb1
# 或用 systemd 启动同样的单元(假设 /dev/sdb1 存在)
sudo systemctl start usb-backup@sdb1.service
六、常见问题与排查(快速查表)
- 服务未触发?
- udevadm monitor –environment –udev 插入设备观察 udev 事件。
- udevadm info –query=all –name=/dev/sdb1 查看 udev 属性(是否有 ID_BUS=usb 与 ID_FS_TYPE)。
- sudo udevadm test /sys/block/sdb/sdb1(或对应 sys path)查看规则匹配情况。
- rsync 挂起或超时?
- 看 journalctl -u usb-backup@sdb1.service 日志,增加 OP_TIMEOUT 值或检查网络备份目标(若是远程挂载)。
- 权限问题(备份目标不可写)?
- 确认 /srv/usb-backups 的拥有者/权限允许 systemd 服务写入(默认 root 运行)。
- 想对某些 U 盘跳过备份?
- 在 udev 规则里加条件:例如 ENV{ID_SERIAL}!=”YourSerialHere” 或在脚本中检测 LABEL/UUID 后退出。
七、扩展功能(选配)
- 自动解密/解锁 LUKS 分区:脚本可先尝试 cryptsetup 解锁(谨慎,需交互或 keyfile)。
- 备份到远程:把 BACKUP_ROOT 指向已挂载的 NFS/SMB 或直接用 rsync 推到远端 rsync:///SSH(记得用 keyauth)。
- 仅备份特定目录:在脚本里用 include/exclude 控制 rsync(如只备 Documents 目录)。
- 排队/去重:若多盘频繁插入,改用 systemd 服务配合锁文件避免并发写入到同一目标。
- Windows 替代:在 Windows 上可用 USBDeview + 任务计划或商业工具 USBDLM 触发脚本;也可用 PowerShell 结合 Task Scheduler 监听驱动器插入事件(超出本篇范围)。
八、撤销启用或卸载
若要移除自动备份:
sudo rm /etc/udev/rules.d/99-usb-backup.rules
sudo systemctl daemon-reload
sudo rm /etc/systemd/system/usb-backup@.service
sudo rm /usr/local/bin/usb-backup.sh
sudo udevadm control –reload
九、安全与备份策略提醒(务必阅读)
- 先备份重大数据:脚本/规则变更前请做好现有数据备份。
- 权限最小化:若不想以 root 写入目标目录,可创建专门用户并把 systemd 服务用 User= 指定运行(需保证可以挂载/读 U 盘或提前通过 polkit 设置)。
- 验证恢复流程:自动备份只是半步,定期从备份目录恢复一次文件以验证可用性。
- 日志监控:把 journalctl 输出或脚本日志推送到监控系统(邮件/Slack/企业微信)以便异常告警。















暂无评论内容