A better Rsync Incremental Back-up script…
Recently, we published our First Rsync Incremental Backup Script, which was nice, but we could improve. There was no support for setting intervals and the retention period was a function of the amount of increments. So, to have a daily backup go back one year would require 365 increments, not optimal at all.
This newer script support defining your own intervals (e.g. daily, weekly, 4hourly, etc.) and the amount of increments (e.g. 7 daily versions per week) per interval to save. Then, the script itself determines what interval is next to back-up.
This will hopefully be the last back-up script you'll need in a long time. It's the only one I'm using anyway.
TL;DR: The entire script
How it works
Setting increments
The INCREMENTS
variable stores the amount of increments to save per period. The DURATIONS
variable stores how long — in seconds — a period is, this variable only needs changing if you want to alter the duration or add new periods.
In INCREMENTS
, you can set the amount to " 0
" to exclude the increment. For every increment you include, a folder on the back-up target location is created automatically.
Keep in mind both vars are associative arrays, make sure the formatting is right. If you're interested, Andy Balaam's blogpost is a great explanation. If you're not interested, just look at the current formatting and change as you wish.
Installation
Copy the contents of the entire script in a file you name " backup
", store it in " /etc/cron.hourly
":
Don't forget, if you've created an hourly or even shorter period, the script needs to be called more often. Save the file somewhere else and call it accordingly from /etc/crontab
(or any other method you like).
The following variables probably need changing:
BACKUP_LOCAL_DIR
: Folder to keep required tracking files;BACKUP_DIRS
: The folders you want to have back when you computer or server dies, don't remove$BACKUP_LOCAL_DIR
;RSYNC_TARGET
: Where the actual back-up should be stored — the remote, possibly off-site, location;RSYNC_SECRET
: Optional, if Rsync profile on the remote server requires a secret;MYSQL
: Either leave as is or replace--defaults-file=/etc/mysql/debian.cnf
with-uUSERNAME -pPASSWORD
parameters.MYSQLDUMP
: Same as theMSQL
variable.
The following variables only need checked:
INCREMENTS
: Change the amount of increments you want to save in addition to the full back-up per period.
Full and Incremental Back-ups
The first time the script runs, it creates one full back-up and stores it in the
folder.current
The next run — the first increment — it stores that increment in
, e.g. 1
. Files modified since the last run are moved to this folder and the latest copy is moved to the " daily/1
current
" folder. For the amount of given increments for a period, new increments are created every run, e.g
, daily/2
, etc.daily/3
Finally, when the amount of increments has reached, a new full back-up is stored in the " current
" folder. After that, the increment folders are updated one by one.
To make it easier to find files modified before certain date or time, each folder's timestamp is updated to match the time it ran.
Back-up to a local folder or USB disk instead of a remote Rsync server
The RSYNC_TARGET
variable dictates the remote — preferably off-site location — for the back-up. For example, if your back-up USB disk is mounted at /dev/sdc1
(use lsblk
to find out where it's mounted) change it as follows:
Don't forget to empty the RSYNC_SECRET
variable, to ensure it all works as it should.
What's BACKUP_LOCAL_DIR
for?
The back-up script keeps track of which increment it last completed, by storing a file per period in the BACKUP_LOCAL_DIR
folder, e.g. " last_inc_hourly
", " last_inc_daily
", etc. The timestamp of these files is used to determine when that increment was created, to see if the period is elapsed. If you remove these files, or the dir entirely, the script will start with "current" as explained above.
This ensures that if a run was missed — because your laptop was powered off, or because your server was rebooting — the next increment is created as soon as it powers on again, though not sooner than given period duration.
Finally, this folder contains a local copy of all created database dumps.
Conclusion
Is this the final back-up scrip we'll ever create? Probably not, there's always room for improvement. This script allows to create proper back-ups you can rely on, that span big retention periods, without requiring an unhealthy amount of disk space. In our opinion, it's a healthy mix between incremental an full back-ups, allowing for proper disaster recovery.
The current script will only function on Linux systems, or at least systems running Bash. It's unknown if it will run using the Linux Subsystem for Windows 10. Therefore we made a Windows Powershell Rsync backup script instead.
Finally, the script is probably not suitable for the less tech-savvy among us, but that — in my humble opinion — might be a pretty good user filter on itself: If you can't get it running, don't use it.
Perfacilis Back-up Service
The Perfacilis Back-up service alerts you when a back-up didn't finish in the scheduled time-frame, or if a lot of data changes at once (which might indicate an encrypter virus). You only pay for the amount of space your back-ups use.
Want to learn more?
Changelog
- 2021-02-01
- Bump version to 0.7.1
- Removed
$RSYNC_TARGET
from--backup-dir=$RSYNC_TARGET/$PERIOD/$INC/$TARGET
- 2021-04-06
- Removed
log/ logs/ *.log
from exclusion list, it's good practice to back-up log files as well. - 2021-04-25
- Bump version to 0.8.
- Removed
current
dir per increment folder, only onecurrent
dir inside the root directory will be created. - 2021-05-26
- Bump version to 0.8.1.
- Added check to enforce only one running instance, using pidof check.
- 2021-09-24
- Bump version to 0.8.2.
- Added
--single-transaction
, as suggested by mysqldump manpage and ClusterEngine's artile on dumping live MySql databases. - Using shorthand options -E, -R, -q and -Q for mysqldump command, because it's gets too long.
- Remove trailing slash after
$EMPTYDIR
inrsync $RSYNC_OPTS $EMPTYDIR/ $RSYNC_TARGET/${TREE/#\//}
, ensuring folder timestamps are properly set. - 2022-03-07
- Bump version to 0.9 code name Doug.
- No longer overwrite
current
dir if increment is 0, so we have true incremental backups. - Fixed setting
LAST_INC_XXX
files modified time to ensure intervals are more closely met. - Added
-p
argument to rsync command to make sure file permissions are set. - Created GitHub repository to keep track of changes.
- Special thanks to Doug for his suggestions!
- 2022-03-17
- Bump version to 0.9.1
- Check if $MYSQL or $MYSQLDUMP are empty, if no don't make mysql backups.
- 2022-03-29
- Bump version to 0.9.2 code name Gabriel.
- Fixed checking for empty $RSYNC_SECRET
- Special thanks to Gabriel for his suggestions!
- 2022-05-09
- Bump version to 0.9.3
- Making
touch
BSD-compatible, using xave's suggestions. - 2022-06-03
- Bump version to 0.10
- Using
flock
instead ofpidof
for more BDS-compatibility - 2022-06-17
- Bump version to 0.10.1
- More BSD compatibility, now for
date
command. - Bump version to 0.10.2
- Fix for local backups: Force increment dirs on target.
- 2022-06-27
- Bump version to 0.11
- Fixed some off by one errors, backup updates only one interval per run.
- Thanks to mgoerens for his suggestion
- 2022-06-28
- Bump version to 0.11.1
- Magic to sort associative array, to be sure biggest — most important — interval is back-upped