Hi there, today I manage to update automation script for auto backup TrueNAS config to my Raspberry Pi 5 on my local network. Script is from old forum [Script to AutoBackup TrueNAS config]
#!/bin/sh
# Script to backup TrueNAS SCALE configuration file
# WARNING: DOES NOT CHECK IF A VALID BACKUP IS ACTUALLY CREATED
#
# If a valid backup file is not created then there is something wrong with the API call
# Check that your URL and API Key are both correct
#
# # # # # # # # # # # # # # # #
# USER CONFIGURABLE VARIABLES #
# # # # # # # # # # # # # # # #
# Server IP or URL (include http(s)://)
serverURL="http://xxx.xxx.x.xxx"
# Remote Server IP (include ftp://xxx.xxx.x.xx/folder/)
serverFTP="ftp://xxx.xxx.x.xx/"
# Remote Server Login and Password (format login:password)
login="pass:pass"
# TrueNAS API key (Generate from 'User Icon' -> 'API Keys' in TrueNAS WebGUI)
apiKey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Include Secret Seed (true| false)
secSeed=true
# Path on server to store backups
backuploc="/mnt/poolname/foldername"
# Max number of backups to keep (set as 0 to never delete anything)
maxnrOfFiles=5
# # # # # # # # # # # # # # # # # #
# END USER CONFIGURABLE VARIABLES #
# # # # # # # # # # # # # # # # # #
echo
echo "Backing up current TrueNAS config"
# Check current TrueNAS version number
versiondir=`cat /etc/version | cut -d' ' -f1`
# Set directory for backups to: 'path on server' / 'current version number'
backupMainDir="${backuploc}/${versiondir}"
# Create directory for for backups (Location/Version)
mkdir -p $backupMainDir
# Use appropriate extension if we are exporting the secret seed
if [ $secSeed = true ]
then
fileExt="tar"
echo "Secret Seed will be included"
else
fileExt="db"
echo "Secret Seed will NOT be included"
fi
# Generate file name
fileName=$(hostname)-config-$(date +%Y%m%d-%H%M%S).$fileExt
# API call to backup config and include secret seed
curl --no-progress-meter \
-X 'POST' \
$serverURL'/api/v2.0/config/save' \
-H 'Authorization: Bearer '$apiKey \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{"secretseed": '$secSeed'}' \
--output $backupMainDir/$fileName
#### NEW SECTION 1 STARTS ####
# compare new file to old file, delete new if identical to last one
cmpFile="$( ls -t ${backupMainDir} | tail -1 )"
if cmp $fileName $cmpFile ; then
echo deleting "${backupMainDir}/${fileName}"
rm $backupMainDir/$fileName
echo "Config has not changed, no action taken. Quitting"
exit
fi
#
#### NEW SECTION 1 ENDS ####
echo
echo "Config saved to ${backupMainDir}/${fileName}"
#### NEW SECTION 2 STARTS ####
# This copies the config file off the server and onto fastmail files
curl -T ${backupMainDir}/${fileName} -u ${login} ${serverFTP}
echo
echo "Config copied to <off-site server>."
#### NEW SECTION 2 ENDS ####
#
# The next section checks for and deletes old backups
#
# Will not run if $maxnrOfFiles is set to zero (0)
#
if [ ${maxnrOfFiles} -ne 0 ]
then
echo
echo "Checking for old backups to delete"
echo "Number of files to keep: ${maxnrOfFiles}"
# Get number of files in the backup directory
nrOfFiles="$(ls -l ${backupMainDir} | grep -c "^-.*")"
echo "Current number of files: ${nrOfFiles}"
# Only do something if the current number of files is greater than $maxnrOfFiles
if [ ${maxnrOfFiles} -lt ${nrOfFiles} ]
then
nFileToRemove="$((nrOfFiles - maxnrOfFiles))"
echo "Removing ${nFileToRemove} file(s)"
while [ $nFileToRemove -gt 0 ]
do
fileToRemove="$(ls -t ${backupMainDir} | tail -1)"
echo "Removing file ${fileToRemove}"
nFileToRemove="$((nFileToRemove - 1))"
rm ${backupMainDir}/${fileToRemove}
done
fi
# Inform the user that no files will be deleted if $maxnrOfFiles is set to zero (0)
else
echo
echo "NOT deleting old backups because '\$maxnrOfFiles' is set to 0"
fi
#All Done
echo
echo "DONE!"
echo
All seems to be working, but if someone can take a look if I did miss something?
This is my output from the script:
# ./config_backup.sh
Backing up current TrueNAS config
Secret Seed will be included
cmp: TrueNAS.local-config-20241104-130128.tar: No such file or directory
Config saved to /mnt/WebData/Config_Backup/TrueNAS-13.0-U6.2/TrueNAS.local-config-20241104-130128.tar
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 730k 0 0 100 730k 0 7847k --:--:-- --:--:-- --:--:-- 7934k
Config copied to <off-site server>.
Checking for old backups to delete
Number of files to keep: 5
Current number of files: 4
DONE!
This is pretty cool. Out of interest why not just back it up to a dataset in your main pool?
So long as your pool is well designed and maintained it’s unlikely you’d lose it and even if you did your config file is probably worth nothing now anyway without your pool.
Hi Johnny, Thanks for replay.
I 'm about to change mirror USB boot to new single SSD, I was wondering how to make a backup in case all will go sideways.
I thought to maybe make a shedule backup on my 24h RPi5, as I wasn’t quite sure if I will be able to access config file from my POOL if something would go wrong or I will install new TrueNAS on SSD
Makes sense. Just for info even if things go south with your boot drive so long as your main data pool is fine then you can always import and access that pool either from a clean install on new boot media or even a completely different system. That’s one of the beauties of ZFS. After that it’s just a matter of copying things across and rebooting.
# Script to backup TrueNAS SCALE configuration file
# WARNING: DOES NOT CHECK IF A VALID BACKUP IS ACTUALLY CREATED
#
#
# Thanks to 'NasKar' and 'engedics' from this thread: https://www.truenas.com/community/threads/best-way-to-get-auto-config-backup.94537/
#
#
# If a valid backup file is not created then there is something wrong with the API call
# Check that your URL and API Key are both correct
#
# # # # # # # # # # # # # # # #
# USER CONFIGURABLE VARIABLES #
# # # # # # # # # # # # # # # #
# Server IP or URL (include http(s)://)
serverURL="https://localhost"
# TrueNAS API key (Generate from 'User Icon' -> 'API Keys' in TrueNAS WebGUI)
apiKey="1-YOURKEYHERE"
# Include Secret Seed (true| false)
secSeed=true
# Path on server to store backups
backuploc="/mnt/YOUR/LOCATION/"
# Max number of backups to keep (set as 0 to never delete anything)
maxnrOfFiles=5
# # # # # # # # # # # # # # # # # #
# END USER CONFIGURABLE VARIABLES #
# # # # # # # # # # # # # # # # # #
echo
echo "Backing up current TrueNAS config"
# Check current TrueNAS version number
versiondir=`cat /etc/version | cut -d' ' -f1`
# Set directory for backups to: 'path on server' / 'current version number'
backupMainDir="${backuploc}/${versiondir}"
# Create directory for for backups (Location/Version)
mkdir -p $backupMainDir
# Use appropriate extension if we are exporting the secret seed
if [ $secSeed = true ]
then
fileExt="tar"
echo "Secret Seed will be included"
else
fileExt="db"
echo "Secret Seed will NOT be included"
fi
# Generate file name
fileName=$(hostname)-config-$(date +%Y%m%d-%H%M%S).$fileExt
# API call to backup config and include secret seed
curl --no-progress-meter \
-X 'POST' \
$serverURL'/api/v2.0/config/save' \
-H 'Authorization: Bearer '$apiKey \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d '{"secretseed": '$secSeed'}' \
--output $backupMainDir/$fileName
#### NEW SECTION 1 STARTS ####
# compare new file to old file, delete new if identical to last one
cmpFile="$( ls -t ${backupMainDir} | tail -1 )"
if cmp $fileName $cmpFile ; then
echo deleting "${backupMainDir}/${fileName}"
rm $backupMainDir/$fileName
echo "Config has not changed, no action taken. Quitting"
exit
fi
#
#### NEW SECTION 1 ENDS ####
echo
echo "Config saved to ${backupMainDir}/${fileName}"
#
# The next section checks for and deletes old backups
#
# Will not run if $maxnrOfFiles is set to zero (0)
#
if [ ${maxnrOfFiles} -ne 0 ]
then
echo
echo "Checking for old backups to delete"
echo "Number of files to keep: ${maxnrOfFiles}"
# Get number of files in the backup directory
nrOfFiles="$(ls -l ${backupMainDir} | grep -c "^-.*")"
echo "Current number of files: ${nrOfFiles}"
# Only do something if the current number of files is greater than $maxnrOfFiles
if [ ${maxnrOfFiles} -lt ${nrOfFiles} ]
then
nFileToRemove="$((nrOfFiles - maxnrOfFiles))"
echo "Removing ${nFileToRemove} file(s)"
while [ $nFileToRemove -gt 0 ]
do
fileToRemove="$(ls -t ${backupMainDir} | tail -1)"
echo "Removing file ${fileToRemove}"
nFileToRemove="$((nFileToRemove - 1))"
rm ${backupMainDir}/${fileToRemove}
done
fi
# Inform the user that no files will be deleted if $maxnrOfFiles is set to zero (0)
else
echo
echo "NOT deleting old backups because '\$maxnrOfFiles' is set to 0"
fi
#All Done
echo
echo "DONE!"
echo
But that does not work with 24.10 anymore… did anything change with API v2 ?
This is updated script with FTP upload, works on my TrueNAS 13 U6.4 and Raspberry Pi 5 on my local network:
#!/bin/bash
# Script to backup TrueNAS SCALE configuration file
# WARNING: DOES NOT CHECK IF A VALID BACKUP IS ACTUALLY CREATED
#
# If a valid backup file is not created then there is something wrong with the API call
# Check that your URL and API Key are both correct
#
# # # # # # # # # # # # # # # #
# USER CONFIGURABLE VARIABLES #
# # # # # # # # # # # # # # # #
# Server IP or URL (include http(s)://)
serverURL="http://xxx.xxx.x.xxx"
# Remote Server IP (include ftp://xxx.xxx.x.xx/folder/)
serverFTP="ftp://xxx.xxx.x.xx/"
# Remote Server Login and Password (format login:password)
login="user:pass"
# TrueNAS API key (Generate from 'User Icon' -> 'API Keys' in TrueNAS WebGUI)
apiKey="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Include Secret Seed (true|false)
secSeed=true
# Path on server to store backups on TrueNAS pool
backuploc="/mnt/poolname/foldername"
# Max number of backups to keep (set as 0 to never delete anything)
maxnrOfFiles=5
# # # # # # # # # # # # # # # # # #
# END USER CONFIGURABLE VARIABLES #
# # # # # # # # # # # # # # # # # #
echo
echo "Backing up current TrueNAS config"
# Check current TrueNAS version number
versiondir=$(cut -d' ' -f1 < /etc/version)
# Set directory for backups to: 'path on server' / 'current version number'
backupMainDir="${backuploc}/${versiondir}"
# Create directory for backups (Location/Version)
mkdir -p "${backupMainDir}"
# Use appropriate extension if we are exporting the secret seed
if [ "$secSeed" = true ]; then
fileExt="tar"
echo "Secret Seed will be included"
else
fileExt="db"
echo "Secret Seed will NOT be included"
fi
# Generate file name
fileName="$(hostname)-config-$(date +%Y%m%d-%H%M%S).${fileExt}"
# API call to backup config and include secret seed
curl --no-progress-meter \
-X 'POST' \
"${serverURL}/api/v2.0/config/save" \
-H "Authorization: Bearer ${apiKey}" \
-H 'accept: */*' \
-H 'Content-Type: application/json' \
-d "{\"secretseed\": ${secSeed}}" \
--output "${backupMainDir}/${fileName}"
# Ensure backup file exists before proceeding
if [ ! -f "${backupMainDir}/${fileName}" ]; then
echo "Error: Backup file not created!"
exit 1
fi
echo "Backup created: ${backupMainDir}/${fileName}"
# Compare new file to previous backup and delete if identical
cmpFile=$(ls -t "${backupMainDir}" | sed -n '2p') # Get second most recent file
if [ -f "${backupMainDir}/${cmpFile}" ] && cmp -s "${backupMainDir}/${fileName}" "${backupMainDir}/${cmpFile}" ; then
echo "Deleting identical backup: ${backupMainDir}/${fileName}"
rm "${backupMainDir}/${fileName}"
echo "Config has not changed, no new backup needed. Exiting."
exit
fi
# FTP upload with improved error handling
echo "Uploading backup to FTP: ${serverFTP}"
if curl -v -T "${backupMainDir}/${fileName}" -u "${login}" "${serverFTP}"; then
echo "Config successfully copied to remote server."
else
echo "FTP upload failed!"
exit 1
fi
# Check for and delete old backups if needed
if [ "$maxnrOfFiles" -ne 0 ]; then
echo "Checking for old backups to delete"
echo "Number of files to keep: ${maxnrOfFiles}"
# Get number of files in the backup directory
nrOfFiles=$(find "${backupMainDir}" -type f | wc -l)
echo "Current number of files: ${nrOfFiles}"
# Only delete files if the current number exceeds the max allowed
if [ "$maxnrOfFiles" -lt "$nrOfFiles" ]; then
nFileToRemove=$((nrOfFiles - maxnrOfFiles))
echo "Removing ${nFileToRemove} file(s)"
while [ "$nFileToRemove" -gt 0 ]; do
fileToRemove=$(ls -t "${backupMainDir}" | tail -1)
echo "Removing file ${fileToRemove}"
rm "${backupMainDir}/${fileToRemove}"
nFileToRemove=$((nFileToRemove - 1))
done
fi
else
echo "NOT deleting old backups because maxnrOfFiles is set to 0"
fi
echo "DONE!"