MikroTik Script: RouterOS Backup

For the past few months, I’ve been manually backing up my MikroTik (CCR1009-7G-1C-1S+). It was routine, after making any adjustments to my router, I would promptly create and move the backup to a network share hosted on my local Synology NAS unit.  Normally, being someone who prefers automating tasks, I was reluctant to start writing this script, since, at the time, I had never written my own script within RouterOS. Learning a new scripting language in an unfamiliar environment has its own learning curve and would, without a doubt, become a black hole;  a black void of despair that would suck away all the time that I had set aside for this evening for more interesting activities – like reviewing mathematical proofs, calculating probabilities of random events, studying string theory, and doing an inventory of my matchstick collection, which consists of rare matchsticks from all over the world.

Let’s be honest, I didn’t have anything better to do this evening. I flat out planned to get this script written and nailed down to meet my needs and hopefully yours as well. I wrote this script to be somewhat granular. I pulled apart the date and time values and assigned them to new variables to better aid in customization. Mix and match these variables to fit your desired date/time format. I also included boolean variables to turn on/off features you may or may not need. At the very least, it’s easier than commenting out multiple line items one at a time. In the end, I hope this script proves to be beneficial to you. I’m currently using this script in my production environment, but only after I thoroughly tested each feature. If you decide to use this script in your environment, I recommend that you do the same – I take no responsibility for how you use this script.

Marthur's RouterOS Backup Script v1.0

#---------------------------------------------------SCRIPT INFORMATION----------------------------------------------------
#
# Script:  Marthur's RouterOS Backup Script
# Version: 1.0
# Updated: 10/08/2017
# Created: 10/08/2017
# Author:  Marthur Jones
# Website: https://www.marthur.com
#
# The script will first create local backup file(s) (.backup and/or .rsc). The backup file(s) can then be uploaded via
# FTP to another location if needed. Furthermore, depending on the script settings ($keepRecentLocalBackup), the script 
# can leave the most recent backup(s) on the MikroTik OR remove the backup(s). Afterwards, the script can send script
# success/error alerts via e-mail as long as the MikroTik's Email settings have been properly configured (/Tools E-Mail). 
#
# I've written this script to allow for granular/custom filenames:
#
# Backup Filename Syntax:  CustomPrefix_Identity_RouterOS Version_YYYY.MM.DD_HHMMSS.backup
# Backup Filename Example: MikroTik_Triton_RouterOS v6.40.4_2017.10.08_104456.backup
#
#-----------------------------------------------TESTED USING THE FOLLOWING------------------------------------------------
#
# Hardware: CCR1009-7G-1C-1S+
# Firmware: v3.41
# RouterOS: v6.40.4
#
#----------------------------------------------MODIFY THIS SECTION AS NEEDED----------------------------------------------

# script settings
:local saveConfigBackup         true
:local saveSystemBackup         true
:local encryptSystemBackup      false
:local keepRecentLocalBackup    true

# ftp settings
:local ftpUpload                true
:local ftpAddress               "192.168.88.100"
:local ftpPort                  "990"
:local ftpUser                  "user"
:local ftpPassword              "password"
:local ftpDestination           "/Backups"

# email settings
:local emailAlertOnSuccess      true
:local emailAlertOnError        true
:local emailTo                  "email@address.com"
:local emailSubjectOnSuccess    ("MikroTik Backup Alert for ".[/system identity get name]." - SUCCESS")
:local emailSubjectOnError      ("MikroTik Backup Alert for ".[/system identity get name]." - ERROR")
:local emailBody                "MIKROTIK BACKUP SCRIPT SETTINGS\r\n\r\n\
                                saveConfigBackup: $saveConfigBackup\r\n\
                                saveSystemBackup: $saveSystemBackup\r\n\
                                encryptSystemBackup: $encryptSystemBackup\r\n\
                                keepRecentLocalBackup: $keepRecentLocalBackup\r\n\r\n\
                                ftpUpload: $ftpUpload\r\n\
                                ftpAddress: $ftpAddress\r\n\
                                ftpPort: $ftpPort\r\n\
                                ftpUser: $ftpUser\r\n\
                                ftpDestination: $ftpDestination"

