Site Tools


backup_script

This is an old revision of the document!


Backup Script

Goals


  1. You want to schedule a backup done via a cron job.
  2. You want the script initiated from, and stored in a safe location
    on a server on the network, (not on the router).
  3. You do not wish to install SFTP just for these backups.


The script at the bottom of this page will create and download the backup without needing to have SFTP enabled on the router.

We could, of course, create the backup as a cron job on the router itself, and then use the mechanism applied in the script below to download the backup file. However, let's assume you want everything done in just one run of the script. To achieve this, the script covers creation of the backup in an individual file with timestamp and download.

In this way, just one run of the script on the backup server will create the backup and download it to to a safe location.

Action is based on using a here doc to execute commands on the router.



The backup is created using the “nvram save” command. This is how backups are done “under the hood” in the web interface.

You may cross-check that the backups are identical to the ones via the GUI using the following steps (last tested at 22.04.2025):


  1. Download the backup via the graphical interface
  2. Create a backup via a script
  3. Copy both files to router
  4. Convert both files via the command “nvram convert <filename1/2> > result_file1/2.txt”
  5. Perform a diff between the two resulting text files.


The script then archives the resulting data in a tar file and sends it through the netcat command, transferring it over the network. Restore a backup file is the same procedure as resorting an archive created in the WEB-GUI (last tested 29.04.2025).


Prerequisites


  1. The netcat command must be available on the backup server.
  2. The router's root user must have access to the public SSH key of the user executing the script on backup server.


