How to Make a USB Drive Back Up Automatically When Plugged In (A Cold Backup That Lives in a Drawer)

The nightly backup drive (23) is always connected, so anything that can wipe the server — ransomware, a bad script, a lightning strike — can reach it too. The off-site copy (54) is slow to restore. In between sits the cold backup: a USB drive that's plugged in once a month, backed up to, and put back in a drawer. The chore is remembering the commands; a udev rule removes it. Plug the drive in; the server mounts it, runs the backup, pings your phone, unmounts. Pull it out.
Quick reference
| Piece | What |
|---|---|
| Identify the drive | sudo blkid → its UUID (or label COLD1) |
| udev rule | /etc/udev/rules.d/99-cold-backup.rules — on that UUID, start a service |
| Service | cold-backup@.service mounts, runs the script, unmounts |
| Script | restic (55) to a repo on the drive, or rsync -a --delete |
| Notify | ntfy (93) at start and finish |
| Two drives | COLD1 / COLD2 alternating; one always in the drawer |
1. Prepare the drive
Format it ext4 with a label (LUKS first if you want it encrypted, 167):
sudo mkfs.ext4 -L COLD1 /dev/sdc1
sudo blkid /dev/sdc1 # note the UUID
sudo mkdir -p /mnt/cold
Don't put it in fstab — the rule will mount it.
2. The backup script
sudo nano /usr/local/bin/cold-backup.sh
#!/bin/bash
set -euo pipefail
DEV="/dev/disk/by-uuid/$1"
MNT=/mnt/cold
NTFY="https://ntfy.example.com/server"
source /etc/ntfy.env # NTFY_TOKEN
notify() { curl -s -H "Authorization: Bearer $NTFY_TOKEN" -H "Title: Cold backup" -d "$1" "$NTFY" >/dev/null; }
mount "$DEV" "$MNT"
notify "Started on $(blkid -s LABEL -o value "$DEV")"
export RESTIC_REPOSITORY="$MNT/restic" RESTIC_PASSWORD_FILE=/root/restic-cold.pw
[ -d "$MNT/restic" ] || restic init
restic backup /home /etc /var/www /home/john/docker /mnt/data/photos --exclude-caches --quiet
restic forget --keep-monthly 12 --prune --quiet
restic check --read-data-subset=5% --quiet
sync
umount "$MNT"
notify "✅ Done. Safe to unplug. $(df -h "$DEV" 2>/dev/null | tail -1 | awk '{print $4 " free"}')"
sudo chmod +x /usr/local/bin/cold-backup.sh. The repo password in /root/restic-cold.pw (chmod 600) — and on paper, since this drive is for the day everything else is gone (159). For a simpler mirror, replace the restic lines with rsync -a --delete /mnt/backup/ "$MNT/" — it then holds a copy of the nightly backup folder.
3. The systemd service
A templated unit so the UUID comes from udev:
sudo nano /etc/systemd/system/cold-backup@.service
[Unit]
Description=Cold backup to USB drive %i
After=local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/cold-backup.sh %i
TimeoutStartSec=0
sudo systemctl daemon-reload.
4. The udev rule
sudo nano /etc/udev/rules.d/99-cold-backup.rules
ACTION=="add", SUBSYSTEM=="block", ENV{ID_FS_UUID}=="paste-the-uuid-here", TAG+="systemd", ENV{SYSTEMD_WANTS}="cold-backup@paste-the-uuid-here.service"
(udev can't run long commands itself — it hands off to systemd, which is why the service exists.) A second line with a second UUID for COLD2.
sudo udevadm control --reload-rules
5. Test it
Plug the drive in. Within seconds: "Started on COLD1" on the phone; journalctl -u cold-backup@* -f shows restic working; "Done. Safe to unplug." Pull it out. Put it in the drawer. Next month, the other drive.
First run copies everything (hours for photos); later runs only changes — restic dedups against the repo on that drive.
6. Why two drives
One is always offline. If the server is compromised while COLD1 is plugged in, COLD2 in the drawer is untouched. Label them with the month; the restic forget --keep-monthly 12 gives a year of monthlies on each.
Hygiene
- The drive's repo password is separate from the main restic password — if the main one leaks, the cold copy still needs its own.
- restic check --read-data-subset reads a slice each time, so a dying drive is noticed before you need it (and SMART, 56, works on USB with -d sat).
- A plug-in meter or Scrutiny (134) can't see a drive in a drawer; spin it up once a quarter even if you skip the backup.
Troubleshooting
Nothing happens on plug-in. udevadm monitor while plugging: does the UUID appear? Rules reload done? systemctl status cold-backup@UUID.
"already mounted" / busy on unmount. A previous run left it; umount /mnt/cold by hand, check lsof +D /mnt/cold.
Notify never fires. /etc/ntfy.env unreadable by root, or the token.
Slow. USB 2 port or a hub; use USB 3 (blue) directly. An SSD in an enclosure is faster and quieter than a spinning drive.
Wrapping up
A labelled drive, a script, a templated service, one udev line. Plug it in, wait for the buzz, pull it out, drawer. Two drives alternating, and the backup that no attacker can reach exists without you ever typing a command.