# destination directory for local system backup file (.backup)
:local systemBackupDir "/disk1/backups"

# destination directory for local config backup file (.rsc)
:local configBackupDir "/disk1/backups"

# filename prefix
:local filePrefix "MikroTik"

#-------------------------------------------------------------------------------------------------------------------------

:log warning message="START: Backup Script"

# system identity
:local systemIdentity ([/system identity get name])

# router os version
:local routerOSVersion ("RouterOS v".[/system package get number=0 value-name=version])

# months array
:local months ("jan","feb","mar","apr","may","jun","jul","aug","sep","oct","nov","dec")

# get current time
:local currentTime [/system clock get time]
:set currentTime ([:pick $currentTime 0 2].[:pick $currentTime 3 5].[:pick $currentTime 6 8])

# get current Date
:local currentDate [/system clock get date]

# convert name of month to number
:local month [ :pick $currentDate 0 3 ]
:local monthNumber ([ :find $months $month -1 ] + 1)
:if ($monthNumber < 10) do={
    :set monthNumber ("0" . $monthNumber)
}

# set $currentDate to format YYYY-MM-DD
:set currentDate ([:pick $currentDate 7 11] .".". $monthNumber .".". [:pick $currentDate 4 6])

# filename for system backup
:local backupFilename ($filePrefix."_".$systemIdentity."_".$routerOSVersion."_".$currentDate."_".$currentTime.".backup")

# filename for config backup
:local configFilename ($filePrefix."_".$systemIdentity."_".$routerOSVersion."_".$currentDate."_".$currentTime.".rsc")

# filename for wildcard filename search
:local wildcardFilename ($filePrefix."_".$systemIdentity."_".$routerOSVersion."_")

# store various error messages
:local errorMessage

# do not modify - this variable is used for error handling
:local scriptError false

# do not modify - this variable is used for error handling
:local exitBackupScript false

# remove all previous local backups
    :foreach backupFile in=[/file find name~"$wildcardFilename"] do={
        :do {
            /file remove $backupFile
        }   on-error={
                :set errorMessage "Backup Script: Error removing/clearing backups"
                :log error message="$errorMessage"
                :set scriptError true
                :set exitBackupScript true
            }
}

# save new system backup
:if (($saveSystemBackup = true) && ($scriptError = false)) do={
    :if (($encryptSystemBackup = true) && ($scriptError = true)) do={
        :do {
            /system backup save name="$systemBackupDir/$backupFilename"
        }   on-error={
                :set errorMessage "Backup Script: Error saving system backup (.backup file)"
                :log error "$errorMessage"
                :set scriptError true
                :set exitBackupScript true
            }
    }
    :if (($encryptSystemBackup = false) && ($scriptError = false)) do={
        :do {
            /system backup save dont-encrypt=yes name="$systemBackupDir/$backupFilename"
        }   on-error={
                :set errorMessage "Backup Script: Error saving encrypted system backup (.backup file)"
                :log error "$errorMessage"
                :set scriptError true
                :set exitBackupScript true
            }
    }
    :log info message="Backup Script: Finished system backup $systemBackupDir/$backupFilename"
}

# save new config backup
:if (($saveConfigBackup = true) && ($scriptError = false)) do={
    :do {
        /export compact file="/$configBackupDir/$configFilename"
        :log info message="Backup Script: Finished config backup $configBackupDir/$configFilename"
    }   on-error={
            :set errorMessage "Backup Script: Error saving config backup (.rsc file)"
            :log error "$errorMessage"
            :set scriptError true
            :set exitBackupScript true
        }
}