Remarks


  1. Command line arguments: backup directory, id-file and router /.eg. as IP). If provided, these will be used, else defaults apply (Router IP from `ip r`)
  2. Date regex covers from 1970 - in case Tomato Router has no time.
  3. Sometimes tar fails. - cover this error by just cleaning, next cron run may do it
  4. All earlier backups from the same day are abandoned.
  5. A total number of backups is kept. This number is configurable. Older ones are deleted.


 #!/bin/bash
 
 DIR2BACKUP=/home/${LOGNAME}/Router_Backups
 LOCAL_ID_FILE=/home/${LOGNAME}/.ssh/id_tomato_ecdsa
 ROUTER=`ip r | grep default | head -1 | cut -d " " -f 3`   
 
 while [[ $# -gt 0 ]]; do
      case $1 in
              -d|--dir2backup)
                      DIR2BACKUP=$2 ;;
              -i|--idfile)
                      LOCAL_ID_FILE=$2 ;;
              -r|--router)
                      ROUTER=$2 ;;
      esac
      shift; shift
 done
 
 BACKUPHOST=`ip r | grep "${ROUTER%1}0/24" | head -1 | cut -d " " -f 9`
 echo
 echo "Backup dir:  "${DIR2BACKUP}
 echo "id file:     "${LOCAL_ID_FILE}
 echo "Backing up:  "${ROUTER}
 echo "Backup host: "${BACKUPHOST}
 echo
 USER=root
 PORT=5555
 SCRIPT_FILE=nvram_save_cfg.sh
 PREFIX=FreshTomato
 EXT=cfg
 TRANSFER_FILENAME=config.tar
 
 # DATE_REGEX covers back to 1970 and further, in case Tomato Router has no date or date 1970-01-01
 # Total coverage: 1900-01-01 until 2999-12-31 :-)
 DATE_REGEX=[12][09][0-9][0-9][01][0-9][0123][0-9]
 TIME_REGEX=[012][0-9][0-5][0-9]
 NO_OF_DIFF_FILES_TO_BE_KEPT=10
  
 pushd ${DIR2BACKUP} > /dev/null
 
 rm -f ${TRANSFER_FILENAME} 
 #
 # Thinks like
 # VAR=`nvram get os_version` 
 # seem not to work in bash via here doc, so write results into script file and source it
 # Further the individual filename is general not known, so tar it into temp file
 #
 # Kill netcat zombies
 kill -9 `ps -ef | grep -v grep | grep netcat | sed -e "s/ [ ]*/ /g" | cut -d " " -f 2` 2> /dev/null
 (netcat -l -p ${PORT} > ${TRANSFER_FILENAME}) &
 ssh ${USER}@${ROUTER} -i ${LOCAL_ID_FILE} <<ENDSSH
      rm -f ${SCRIPT_FILE} ${TRANSFER_FILENAME} ${PREFIX}_*_${DATE_REGEX}_${TIME_REGEX}.${EXT}
      echo "nvram save ${PREFIX}" >> ${SCRIPT_FILE}
      nvram get os_version | sed -e "s/ .*$//" >> ${SCRIPT_FILE}
      echo "on" >> ${SCRIPT_FILE}
      nvram get t_model_name | tr " " "_" >> ${SCRIPT_FILE}
      nvram get router_name >> ${SCRIPT_FILE}
      date +%Y%m%d_%H%M >> ${SCRIPT_FILE}
      sed -e "N;N;N;N;N;s/\n/_/g;s/$/.${EXT}/" -i ${SCRIPT_FILE}
      source ${SCRIPT_FILE}
      tar -cvf ${TRANSFER_FILENAME} ${PREFIX}_*_${DATE_REGEX}_${TIME_REGEX}.${EXT} > /dev/null
      cat ${TRANSFER_FILENAME} | nc ${BACKUPHOST} ${PORT}
      sleep 5 # just wait a little bit before deleting the files not needed here any more
      rm -f ${SCRIPT_FILE} ${TRANSFER_FILENAME} ${PREFIX}_*_${DATE_REGEX}_${TIME_REGEX}.${EXT}
 ENDSSH
 
 THIS_BACKUP_FILE=`tar -xvf ${TRANSFER_FILENAME} | sed -e "s/^.*${PREFIX}/${PREFIX}/"`
 if [ "${THIS_BACKUP_FILE}" ]; then
      echo "Saved on this computer in `pwd`:"
      echo ${THIS_BACKUP_FILE}
      echo
      TODAYS_BACKUP_FILES_PREFIX=${THIS_BACKUP_FILE%_*}
      ALL_BACKUP_FILES_PREFIX=${TODAYS_BACKUP_FILES_PREFIX%_*}
      DATE=`date +%Y%m%d_%H%M`
      if ! [[ `find -cmin 5 | grep ${THIS_BACKUP_FILE}` ]] ; then
              # Date of the new files is more that 5 mind in the past  => seems Tomato Router has no date (or date 1970-01-01)
              touch ${THIS_BACKUP_FILE}
      fi
      # Keep only one file (the latest) per day - delete earlier file of same day    
      LIST_OLD_BACKUPS_OF_TODAY=`ls -t ${TODAYS_BACKUP_FILES_PREFIX}_${TIME_REGEX}.${EXT} 2> /dev/null | sed -e 1,1d`
      if [ "${LIST_OLD_BACKUPS_OF_TODAY}" ]; then
              echo "deleting today's earlier backups (to keep just one per day - the most recent):"
              rm -fv ${LIST_OLD_BACKUPS_OF_TODAY}
              echo
      fi
      # In total, keep only ${NO_OF_DIFF_FILES_TO_BE_KEPT} files - delete older files (of any day)
      OLDER_FILES=`ls -t ${ALL_BACKUP_FILES_PREFIX}_${DATE_REGEX}_${TIME_REGEX}.${EXT} | sed -e 1,${NO_OF_DIFF_FILES_TO_BE_KEPT}d`
      if [ "${OLDER_FILES}" ]; then
              echo "keep only ${NO_OF_DIFF_FILES_TO_BE_KEPT} in total, delete:"
              rm -fv ${OLDER_FILES}
              echo
      fi
      # delete transfer file only when tar was successfull, i.e. only here
      rm ${TRANSFER_FILENAME}
 else
      echo "unknown error while untaring"
 fi
 popd > /dev/null



/home/fresoehv/wiki/data/pages/backup_script.txt · Last modified: 2025/05/06 08:08 by thilo