TrueNAS Scale Backup Script
In my previous post, I described how to install the proxmox backup client and how to create an account within PBS (Proxmox Backup Server) to allow backup and restore operations on a specific PBS datastore. As well as create a manual backup of a TrueNAS Scale datastore. For a once off backup it would suffice but I wanted a regular backup of my TrueNAS datasets onto the PBS, with logging for trouble shooting if the need arises.
In this article I will list my backup script, invocation method and backup workflow.
Script Setup
To use this script, modify the PBS_PASSWORD, PBS_REPOSITORY, LOGDIR,STOREAGEPOOLS and PXAR_NAMES environment variables to supply your PBS account, password, server and datastore information.
STORAGEPOOLS is an array of the TrueNAS storage pools and datasets that you with to backup.
PXAR_NAMES is an array of file names for the pxar archive files to be created on the PBS server. Note that the pxar file names must be in the same order as the storage pools in the STORAGEPOOLS array.
Finally, the LOGDIR variable contains the location where you want to store the backup logs. In my case I have a dataset called backup, which hosts this script and the backup logs within a Logs subdirectory. This dataset is also backed up onto the PBS.
Requirements
This script will create a temporary ZFS snapshot of the dataset called PreBackupSnapshot
and backup the contents of this snapshot. Once the backup has completed, it will delete the PreBackupSnapshot
snapshot.
The script expects the snapshot directory to be visible, creating a .zfs folder within the parent folder of the dataset. Ensure that the snapdir property is set to visible for all datasets you wish to backup.
You can view the status of this feature by opening a TrueNAS shell and using zfs get
to show the snapdir property.
This example will show the value of the snapdir property of the backup dataset within the pool StoragePool.
sudo zfs get snapdir StoragePool/backup
The StoragePool/backup dataset snapdir property is set to hidden.
NAME PROPERTY VALUE SOURCE
StoragePool/backup snapdir hidden local
Lets change that.
sudo zfs set snapdir=visible StoragePool/backup
Now using ls -a /mnt/StoragePool/backup
will show a .zfs folder. Inside the .zfs/snapshot
folder all the snapshots for this dataset will be available.
admin@nas[~]$ ls -al /mnt/StoragePool/backup
total 62
drwxr-xr-x 4 root root 7 Mar 1 10:50 .
drwxr-xr-x 9 root root 10 Feb 28 17:28 ..
drwxrwxrwx 1 root root 0 Feb 28 09:17 .zfs
drwxrwxr-x 2 root root 2 Mar 1 10:44 Logs
-rwxr-xr-x 1 root root 13541 Feb 26 23:29 backup_TestShare.sh
-rwxr-xr-x 1 root root 13471 Feb 26 23:06 backup_vm.sh
-rwxr-xr-x 1 root root 3834 Mar 1 10:49 pbs-backup.sh
-rwxr-xr-x 1 root root 3689 Mar 1 10:45 test.sh
Backup Methodology
Within TrueNAS I have scheduled daily snapshots of my datasets with a two week retention. I then setup a cron job (under System Settings/System) within TrueNAS to run my backup script daily. This gives me a quick method to restore backups within the snapshot retention policy as well as a second long term backup, that can then be replicated to a cloud provider or second PBS server. The PBS server has a retention policy set to two months which does the clean up of old backups as well as the de-duplication of all the backups.
The Script
I don’t claim to be an expert coder but this script serves me well. Hopefully it will serve you just as well.
#!/bin/bash
### TrueNAS-PBS: Backup TrueNAS data sets into Proxmox Backup Server (PBS)
### Written by Chris MacKenzie, 2023
###
### Requires proxmox-backup-client installed on TrueNAS host and an account created in PBS with appropriate permissions.
###
### TODO: Add Log cleanup function with retention policy.
export PBS_PASSWORD=truenas
export PBS_REPOSITORY=truenas@pbs@192.168.0.150:Mirror8
SCRIPTNAME=`basename -s .sh ${0}` # Name of this script minus path and the .sh extension
CUR_DATE=`date +%Y-%m-%d-%H-%M-%S`
LOGDIR=/mnt/StoragePool/backup/Logs # Where to store the logs
LOGNAME="$LOGDIR/$SCRIPTNAME-${CUR_DATE}.log"
STORAGEPOOLS=("StoragePool/backup" "StoragePool/FileStore/NAS-Data" "StoragePool/FileStore/NAS-Media" "StoragePool/FileStore/NAS-Home")
PXAR_NAMES=("backup.pxar" "nas-data.pxar" "nas-media.pxar" "nas-home.pxar") # pxar archive file names for pbs server (in same order as dataset array)
STORAGEPOOL_LENGTH=${#STORAGEPOOLS[@]} # Number of array elements
TEMP_SNAPSHOTNAME="PreBackupSnapshot"
SPEC="" # Specification variable for proxmox-backup-client
MY_DEBUG=0 # Set to 1 to do everything except the calling of proxmox-backup-client, essentially a dry-run
#### Declare Functions
WriteLog () { # Writes to both log and stdout
echo $1
echo $1 >> ${LOGNAME}
}
CreateSnapshot () {
TEMP_SNAPSHOT="$STORAGEPOOL@$TEMP_SNAPSHOTNAME"
WriteLog " - Creating Snapshot -> $TEMP_SNAPSHOT"
zfs snapshot $TEMP_SNAPSHOT 2>/dev/nul # Redirect STDERROR to /dev/nul
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
WriteLog " !! Cannot create snapshot (error $EXITCODE)"
fi
return $EXITCODE
}
DeleteSnapshot () {
TEMP_SNAPSHOT="$STORAGEPOOL@$TEMP_SNAPSHOTNAME"
WriteLog " - deleting Snapshot -> $TEMP_SNAPSHOT"
zfs destroy $TEMP_SNAPSHOT 2>/dev/nul # Redirect STDERROR to /dev/nul
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
WriteLog " !! Cannot delete snapshot (error $EXITCODE)"
fi
return $EXITCODE
}
CleanUp () {
WriteLog "Performing CleanUp()"
for STORAGEPOOL in "${STORAGEPOOLS[@]}"
do
DeleteSnapshot $STORAGEPOOL
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
WriteLog " !! Error performing CleanUp ($EXITCODE)."
WriteLog
exit 255
fi
done
}
#### End of Functions
## Create log file and log directory if it does not exist.
ls $LOGDIR >/dev/nul 2>/dev/nul
if [ "$?" != "0" ]; then
mkdir -m 775 -p $LOGDIR
if [ "$?" != "0" ]; then
echo " !! Cannot create log directory $LOGDIR, Aborting."
exit 255
fi
fi
touch ${LOGNAME}
if [ "$?" != "0" ]; then
echo " !! Cannot create logfile $LOGNAME"
exit 255
fi
## Do Preperations (Create snapshots and build SPEC variable)
WriteLog "Doing Preperations, Please Wait."
for ((i=0; i<STORAGEPOOL_LENGTH; i++))
do
SPEC="$SPEC ${PXAR_NAMES[$i]}:/mnt/${STORAGEPOOLS[$i]}/.zfs/snapshot/$TEMP_SNAPSHOTNAME/"
STORAGEPOOL="${STORAGEPOOLS[$i]}"
CreateSnapshot $STORAGEPOOL
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
WriteLog " !! Cannot create snapshot (error $EXITCODE), exiting."
WriteLog
CleanUp # Attempt Cleanup
WriteLog
WriteLog "Backup Aborted."
exit 255
fi
done
### Run Backup
WriteLog
WriteLog "SPEC = $SPEC"
if [ $MY_DEBUG -eq 1 ]; then
WriteLog "Debug Detected."
CleanUp
WriteLog
WriteLog "Debug Exit."
WriteLog
exit 0
fi
WriteLog
WriteLog "Starting Backup....."
WriteLog
proxmox-backup-client backup $SPEC >> $LOGNAME 2>&1
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
WriteLog "proxmox-backup-client failed (error $EXITCODE), aborting."
CleanUp
exit 255
fi
WriteLog
CleanUp
EXITCODE=$?
if [ $EXITCODE != 0 ]; then
WriteLog " !! Error performing CleanUp."
exit 255
fi
WriteLog
WriteLog "Backup completed successfully."
exit 0