# upload to ftp
:if ($ftpUpload = true) do={

    :delay 5

    :if (($saveSystemBackup = true) && ($scriptError = false)) do={
        :if ([:len [/file find name~"$backupFilename"]] > 0) do={
            :do {
                /tool fetch mode=ftp address="$ftpAddress" port="$ftpPort" user="$ftpUser" password="$ftpPassword"\
                src-path="$systemBackupDir/$backupFilename" dst-path="$ftpDestination/$backupFilename" upload=yes
                :log info message="Backup Script: Finished uploading system backup via FTP to $ftpAddress$ftpDestination/$backupFilename"
            }   on-error={
                    :set errorMessage "Backup Script: Error uploading system backup $systemBackupDir/$backupFilename via FTP to $ftpAddress$ftpDestination/$backupFilename"
                    :log error "$errorMessage"
                    :set scriptError true
                    :local exitBackupScript true
                }
        } 
    }

    :delay 5

    :if (($saveConfigBackup = true) && ($scriptError = false)) do={
        :if ([:len [/file find name~"$configFilename"]] > 0) do={
            :do {
                /tool fetch mode=ftp address="$ftpAddress" port="$ftpPort" user="$ftpUser" password="$ftpPassword"\
                src-path="$configBackupDir/$configFilename" dst-path="$ftpDestination/$configFilename" upload=yes
                :log info message="Backup Script: Finished uploading config backup via FTP to $ftpAddress$ftpDestination/$configFilename"
            }   on-error={
                    :set errorMessage "Backup Script: Error uploading config backup $configBackupDir/$configFilename via FTP to $ftpAddress$ftpDestination/$configFilename"
                    :log error "$errorMessage"
                    :set scriptError true
                    :set exitBackupScript true
                }
        }
    }
}

# remove local backups
:if ($keepRecentLocalBackup = false) do={
    :if (($saveSystemBackup = true) && ($scriptError = false)) do={
        :if ([:len [/file find name~"$backupFilename"]] > 0) do={
            :do {
                :delay 5
                /file remove [/file find name~"$backupFilename"]
                :log info message="Backup Script: Finished local system backup removal"
            }   on-error={
                    :set errorMessage "Backup Script: Error removing recent local system backup $systemBackupDir/$backupFilename"
                    :log error "$errorMessage"
                    :set scriptError true
                    :set exitBackupScript true
                }
        }
    }

    :if (($saveConfigBackup = true) && ($scriptError = false)) do={
        :if ([:len [/file find name~"$configFilename"]] > 0) do={
            :do {
                :delay 5
                /file remove [/file find name~"$configFilename"]
                :log info message="Backup Script: Finished local config backup removal"
            }   on-error={
                    :set errorMessage "Backup Script: Error removing recent local config backup $configBackupDir/$configFilename"
                    :log error "$errorMessage"
                    :set scriptError true
                    :set exitBackupScript true
                }
        } 
    }
}

# send email alert on success
:if (($emailAlertOnSuccess = true) && ($scriptError = false)) do={
    
    :delay 5

    :if (($saveSystemBackup = true) && ($saveConfigBackup = true) && ($scriptError = false)) do={
        :do {
            /tool e-mail send to="$emailTo" subject="$emailSubjectOnSuccess" body="$emailBody\r\n\r\nBackup File: $backupFilename\r\nConfig File: $configFilename"
        }   on-error={
            :set errorMessage "Backup Script: Error sending error alert via email to $emailTo"
            :log error "$errorMessage"
            :set scriptError true
            :set exitBackupScript true
            }
    }
    
    :if (($saveSystemBackup = true) && ($saveConfigBackup = false) && ($scriptError = false)) do={
        :do {
            /tool e-mail send to="$emailTo" subject="$emailSubjectOnSuccess" body="$emailBody\r\n\r\nBackup File: $backupFilename\r\nConfig File: none"
        }   on-error={
            :set errorMessage "Backup Script: Error sending error alert via email to $emailTo"
            :log error "$errorMessage"
            :set scriptError true
            :set exitBackupScript true
            }
    }
    
    :if (($saveSystemBackup = false) && ($saveConfigBackup = true) && ($scriptError = false)) do={
        :do {
            /tool e-mail send to="$emailTo" subject="$emailSubjectOnSuccess" body="$emailBody\r\n\r\nBackup File: none\r\nConfig File: $configFilename"
        }   on-error={
            :set errorMessage "Backup Script: Error sending error alert via email to $emailTo"
            :log error "$errorMessage"
            :set scriptError true
            :set exitBackupScript true
            }
    } 
    
    :if (($saveSystemBackup = false) && ($saveConfigBackup = false) && ($scriptError = false)) do={
        :do {
            /tool e-mail send to="$emailTo" subject="$emailSubjectOnSuccess" body="$emailBody\r\n\r\nBackup File: none\r\nConfig File: none"
        }   on-error={
            :set errorMessage "Backup Script: Error sending error alert via email to $emailTo"
            :log error "$errorMessage"
            :set scriptError true
            :set exitBackupScript true
            }
    }

    :log info message="Backup Script: Sent backup alert via email to $emailTo"
}

