==== Backup with rsync ==== So, this is what I've been doing to make backups of machines for years, it stores permissions, and you can export the /Backup folder via NFS, then remap it to another folder as read-only so users can do their own restores if you want (not going into that here). The reason that the *.conf files start with 00 and 01 is just to set the order that things are backed up, the ''**for Script in *.conf**'' part below goes in lexical order.\\ \\ This is what I see in my /Backup folder with;\\ ''**ls -Al /Backup**''. total 64 drwxr-xr-x 12 root root 4096 2026-02-04+15:20:02 00-EFI -rw------- 1 root root 613 2024-08-27+11:29:00 00-EFI.conf drwxr-xr-x 12 root root 4096 2026-02-04+15:23:10 01-Root -rw------- 1 root root 605 2024-08-27+11:29:15 01-Root.conf drwx------ 2 root root 16384 2024-06-27+11:37:59 lost+found -rwx------ 1 root root 4489 2024-06-27+13:18:01 Snapshot -rwx------ 1 root root 333 2024-06-27+13:17:20 SystemBackup \\ Below is a short script that just runs the actual backup script with different sets of options for what goes where;\\ ''**sudo cat /Backup/SystemBackup**'' #!/bin/bash # make sure we're running as root if (( 0 != 0 )); then { echo "Sorry, must be root. Exiting..."; exit; } fi; # Run a backup for every .conf file in the /Backup directory cd /Backup for Script in *.conf do ./Snapshot ${Script} done # And send an e-mail with the list of Summaries; cat /Backup/*/Summary \\ The .conf script below that gets sourced by the backup script below that;\\ ''**sudo cat /Backup/01-Root.conf**'' # =-=-=-=-=-=- File locations and variables. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # Where to write the backups, begins with / only. SNAPSHOT_RW=/Backup/01-Root; # What directory to back up, begins and ends in /. SNAP_DIR="/"; # Where to store the list of files and directories that we backed up. FILELIST=$SNAPSHOT_RW/Filelist # Summary file, a short list of actions taken by rsync to complete the backup. SUMMARY=$SNAPSHOT_RW/Summary # Stuff not to back up, there is always stuff to not back up! EXCLUDES=$SNAPSHOT_RW/Excludes; # How many snapshot backups do we want to keep? Must be at least 2! NUM_SNAP=10; \\ Below is the actual script that calls rsync to do the backup, into a unique folder-by-date.\\ ''**sudo cat /Backup/Snapshot**'' #!/bin/bash # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # 2017-01-06-SRJ # For information on how this script works, and what it does, read the # file README in this folder # =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # # suggestion from H. Milz: avoid accidental use of $PATH unset PATH # # =-=-=-=- System commands used by this script. -=-=-=-=-=-=-=-= ID=/usr/bin/id; ECHO=/bin/echo; MOUNT=/bin/mount; RM=/bin/rm; MV=/bin/mv; CP=/bin/cp; TOUCH=/bin/touch; RSYNC=/usr/bin/rsync; DATE=/bin/date; WC=/usr/bin/wc; CAT=/bin/cat; TAIL=/usr/bin/tail; HEAD=/usr/bin/head; GREP=/bin/grep; CHMOD=/bin/chmod # =-=-=-=-=-=-=- Make sure we're running as root -=-=-=-=-=-=-=-=-= if (( `$ID -u` != 0 )); then { $ECHO "Sorry, must be root. Exiting..."; exit; } fi; # =-=-=-=-=-=-=-=-=-=- Read in the Variables -=-=-=-=-=-=-=-=-=-=-= if [ ! -e $1 ] ; then { $ECHO "No viable config file given."; exit 0 } fi; # If we're here, there must be a config file to read, the line below # reads the variables from that file into this bash environment. . $1 # # # Update 2017-01-01 SRJ The line above sources the variables from # # # the config file into this script - see /Backup/00-System.conf # # # for more information. # Make sure that the folder list exists, create it if needed; if [ ! -f $SNAPSHOT_RW/Backups ] ; then { $ECHO Nothing >> $SNAPSHOT_RW/Backups } fi; # The full name of the oldest snapshot, first line in Backups [ $($CAT $SNAPSHOT_RW/Backups | $WC --lines) -ge $NUM_SNAP ] && \ OLDEST=$($HEAD -1 $SNAPSHOT_RW/Backups) || OLDEST="Nothing" # The full name of the last snapshot, last line in Backups LAST=$($TAIL -1 $SNAPSHOT_RW/Backups) # The full name of the snapshot for this itteration. (2006-06-22-09-47) CURRENT=$SNAPSHOT_RW/$($DATE +%F-%H-%M) # What time is it, in seconds past the epoch? StartTime=$($DATE +%s) # Hour, minute, second function; _hms() { local S=${1} # this S is used only in this sub-routine ((h=S/3600)) # fills h with the integer of seconds / 3600 ((m=S%3600/60)) # fills m with the integer of the modula from above / 60 ((s=S%60)) # fills s with the integer of seconds / 60 printf "%02d:%02d:%02d\n" $h $m $s # print 2 digit zero padded numbers } # =-=-=-=-=-=-=-=-=- The script itself. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # I stopped mounting and unmounting the filesystem, I now do this by # hand on an as-needed basis - these backup scripts are now on the # backup drives themselves. # Attempt to remount the RO mount point as RW; else abort # $MOUNT -o remount,rw $MOUNT_DEVICE $MOUNT_DIR ; # if (( $? )); then { # $ECHO "Could not remount $MOUNT_DIR read-write"; exit; # } fi; # Creating the snapshot. # Delete the oldest snapshot, if it exists: if [ -e ${OLDEST} ] ; then { $RM -rf ${OLDEST} ;} fi ; # Delete the last filelist and create a new one with proper permissions. if [ -f $FILELIST ] ; then { $RM -f $FILELIST ;} fi ; $TOUCH $FILELIST ; $CHMOD 600 $FILELIST # Rsync from the system into the latest snapshot (notice that rsync # behaves like cp --remove-destination by default, so the destination is # unlinked first. If it were not so, this would copy over the other # snapshot(s) too! RSARGS=" --archive --verbose --delete --delete-excluded --numeric-ids \ --modify-window=1 --hard-links --one-file-system --acls --xattrs \ --exclude-from="$EXCLUDES" --link-dest=$LAST/ " # This is the line that does everything we're doing here... $RSYNC $RSARGS $SNAP_DIR $CURRENT >> $FILELIST; # Add today's snapshot to the list, and remove the oldest; $ECHO $CURRENT >> $SNAPSHOT_RW/Backups $GREP -v $OLDEST $SNAPSHOT_RW/Backups >> $SNAPSHOT_RW/$$.tmp $MV -f $SNAPSHOT_RW/$$.tmp $SNAPSHOT_RW/Backups EndTime=$($DATE +%s) ; ElapsedTime=$(( $EndTime - $StartTime )) TimeWellSpent=$( _hms ${ElapsedTime}) # Write out the summary file. $HEAD -2 $FILELIST > $SUMMARY; $ECHO $(( $($GREP -ve /$ $FILELIST | $WC --lines )-5)) \ New files backed up. >> $SUMMARY $ECHO $OLDEST was removed and $CURRENT was created >> $SUMMARY $ECHO Elapsed time: $TimeWellSpent >> $SUMMARY $TAIL -3 $FILELIST >> $SUMMARY $MV $FILELIST $CURRENT # And thats it for SNAP_DIR. Now remount the RW snapshot mountpoint as RO # $MOUNT -o remount,ro $MOUNT_DEVICE $MOUNT_DIR ; # if (( $? )); then { # $ECHO "Could not remount $MOUNT_DIR readonly"; exit; # } fi; \\ The /Backup/01-Root/Excludes file is important, there's always stuff you don't want backed up (some things can't be as they recursively call themselves) and this is a list that has been created over years of 'what the heck happened' moments;\\ ''**sudo cat /Backup/01-Root/Excludes**'' /Backup/* /home/Shared/Backup */Cache/* /dev/* /flows/* /initrd* /home/*/.gvfs */lost+found* /media/* /mnt/* /run/* /tmp/* /proc/* /var/virus* /var/lib/vmware* /var/run/cups/certs* /var/lib/docker/* \\ And, what's in the partition backup folder;\\ ''**ls -Al /Backup/01-Root/**'' total 52 drwxr-xr-x 44 root root 4096 2026-01-26+15:21:57 2026-01-26-20-20 drwxr-xr-x 44 root root 4096 2026-01-27+15:22:44 2026-01-27-20-20 drwxr-xr-x 44 root root 4096 2026-01-28+15:22:39 2026-01-28-20-20 drwxr-xr-x 44 root root 4096 2026-01-29+15:22:20 2026-01-29-20-20 drwxr-xr-x 44 root root 4096 2026-01-30+15:21:58 2026-01-30-20-20 drwxr-xr-x 44 root root 4096 2026-01-31+15:22:42 2026-01-31-20-20 drwxr-xr-x 44 root root 4096 2026-02-01+15:23:43 2026-02-01-20-20 drwxr-xr-x 44 root root 4096 2026-02-02+15:22:12 2026-02-02-20-20 drwxr-xr-x 44 root root 4096 2026-02-03+15:25:32 2026-02-03-20-20 drwxr-xr-x 44 root root 4096 2026-02-04+15:23:10 2026-02-04-20-20 -rw-r--r-- 1 root root 330 2026-02-04+15:23:10 Backups -rw------- 1 root root 199 2024-09-02+19:06:02 Excludes -rw-r--r-- 1 root root 349 2026-02-04+15:23:10 Summary \\ The Summary file is a quick recap of what happened during the last backup;\\ ''**sudo cat /Backup/01-Root/Summary**'' sending incremental file list created directory /Backup/01-Root/2026-02-04-20-20 13145 New files backed up. /Backup/01-Root/2026-01-25-20-20 was removed and /Backup/01-Root/2026-02-04-20-20 was created Elapsed time: 00:03:08 sent 2,314,795,346 bytes received 461,750 bytes 28,063,722.38 bytes/sec total size is 264,243,317,875 speedup is 114.13 \\ Backing up another partition requires only to create another .conf file, creating the folder to drop the backups into, and copying the 'Excludes' file there.\\ Below is the .conf for the EFI partition;\\ ''**sudo cat /Backup/00-EFI.conf**'' # =-=-=-=-=-=- File locations and variables. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= # Where to write the backups, begins with / only. SNAPSHOT_RW=/Backup/00-EFI; # What directory to back up, begins and ends in / SNAP_DIR="/boot/efi/"; # Where to store the list of files and directories that we backed up. FILELIST=$SNAPSHOT_RW/Filelist # Summary file, a short list of actions taken by rsync to complete the backup. SUMMARY=$SNAPSHOT_RW/Summary # Stuff not to back up, there is always stuff to not back up! EXCLUDES=$SNAPSHOT_RW/Excludes; # How many snapshot backups do we want to keep? Must be at least 2! NUM_SNAP=10; \\ Other stuff;\\ In one of the date points in the backup folder, there are a few added files, ''**/Backup/01-Root/2026-02-04-20-20/Filelist**'' and a copy of the Summary file; ''**sudo ls -Al /Backup/01-Root/2026-02-04-20-20/**'' total 8389772 drwxr-xr-x 2 root root 4096 Nov 26 2024 Backup lrwxrwxrwx 10 root root 7 Apr 22 2024 bin -> usr/bin drwxr-xr-x 2 root root 4096 Feb 26 2024 bin.usr-is-merged drwxr-xr-x 4 root root 4096 Feb 3 11:10 boot drwxr-xr-x 2 root root 4096 Feb 4 14:46 dev drwxr-xr-x 149 root root 12288 Feb 4 14:30 etc -rw------- 1 root root 1000059 Feb 4 15:23 Filelist drwxr-xr-x 6 root root 4096 Jan 15 2025 home drwxr-xr-x 2 root root 4096 Feb 3 11:07 i18n lrwxrwxrwx 10 root root 7 Apr 22 2024 lib -> usr/lib lrwxrwxrwx 10 root root 9 Apr 22 2024 lib64 -> usr/lib64 drwxr-xr-x 2 root root 4096 Feb 26 2024 lib.usr-is-merged drwx------ 2 root root 4096 Jun 27 2024 lost+found drwxr-xr-x 2 root root 4096 Jun 27 2024 media drwxr-xr-x 2 root root 4096 Apr 23 2024 mnt drwxr-xr-x 12 root root 4096 Aug 27 00:14 opt dr-xr-xr-x 2 root root 4096 Feb 3 11:06 proc drwx------ 12 root root 4096 Feb 3 10:54 root drwxr-xr-x 2 root root 4096 Feb 4 14:46 run lrwxrwxrwx 10 root root 8 Apr 22 2024 sbin -> usr/sbin drwxr-xr-x 2 root root 4096 Apr 3 2024 sbin.usr-is-merged drwxr-xr-x 2 root root 4096 Apr 23 2024 srv -rw-r--r-- 10 root root 116 Jun 27 2024 Summary dr-xr-xr-x 2 root root 4096 Feb 3 15:22 sys drwxrwxrwt 2 root root 4096 Feb 4 14:46 tmp drwxr-xr-x 12 root root 4096 Apr 23 2024 usr drwxr-xr-x 14 root root 4096 Jun 27 2024 var Notice above that the actual files (the soft links) in this folder have inode counts of 10. That means that they haven't changed in all of the backups, it's only a single file in the /Backup sub-folder, with hard links in pointing at the original file.\\ \\ Below, you can see that files that change every day change their link count;\\ ''**sudo ls -l /Backup/01-Root/*/var/log/unattended-upgrades/unattended-upgrades.log**'' -rw-r--r-- 1 root root 22146 Jan 26 06:47 /Backup/01-Root/2026-01-26-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 23063 Jan 27 12:44 /Backup/01-Root/2026-01-27-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 23992 Jan 28 06:45 /Backup/01-Root/2026-01-28-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 24790 Jan 29 06:35 /Backup/01-Root/2026-01-29-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 28212 Jan 30 09:05 /Backup/01-Root/2026-01-30-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 31634 Jan 31 12:40 /Backup/01-Root/2026-01-31-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 3422 Feb 1 14:22 /Backup/01-Root/2026-02-01-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 6844 Feb 2 06:21 /Backup/01-Root/2026-02-02-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 10096 Feb 3 06:09 /Backup/01-Root/2026-02-03-20-20/var/log/unattended-upgrades/unattended-upgrades.log -rw-r--r-- 1 root root 11239 Feb 4 08:39 /Backup/01-Root/2026-02-04-20-20/var/log/unattended-upgrades/unattended-upgrades.log