# send email alert on error
:if (($emailAlertOnError = true) && ($scriptError = true)) do={
    :do {
        /tool e-mail send to="$emailTo" subject="$emailSubjectOnError" body="$errorMessage"
        :log info message="Backup Script: Sent backup alert via email to $emailTo"
    }   on-error {
            :log error "Backup Script: Error sending error alert via email to $emailTo"
        }
}

:log warning message="END: Backup Script"

Example: Email Alert Output (On Success)

MIKROTIK BACKUP SCRIPT SETTINGS

saveConfigBackup: true
saveSystemBackup: true
encryptSystemBackup: false
keepRecentLocalBackup: true

ftpUpload: true
ftpAddress: 192.168.88.100
ftpPort: 990
ftpUser: user
ftpDestination: /Backups

Backup File: MikroTik_MikroTikIdentity_RouterOS v6.40.4_2017.10.08_104456.backup
Config File: MikroTik_MikroTikIdentity_RouterOS v6.40.4_2017.10.08_104456.rsc

Example: Email Alert Output (On Error)

Backup Script: Error uploading system backup /disk1/backups/MikroTik_MikroTikIdentity_RouterOS v6.40.4_2017.10.08_104456.backup via FTP to 192.168.88.100

10 thoughts on “MikroTik Script: RouterOS Backup”

  1. Hi Marthur,
    I would really like to get this script of yours working properly. Unfortunately i am getting errors when trying to execute this script.
    I am assuming its because i am trying it on a new version of Mikrotik os (6.44)
    Have you tested your script on the latest version?

    Clive.

  2. Hi Marthur,
    thanks so much for that invaluable skript! Great job!
    I’m running that script on my RB3011 with 6.44.3. I copied the script and made my FTP and email adjustments, but the script still failed (action failed (6)). It took me some time to finally find the pitfall I fell in:
    It is the path to the destination directory for the configs and backups (“/disk1/backups”), which points to an external USB storage. As me and probably most new MT-users don’t use an USB thumb drive on MT, I assumed that the path points to the internal flashdrive. But it doesn’t, it’s to an external USB drive.
    Inserting an USB drive and formatting alone is only the half solution, as you either FTP to the MT and create a directory (“mkdir /disk1/backups”) or you change the destination directory to “/backups”. BTW, it makes totally sense not to save the backups on the internal storage. In case the MT stretches its legs for good you still have a copy of the backups on the USB drive.

    tl;dr:
    Maybe you can add a note regarding the destination path to an external USB drive. That may help MT beginners a lot! Probably that was also Clive’s problem in his post before.
    Keep on your great work!

    1. Yes, I store the backups on the USB for the same reason you pointed out for a local backup. You also made a good point to add a note regarding the destination path. I’ll add this shortly!

  3. Hello Marthur,
    Your script has stopped working as of ROS 7.8 (released earlier this week).
    Up till ROS 7.7 it worked correctly.

  4. Marthur – I came across this script and it was the closest I could find to meet my needs. I’m running RouterOS 7.10 vs version 6 this was written for. Everything generally worked, with the exception of date formatting – the date was already formatted correctly:

    [jhester@TechtricityRB750Gr3] /file> :put [/system/clock get date]
    2023-08-03

    So I just had to remove date parsing logic. After that, everything worked correctly.
    If you are no longer supporting, is it OK if I put up on my Github repo, so I can track changes and fix as RouterOS changes occur? Naturally I will leave your attribution in the header.

    Thanx!

    1. Hey John, thanks for chiming in. I haven’t been very active on this site at all, at some point I plan on updating it again, but I’m using a different firewall – though I haven’t forgotten about MikroTik, I may revisit the scripting side in the future. Until then, feel free to use the script on your Github repo. I’m glad that you have found it useful and appreciate your followup on how the script behaves with RouterOS v7.10

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top