-#!rsc by Vados\r
-# RouterOS script: AM-Backup-UpdateEmail\r
-# Script comment: Update and Backup send notification to EMail\r
-# Copyright (c) 2007-2026 Vados <vados@vados.ru>\r
-#\r
-#\r
-# requires RouterOS, version>=6.43.7\r
-# requires device-mode, fetch\r
-#\r
-# Updated: 15/04/2025\r
-# Website: https://github.com/beeyev\r
-# Notification e-mail (Make sure you have configured Email settings in Tools -> Email)\r
-:local ExitOK false;\r
-:onerror Err {\r
- :global GlobalConfReady; :global GlobalFuncReady;\r
- :retry { :if ($GlobalConfReady != true || $GlobalFuncReady != true) \\r
- do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;\r
- :local ScriptName [ :jobname ];\r
-\r
-:local IfThenElse do={:if ([ :tostr $1 ] = "true" || [ :tobool $1 ] = true) do={:return $2}; :return $3;}\r
-:local EitherOr do={\r
- :if ([ :typeof $1 ] = "num") do={:if (($1 != 0) = true) do={:return $1} else={:return $2};}\r
- :if ([ :typeof $1 ] = "time") do={:if (($1 > 0s) = true) do={:return $1} else={:return $2};}\r
- :if ([ :len [ :tostr $1 ] ] > 0) do={:return $1} else={:return $2};\r
-}\r
-:local ExitError do={\r
- :local ExitOK [ :tostr $1 ];\r
- :local Name [ :tostr $2 ];\r
- :local Error [ :tostr $3 ];\r
- :if ($ExitOK = "false") do={:log error ($Name [ $IfThenElse ([ :pick $Name 0 1 ] = "\$") \\r
- "Function" "Script" ] . " '" . $Name . "' exited with error" . \\r
- [ $IfThenElse (!($Error ~ "^(|true|false)\$")) (": " . $Error) "." ]);}\r
-}\r
-\r
-:global LogPrint;\r
-:global EditSchedulers;\r
-:global DevInfoIncludeIP;\r
-\r
-:local SchedInterval "7d";\r
-:local SchedStartTime "03:41:27";\r
-:local SchedComment "Every 7 Day Check For Update and Backup send notification to EMail.";\r
-\r
-# Function to add or edit schedulers for scripts, to ensure they are set up correctly\r
-# How to use:\r
-# Call this function with the following parameters:\r
-# 1. $1 - Scheduler name (usually same as script name) [*]\r
-# 2. $2 - Interval (e.g. "1d" (default is "1d")) [**]\r
-# 3. $3 - Start Time (e.g. "00:00:00", default is current time) [**]\r
-# 4. $4 - Comment (optional, default: "Scheduler for script: <name>") [**]\r
-# 5. $5 - On Event command (e.g. "/system/script { run <name>; }" (default is "/system/script { run $SchedName; }")) [**]\r
-# 6. $6 - Policy (e.g. "ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon" (default is the same)) [**]\r
-# 7. $7 - Start Date (e.g. "jan/01/1970", default is current date) [**]\r
-# Notes:\r
-# * - Scheduler name is required, and is used to identify the scheduler to create or edit. It is usually the same as the script name ($ScriptName).\r
-# ** - If optional parameters are not provided, default values will be used.\r
-# This allows for quick setup with minimal parameters, while still providing flexibility for customization.\r
-# Example usage:\r
-# :if ([ $EditSchedulers "my-script" ] = false) do={:set ExitOK false; :error true;}\r
-# :if ([ $EditSchedulers "my-script" "1d" "03:41:27" "My custom scheduler comment" false false "jan/01/1970" ] = false) do={:set ExitOK false; :error true;}\r
-\r
-:set EditSchedulers do={\r
- :local SchedName [ :tostr $1 ];\r
- :if ([ :len $SchedName ] = 0) do={ :return false; }\r
- :local Interval [ :tostr $2 ];\r
- :if ([ :len $Interval ] = 0) do={ :set Interval "1d"; }\r
- :local StartTime [ :tostr $3 ];\r
- :if ([ :len $StartTime ] = 0) do={ :set StartTime [/system/clock/get time]; }\r
- :local Comment [ :tostr $4 ];\r
- :if ([ :len $Comment ] = 0) do={ :set Comment "Scheduler for script: $SchedName"; }\r
- :local OnEvent [ :tostr $5 ];\r
- :if ([ :len $OnEvent ] = 0) do={ :set OnEvent "/system/script { run $SchedName; }"; }\r
- :local Policy [ :tostr $6 ];\r
- :if ([ :len $Policy ] = 0) do={ :set Policy "ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon"; }\r
- :local StartDate [ :tostr $7 ];\r
- :if ([ :len $StartDate ] = 0) do={ :set StartDate [/system/clock/get date]; }\r
-\r
- :onerror Err {\r
- # Check if scheduler exists, if not - create it\r
- :if ([ :len [ /system/scheduler/find where name=$SchedName ] ] = 0) do={\r
- :log warning ($SchedName . "System Scheduler for script: " . $SchedName . " is NOT SET! Fix It Now!");\r
- /system/scheduler/add comment=$Comment interval=$Interval name=$SchedName on-event=$OnEvent policy=$Policy start-date=$StartDate start-time=$StartTime;\r
- }\r
- # Check if scheduler parameters are correct, if not - fix them\r
- :if ([ /system/scheduler/get $SchedName comment ] != $Comment) do={\r
- /system/scheduler/set $SchedName comment=$Comment;\r
- }\r
- :if ([ /system/scheduler/get $SchedName interval ] != $Interval) do={\r
- /system/scheduler/set $SchedName interval=$Interval;\r
- }\r
- :if ([ /system/scheduler/get $SchedName on-event ] != $OnEvent) do={\r
- /system/scheduler/set $SchedName on-event=$OnEvent;\r
- }\r
- :if ([ /system/scheduler/get $SchedName policy ] != $Policy) do={\r
- /system/scheduler/set $SchedName policy=$Policy;\r
- }\r
- :if ([ /system/scheduler/get $SchedName start-date ] != $StartDate) do={\r
- /system/scheduler/set $SchedName start-date=$StartDate;\r
- }\r
- :if ([ /system/scheduler/get $SchedName start-time ] != $StartTime) do={\r
- /system/scheduler/set $SchedName start-time=$StartTime;\r
- }\r
- } do={:log error ($SchedName . "Failed to add/modify scheduler for '" . $SchedName . "' failed: " . $Err); :return false};\r
- :return true;\r
-}\r
-\r
-:if ([ $EditSchedulers $ScriptName $SchedInterval $SchedStartTime $SchedComment ] = false) do={\r
- :log error ($ScriptName . "Failed to add/modify scheduler for " . $ScriptName . "!");\r
- :set ExitOK true;\r
- :error true;\r
-}\r
-\r
-# Local Function CheckOSUpdateMode\r
-:local CheckOSUpdateMode;\r
-:set CheckOSUpdateMode do={\r
- :local NewMode [ :tostr $1 ];\r
- :if ([ :len $NewMode ] = 0) do={\r
- :log error ($0 . "/nFunction /$CheckOSUpdateMode received empty value!");\r
- :return false;\r
- :error true;\r
- }\r
-\r
- :global BackupAndUpdateMode;\r
- :global OldMode [ :tostr $BackupAndUpdateMode ];\r
- :if ($NewMode != $BackupAndUpdateMode && $NewMode = "updateOnce") do={\r
- :set BackupAndUpdateMode [ :tostr $NewMode ];\r
- :log info ($0 . "/nOk. /$BackupAndUpdateMode set to: '" . $NewMode . "'.\nYou're a good boy! ))\nI'm launching the update in 5 seconds.");\r
- :delay 5;\r
- /system/script { run $ScriptName; };\r
- } else={\r
- :log warning ($0 . "/nFunction /$CheckOSUpdateMode received value: '" . $NewMode . "', but is may be only \"updateOnce\"!");\r
- :return false;\r
- }\r
- :return true;\r
- :error false;\r
-}\r
-\r
-# :if ([ :len [ /system/scheduler/find where name="running-from-backup-partition" ] ] > 0) do={\r
-# $LogPrint warning $ScriptName ("Running from backup partition, refusing to act.");\r
-# :set ExitOK true;\r
-# :error false;\r
-# }\r
-\r
-:global EmailGeneralTo;\r
-:global BackupAndUpdateMode;\r
-:global forceBackup;\r
-:global BackupPassword;\r
-:global BackupSens;\r
-:global updateChannel;\r
-\r
-:global DevInfoIncludeIP;\r
-\r
-# Installs patch updates only (BackupAndUpdateMode = "osupdate").\r
-# Works for `stable` and `long-term` channels.\r
-# Updates only if MAJOR.MINOR match (e.g. 6.43.2 > 6.43.6 allowed, 6.44.1 skipped).\r
-# Sends info if a newer (non-patch) version is found.\r
-:local installOnlyPatchUpdates false;\r
-:local scriptVersion "26.04.30";\r
-:local copyrightUrl "https://www.github.com/vados-dev/";\r
-#Script messages prefix\r
-:local SMP "BkpAndUpdate:";\r
-\r
-:local exitErrorMessage "$SMP script stopped due to an error. Please check logs for more details.";\r
-:log info "\n\n$SMP Script \"Mikrotik RouterOS automatic backup & update\" v.$scriptVersion started.";\r
-:log info "$SMP Script Mode: `$BackupAndUpdateMode`, Update channel: `$updateChannel`, Force backup: `$forceBackup`, Install only patch updates: `$installOnlyPatchUpdates`";\r
-\r
-## vv FUNCTIONS vv ##\r
-:global WaitCheckUpdates; $WaitCheckUpdates;\r
-:global MiniDateTimeStamp;\r
-:local MDTSFix [$MiniDateTimeStamp];\r
-:global Identity;\r
-:global IdentityShort;\r
-:global devBoardName;\r
-:global runningVersion;\r
-:global runningChannel;\r
-:global devModel;\r
-:global devRbSerialNumber;\r
-:global ROsVerAvail;\r
-:global PkgUpdStatus;\r
-\r
-# Checks if two RouterOS version strings differ only by the patch version\r
-# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.2.4"] # Output: true\r
-# :put [$FuncIsPatchUpdateOnly "6.2.1" "6.3.1"] # Output: false\r
-:local FuncIsPatchUpdateOnly do={\r
- :local ver1 $1;\r
- :local ver2 $2;\r
- # Extract the major and minor components from a version\r
- :local extractMajorMinor do={\r
- :local ver $1;\r
- :local dot1 [:find $ver "."];\r
- :if ($dot1 = -1) do={:return $ver}\r
- :local major [:pick $ver 0 $dot1];\r
- :local rest [:pick $ver ($dot1 + 1) [:len $ver]];\r
- :local dot2 [:find $rest "."];\r
- :local minor $rest;\r
- :if ($dot2 >= 0) do={:set minor [:pick $rest 0 $dot2]}\r
- :return ($major . "." . $minor);\r
- }\r
-\r
-# Compare the major and minor components of both version strings\r
-:if ([$extractMajorMinor $ver1] = [$extractMajorMinor $ver2]) do={:return true}\r
- :return false;\r
-}\r
-# Creates backups and returns array of names\r
-# Possible arguments:\r
-# $1 - file name, without extension\r
-# $2 - password (optional)\r
-# $3 - sensitive data in config (optional, default: false)\r
-# Example:\r
-#:put [$FuncCreateBackups $backupName]\r
-:local FuncCreateBackups do={\r
- :local backupName [ :tostr $1 ];\r
- :local BackPass $2;\r
- :local BackSens $3;\r
-\r
- #Script messages prefix\r
- :local SMP "BkpAndUpdate:";\r
- :local exitErrorMessage "$SMP script stopped due to an error. Please check logs for more details.";\r
- :log info ("$SMP global function `FuncCreateBackups` started, input: `$backupName`");\r
-\r
- # validate required parameter: backupName\r
- :if ([:typeof $backupName] != "str" or [:len $backupName] = 0) do={\r
- :log error "$SMP parameter 'backupName' is required and must be a non-empty string";\r
-# :log warning "$SMP parameter '\$backupName' is required and must be a non-empty string.\nI set '\$backupName' to 'default-backup'";\r
-# :set $backupName "default-backup";\r
- :error $exitErrorMessage;\r
- }\r
-\r
- :local backupFileSys "$backupName.backup";\r
- :local backupFileConfig "$backupName.rsc";\r
- :local backupNames {$backupFileSys;$backupFileConfig};\r
-\r
- ## Perform system backup\r
- :if ([:len $BackPass] = 0) do={\r
- :log info ("$SMP starting backup without password, backup name: `$backupName`");\r
- /system backup save dont-encrypt=yes name=$backupName;\r
- } else={\r
- :log info ("$SMP starting backup with password, backup name: `$backupName`");\r
- /system backup save password=$BackPass name=$backupName;\r
- }\r
- :log info ("$SMP system backup created: `$backupFileSys`");\r
- ## Export config file\r
- :if ($BackSens = true) do={\r
- :log info ("$SMP starting export config with sensitive data, backup name: `$backupName`");\r
- # Since RouterOS v7 it needs to be explicitly set that we want to export sensitive data\r
- :if ([:pick [/system resource get version] 0 1] < 7) do={\r
- :execute "/export compact terse file=$backupName";\r
- } else={\r
- :execute "/export compact show-sensitive terse file=$backupName";\r
- }\r
- } else={\r
- :log info ("$SMP starting export config without sensitive data, backup name: `$backupName`");\r
- /export compact hide-sensitive terse file=$backupName;\r
- }\r
- :log info ("$SMP Config export complete: `$backupFileConfig`");\r
- :log info ("$SMP Waiting a little to ensure backup files are written");\r
- :delay 20;\r
- :if ([:len [/file find name=$backupFileSys]] > 0) do={\r
- :log info ("$SMP system backup file successfully saved to the file system: `$backupFileSys`");\r
- } else={\r
- :log error ("$SMP system backup was not created, file does not exist: `$backupFileSys`");\r
- :error $exitErrorMessage;\r
- }\r
- :if ([:len [/file find name=$backupFileConfig]] > 0) do={\r
- :log info ("$SMP config backup file successfully saved to the file system: `$backupFileConfig`");\r
- } else={\r
- :log error ("$SMP config backup was not created, file does not exist: `$backupFileConfig`");\r
- :error $exitErrorMessage;\r
- }\r
- :log info ("$SMP global function `FuncCreateBackups` finished. Created backups, system: `$backupFileSys`, config: `$backupFileConfig`")\r
- :return $backupNames;\r
-}\r
-# Sends an email\r
-# Parameters:\r
-# $1 - to (email address)\r
-# $2 - subject\r
-# $3 - body\r
-# $4 - file attachments (optional; pass "" if not needed)\r
-#\r
-# Example:\r
-# $FuncSendEmailSafe "admin@domain.com" "Backup Done" "Backup complete." "backup1.backup"\r
-:local FuncSendEmailSafe do={\r
- :global EmailGeneralTo;\r
- :local emailSubject $2;\r
- :local emailBody $3;\r
- :local emailAttachments $4;\r
- :local SMP "Bkp&Upd:";\r
- :local exitErrorMessage "$SMP script stopped due to an error. Please check logs for more details.";\r
- :log info "$SMP Attempting to send email to `$EmailGeneralTo`";\r
- # SAFETY: wait for any previously queued email to finish\r
- :local waitTimeoutPre 60;\r
- :local waitCounterPre 0;\r
- :while (([/tool e-mail get last-status] = "resolving-dns" or [/tool e-mail get last-status] = "in-progress")) do={\r
- :if ($waitCounterPre >= $waitTimeoutPre) do={\r
- :log error "$SMP Email send aborted: previous send did not complete after $waitTimeoutPre seconds";\r
- :error $exitErrorMessage;\r
- }\r
- :log info "$SMP Waiting for previous email to finish (status: $[/tool e-mail get last-status])...";\r
- :delay 1; \r
- :set waitCounterPre ($waitCounterPre + 1);\r
- }\r
- # Send the email\r
- :do {\r
- /tool e-mail send to=$EmailGeneralTo subject=$emailSubject body=$emailBody file=$emailAttachments;\r
- } on-error={\r
- :log error "$SMP Email send command failed to execute. Check logs and verify email settings.";\r
- :error $exitErrorMessage;\r
- }\r
- # Wait for send status to change from "in-progress" / "resolving-dns"\r
- :local waitTimeout 60;\r
- :local waitCounter 0;\r
- :local emailStatus "";\r
- :log info "$SMP Waiting for email to be sent, timeout in `$waitTimeout` seconds...";\r
- :while ($waitCounter < $waitTimeout) do={\r
- :set emailStatus [/tool e-mail get last-status];\r
- :if ($emailStatus != "in-progress" and $emailStatus != "resolving-dns") do={\r
- :log info "$SMP Email send status received: $emailStatus";\r
- # exit loop\r
- :set waitCounter $waitTimeout;\r
- } else={:delay 1; :set waitCounter ($waitCounter + 1)}\r
- }\r
- # Final decision based on last status\r
- :if ($emailStatus = "succeeded") do={\r
- :log info "$SMP Email successfully sent to `$EmailGeneralTo`";\r
- } else={\r
- :log error "$SMP Email failed to send. Status: `$emailStatus`. Check logs for more details and verify email settings.";\r
- :error $exitErrorMessage;\r
- }\r
-}\r
-# Global variable to track current update step\r
-# They need to be initialized here first to be available in the script\r
-:global buGlobalVarTargetOsVersion;\r
-:global buGlobalVarScriptStep;\r
-:local scriptStep $buGlobalVarScriptStep;\r
-:do {\r
- /system/script/environment remove buGlobalVarScriptStep;\r
-} on-error={}\r
-:if ([:len $scriptStep] = 0) do={\r
- :set scriptStep 1;\r
-}\r
-## ^^ FUNCTIONS ^^ ##\r
-#\r
-# Initial validation\r
-## Check email settings\r
-:if ([:len $EmailGeneralTo] < 3) do={\r
- :log error ("$SMP Parameter `\$EmailGeneralTo` is not set, or contains invalid value. Script stopped.");\r
- :error $exitErrorMessage;\r
-}\r
-# Values will be defined later in the script\r
-:local emailServer "";\r
-:local emailFromAddress [/tool e-mail get from];\r
-:log info "$SMP Validating email settings...";\r
-:do {\r
- :set emailServer [/tool e-mail get server];\r
-} on-error={\r
- # This is a workaround for the RouterOS v7.12 and older versions\r
- :set emailServer [/tool e-mail get address];\r
-}\r
-:if ($emailServer = "0.0.0.0") do={\r
- :log error ("$SMP Email server address is not correct: `$emailServer`, check `Tools -> Email`. Script stopped.");\r
- :error $exitErrorMessage;\r
-}\r
-:if ([:len $emailFromAddress] < 3) do={\r
- :log error ("$SMP Email configuration FROM address is not correct: `$emailFromAddress`, check `Tools -> Email`. Script stopped.");\r
- :error $exitErrorMessage;\r
-}\r
-# Script mode validation\r
-:if ($BackupAndUpdateMode != "backup" and $BackupAndUpdateMode != "osupdate" and $BackupAndUpdateMode != "updateOnce" and $BackupAndUpdateMode != "osnotify") do={\r
- :log error ("$SMP Script parameter `\$BackupAndUpdateMode` is not set, or contains invalid value: `$BackupAndUpdateMode`. Script stopped.");\r
- :error $exitErrorMessage;\r
-}\r
-# Update channel validation\r
-:if ($updateChannel != "stable" and $updateChannel != "long-term" and $updateChannel != "testing" and $updateChannel != "development") do={\r
- :log error ("$SMP Script parameter `\$updateChannel` is not set, or contains invalid value: `$updateChannel`. Script stopped.");\r
- :error $exitErrorMessage;\r
-}\r
-# Verify if script is set to install patch updates and if the update channel is valid\r
-:if (($BackupAndUpdateMode = "osupdate" or $BackupAndUpdateMode = "updateOnce") and $installOnlyPatchUpdates = true) do={\r
- :if ($updateChannel != "stable" and $updateChannel != "long-term") do={\r
- :log error ("$SMP Patch-only updates enabled, but update channel `$updateChannel` is invalid. Only `stable` and `long-term` are supported. Script stopped");\r
- :error $exitErrorMessage;\r
- }\r
- \r
- :if ($runningChannel != "stable" and $runningChannel != "long-term") do={\r
- :log error ("$SMP Script is set to install only patch updates, but the installed RouterOS version is not from `stable` or `long-term` channel: `$runningChannel`. Script stopped");\r
- :error $exitErrorMessage;\r
- }\r
-}\r
-#\r
-\r
-:local rawTime [/system clock get time];\r
-:local rawDate [/system clock get date];\r
-\r
-:local deviceOsVerAndChannelRunning [/system/resource/get version];\r
-\r
-:local backupNameTemplate ("backup_v" . $runningVersion . "_" . $runningChannel . "_" . $MDTSFix);\r
-:local backupNameBeforeUpdate ($backupNameTemplate . "_before_update");\r
-:local backupNameAfterUpdate ($backupNameTemplate . "_after_update");\r
-\r
-## Email body template\r
-:local mailSubjectPrefix "$SMP Device - `$IdentityShort`";\r
-:local mailBodyCopyright "Mikrotik RouterOS automatic backup & update (ver. $scriptVersion) \n$copyrightUrl";\r
-:local changelogUrl "Check RouterOS changelog: https://mikrotik.com/download/changelogs/";\r
-:local mailBodyDeviceInfo "";\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "Device information:");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\n---------------------");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nName: $Identity");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nModel: $devModel");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nBoard: $devBoardName");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nSerial number: $devRbSerialNumber");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nRouterOS version: v$deviceOsVerAndChannelRunning");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nBuild time: $[/system/resource/get build-time]");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nRouterboard FW Available: $ROsVerAvail");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nDevice date-time: $rawDate $rawTime ($[/system/clock/get time-zone-name ])");\r
-:set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nUptime: $[/system/resource/get uptime]");\r
-## IP address detection\r
-:if ([ $DevInfoIncludeIP ] = true) do={\r
- :global GetPubIp;\r
- :local PublicIpAddress [ $GetPubIp ];\r
- :set mailBodyDeviceInfo ($mailBodyDeviceInfo . "\nPublic IP address: " . $PublicIpAddress . ".");\r
- :log info "$SMP Public IP address detected: $PublicIpAddress";\r
-} \r
-\r
-:local mailAttachments [:toarray ""];\r
-:if ($scriptStep = 1 or $scriptStep = 3) do={\r
- :if ($scriptStep = 3) do={\r
- :log info ("$SMP Waiting for one minute before continuing to the final step.");\r
- :delay 1m;\r
- }\r
-}\r
-\r
-## STEP 1: Create backups, check for new RouterOS, and send email\r
-## Steps 2â3 run only if auto-update is enabled and a new version is available\r
-:if ($scriptStep = 1) do={\r
- :global BackupPassword;\r
- :global BackupSens;\r
- :local isNewOsUpdateAvailable false;\r
- :local isLatestOsAlreadyInstalled true;\r
- :local isOsNeedsToBeUpdated false;\r
- :local isUpdateCheckSucceeded false;\r
- :local isEmailNeedsToBeSent false;\r
- :local mailSubjectPartAction "";\r
- :local mailPtBodyAction "";\r
- :local mailPtSubjectBackup "";\r
- :local mailPtBodyBackup "";\r
- # Checking for new version\r
- :if ($BackupAndUpdateMode = "osupdate" or $BackupAndUpdateMode = "osnotify" or $BackupAndUpdateMode = "updateOnce") do={\r
- :log info ("$SMP Setting update channel to `$updateChannel`");\r
- /system/package/update/set channel=$updateChannel;\r
- :log info ("$SMP Checking for new RouterOS version. Current installed version is: `$runningVersion`");\r
- $LogPrint debug $ScriptName ("Checking for updates...");\r
- \r
-# /system/package/update/check-for-updates without-paging as-value;\r
-# /system/package/update check-for-updates;\r
- :delay 5s;\r
- :set PkgUpdStatus [ /system/package/update/get status ];\r
- :if ($PkgUpdStatus = "New version is available") do={\r
- :set ROsVerAvail [/system/package/update/get latest-version];\r
- }\r
-\r
- :if ($PkgUpdStatus = "New version is available") do={\r
- :log info ("$SMP New RouterOS version is available: `$ROsVerAvail`");\r
- :set isNewOsUpdateAvailable true;\r
- :set isLatestOsAlreadyInstalled false;\r
- :set isUpdateCheckSucceeded true;\r
- :set isEmailNeedsToBeSent true;\r
- :set mailSubjectPartAction "New RouterOS available";\r
- :set mailPtBodyAction "New RouterOS version is available, current version: v$runningVersion, new version: v$ROsVerAvail. \n$changelogUrl";\r
- } else={\r
- :if ($PkgUpdStatus = "System is already up to date") do={\r
- :log info ("$SMP No new RouterOS version is available, the latest version is already installed: `v$runningVersion`");\r
- :set isUpdateCheckSucceeded true;\r
- :set mailSubjectPartAction "No os update available";\r
- :set mailPtBodyAction "No new RouterOS version is available, the latest version is already installed: `v$runningVersion`";\r
- } else={\r
- :log error ("$SMP Failed to check for new RouterOS version. Package check status: `$PkgUpdStatus`");\r
- :set isEmailNeedsToBeSent true;\r
- :set mailSubjectPartAction "Error unable to check new os version";\r
- :set mailPtBodyAction "An error occurred while checking for a new RouterOS version.\nStatus returned: `$PkgUpdStatus`\n\nPlease review the logs on the device for more details and verify internet connectivity.";\r
- }\r
- }\r
- }\r
- # Checking if the script needs to install new os version\r
- :if (($BackupAndUpdateMode = "osupdate" or $BackupAndUpdateMode = "updateOnce") and $isNewOsUpdateAvailable = true) do={\r
- :if ($installOnlyPatchUpdates = true) do={\r
- :if ([$FuncIsPatchUpdateOnly $runningVersion $ROsVerAvail] = true) do={\r
- :log info "$SMP New RouterOS version is available, and it is a patch update. Current version: v$runningVersion, new version: v$ROsVerAvail";\r
- :set isOsNeedsToBeUpdated true;\r
- } else={\r
- :log info "$SMP The script will not install this update, because it is not a patch update. Current version: v$runningVersion, new version: v$ROsVerAvail";\r
- :set mailPtBodyAction ($mailPtBodyAction . "\nThis update will not be installed, because the script is set to install only patch updates.");\r
- }\r
- } else={\r
- :set isOsNeedsToBeUpdated true;\r
- }\r
- }\r
- # Checking If the script needs to create a backup\r
- :if ($forceBackup = true or $BackupAndUpdateMode = "backup" or $isOsNeedsToBeUpdated = true) do={\r
- :log info ("$SMP Starting backup process.");\r
- :set isEmailNeedsToBeSent true;\r
- :local backupName $backupNameTemplate;\r
- # This means it's the first step where we create a backup before the update process\r
- :if ($isOsNeedsToBeUpdated = true) do={\r
- :set backupName $backupNameBeforeUpdate;\r
- #Email body if the purpose of the script is to update the device\r
- :set mailSubjectPartAction "Update preparation";\r
- :set mailPtBodyAction ($mailPtBodyAction . "\nThe update process for device '$Identity' is scheduled to upgrade RouterOS from version v.$runningVersion to version v.$ROsVerAvail (Update channel: $updateChannel)");\r
- :set mailPtBodyAction ($mailPtBodyAction . "\nPlease note: The update will proceed only after a successful backup.");\r
- :set mailPtBodyAction ($mailPtBodyAction . "\nA final report with detailed information will be sent once the update process is completed.");\r
- :set mailPtBodyAction ($mailPtBodyAction . "\nIf you do not receive a second email within the next 10 minutes, there may be an issue. Please check your device logs for further information.");\r
- }\r
- :do {\r
- :set mailAttachments [$FuncCreateBackups $backupName $BackupPassword $BackupSens];\r
- :set mailPtSubjectBackup "Backup created";\r
- :set mailPtBodyBackup "System backups have been successfully created and attached to this email.";\r
- } on-error={\r
- :set isOsNeedsToBeUpdated false;\r
- :set mailPtSubjectBackup "Backup failed";\r
- :set mailPtBodyBackup "The script failed to create backups. Please check device logs for more details.";\r
- :log warning "$SMP Backup creation failed. Update process will be canceled if automatic update is enabled";\r
- }\r
- }\r
- :if ($isEmailNeedsToBeSent = true) do={\r
- :log info "$SMP Preparing to send email...";\r
- :local mailStep1Subject $mailSubjectPrefix;\r
- :local mailStep1Body "";\r
- # subject\r
- :if ($mailSubjectPartAction != "") do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailSubjectPartAction)}\r
- :if ($mailPtSubjectBackup != "") do={:set mailStep1Subject ($mailStep1Subject . " - " . $mailPtSubjectBackup)}\r
- # body\r
- :if ($mailPtBodyAction != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyAction . "\n\n")}\r
- :if ($mailPtBodyBackup != "") do={:set mailStep1Body ($mailStep1Body . $mailPtBodyBackup . "\n\n")}\r
- :set mailStep1Body ($mailStep1Body . $mailBodyDeviceInfo . "\n__________\n" . $mailBodyCopyright);\r
- :set mailStep1Body ($mailStep1Body . "\n[*** TEST START ***]\n\$DeviceInfo: " . [ $DeviceInfo ] . "\n[*** TEST END ***]\n");\r
- # Send email with backups\r
- :do {$FuncSendEmailSafe $EmailGeneralTo $mailStep1Subject $mailStep1Body $mailAttachments} on-error={\r
- :set isOsNeedsToBeUpdated false;\r
- :log error "$SMP The script will not proceed with the update process, because the email was not sent.";\r
- }\r
- }\r
- :if ([:len $mailAttachments] > 0) do={\r
- :log info "$SMP Cleaning up backup files from the file system...";\r
- /file remove $mailAttachments;\r
- :delay 2s;\r
- }\r
- :if ($isOsNeedsToBeUpdated = true) do={\r
- :global OldMode;\r
- :log info "$SMP everything is ready to install new RouterOS, going to start the update process and reboot the device.";\r
- :do {\r
- :local nextStep 2;\r
- :if ($isCloudHostedRouter = true) do={\r
- :log info "$SMP The device is a cloud hosted router, the second step updating the Routerboard firmware will be skipped.";\r
- :set nextStep 3;\r
- }\r
- :local scheduledCommand (":delay 5s; /system/scheduler remove BKPUPD-NEXT-BOOT-TASK; \\r
- :global buGlobalVarScriptStep $nextStep; :global buGlobalVarTargetOsVersion \"$ROsVerAvail\"; \\r
- :delay 10s; /system/script { run $ScriptName; }");\r
- /system/scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=$scheduledCommand start-time=startup interval=0;\r
- /system/package/update install;\r
- } on-error={\r
- # Failed to install new os version, remove the task and variables\r
- :do {\r
- /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;\r
- :set BackupAndUpdateMode $OldMode;\r
- :delay 2;\r
- :do {\r
- :global buGlobalVarTargetOsVersion (a);\r
- } on-error={\r
- :set $mailSubjectPrefix ($mailSubjectPrefix . "ERROR Remove global variable \$buGlobalVarTargetOsVersion failed!");\r
- }\r
-# :if ([ :len $OldMode ] > 0) do={\r
-# :do {\r
-# :global OldMode (a);\r
-# } on-error={\r
-# :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR Remove global variable \$OldMode failed!");\r
-# }\r
-# }\r
- } on-error={\r
- :log error "$SMP Failed to install new RouterOS version. Please check device logs for more details. \\r
- \nAnd Failed to remove task and variables! Check it!";\r
- :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR Remove task and global variables!");\r
- }\r
- :log error "$SMP Failed to install new RouterOS version. Please check device logs for more details.";\r
- :local mailUpdateErrorSubject ($mailSubjectPrefix . " - Update failed");\r
- :local mailUpdateErrorBody "The script was unable to install new RouterOS version. Please check device logs for more details.";\r
- # Send email with error\r
- $FuncSendEmailSafe $EmailGeneralTo $mailUpdateErrorSubject $mailUpdateErrorBody "";\r
- :error $exitErrorMessage;\r
- }\r
- }\r
-}\r
-## STEP 2: (Post-reboot) Upgrade RouterBOARD firmware\r
-## Runs only if auto-update is enabled and a new RouterOS version was found\r
-:if ($scriptStep = 2) do={\r
- :log info "$SMP The script is in the second step, updating Routerboard firmware.";\r
- :log info "$SMP Upgrading routerboard firmware from v.$deviceRbCurrentFw to v.$deviceRbUpgradeFw";\r
- /system routerboard upgrade;\r
- :delay 2;\r
- :log info "$SMP routerboard upgrade process was completed, going to reboot in a moment!";\r
- ## Set task to send final report on the next boot\r
- /system scheduler add name=BKPUPD-NEXT-BOOT-TASK on-event=":delay 2; :global buGlobalVarScriptStep 3; \\r
- :global buGlobalVarTargetOsVersion \"$buGlobalVarTargetOsVersion\"; :delay 10s; /system/script { run $ScriptName; }; \ \r
- :delay 5s; /system/scheduler remove BKPUPD-NEXT-BOOT-TASK;" start-time=startup interval=0;\r
- :delay 2;\r
- /system reboot;\r
-}\r
-\r
-## STEP 3: Final report (after second reboot, with delay).\r
-## Runs only if auto-update is enabled and a new RouterOS version was found.\r
-:if ($scriptStep = 3) do={\r
- :log info ("$SMP The script is in the third step, sending final report.");\r
- :local targetOsVersion $buGlobalVarTargetOsVersion;\r
- :do {\r
-# /system/script/environment remove [find name="buGlobalVarTargetOsVersion"];\r
- :global buGlobalVarTargetOsVersion (a);\r
- } on-error={\r
- :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR Remove global variable \$buGlobalVarTargetOsVersion failed!");\r
- }\r
-\r
- :if ([ :len $OldMode ] != 0) do={\r
- :do {\r
-# /system/script/environment remove [find name="OldMode"];\r
- :global OldMode (a);\r
- } on-error={\r
- :set $mailSubjectPrefix ($mailSubjectPrefix . " ERROR! Remove global variable \$OldMode failed!");\r
- }\r
- }\r
- :if ([:len $targetOsVersion] = 0) do={\r
- :log warning "$SMP Something is wrong, the script was unable to get the target updated OS version from the global variable.";\r
- }\r
- :local mailStep3Subject $mailSubjectPrefix;\r
- :local mailStep3Body "";\r
- :if ($targetOsVersion = $runningVersion) do={\r
- :log info "$SMP Successfully verified new RouterOS version: target: `$targetOsVersion`, current: `$runningVersion`";\r
- :set mailStep3Subject ($mailStep3Subject . " - Update completed - Backup created");\r
- :set mailStep3Body ($mailStep3Body . "RouterOS and routerboard upgrade process was completed");\r
- :set mailStep3Body ($mailStep3Body . "\nNew RouterOS version: v.$targetOsVersion, routerboard firmware: v.$deviceRbCurrentFw");\r
- :set mailStep3Body ($mailStep3Body . "\n$changelogUrl\nBackups of the upgraded system are in the attachment of this email.\n\n$mailBodyDeviceInfo\n\n$mailBodyCopyright");\r
- :set mailAttachments [$FuncCreateBackups $backupNameAfterUpdate $BackupPassword $BackupSens];\r
- } else={\r
- :log error "$SMP Failed to verify new RouterOS version: target: `$targetOsVersion`, current: `$runningVersion`";\r
- :set mailStep3Subject ($mailStep3Subject . " - Update failed");\r
- :set mailStep3Body ($mailStep3Body . "The script was unable to verify that the new RouterOS version was installed, target version: `$targetOsVersion`, current version: `$runningVersion`\nCheck device logs for more details.\n\n$mailBodyDeviceInfo\n\n$mailBodyCopyright");\r
- }\r
- $FuncSendEmailSafe $EmailGeneralTo $mailStep3Subject $mailStep3Body $mailAttachments;\r
- :if ([:len $mailAttachments] > 0) do={\r
- :log info "$SMP Cleaning up backup files from the file system...";\r
- /file remove $mailAttachments;\r
- :delay 2;\r
- }\r
- :log info ("$SMP Final report email sent successfully, and the script has finished.");\r
-}\r
-:log info ("$SMP the script has finished, script step: `$scriptStep` \n\n");\r
-\r
-} do={:global ExitError; $ExitError $ExitOK [ :jobname ] $Err}\r
+#!rsc by Vados
+# RouterOS script: AM-Fetch-Generator
+# Script comment: Downloader for Amnezia generated scripts
+# Copyright (c) 2007-2026 Vados <vados@vados.ru>
+#
+#
+# requires RouterOS, version>=6.43.7
+# requires device-mode, fetch
+#
+# Updated: 17/08/2026
+# Website: https://github.com/vados-dev/
+#:local ExitOK false;
+#:onerror Err {
+# :global GlobalConfReady; :global GlobalFuncReady;
+# :retry { :if ($GlobalConfReady != true || $GlobalFuncReady != true) \
+# do={ :error ("Global config and/or functions not ready."); }; } delay=500ms max=50;
+# :local ScriptName [ :jobname ];
+# ============================================================
+# AWG Proxy -- MikroTik RouterOS (protocol: v2)
+# 2026-07-21 10:33:39
+# ============================================================
+
+# 0. Check prerequisites
+:if ([:len [/system/package/find where name="container" disabled=no]] = 0) do={
+ :put "Container package is not installed or disabled. Install it and reboot."
+ :error "Usage: /system/device-mode/update container=yes"
+}
+
+# Check storage device
+{
+ :local targetDisk "usb1"
+ :local diskFree 0
+ :do { :set diskFree [/disk/get [find where mount-point=$targetDisk] free] } on-error={}
+ :if ($diskFree = 0) do={
+ :local baseDisk $targetDisk
+ :local dashPos [:find $targetDisk "-part"]
+ :if ([:typeof $dashPos] != "nil") do={ :set baseDisk [:pick $targetDisk 0 $dashPos] }
+ :if ([:len [/disk/find where slot=$baseDisk]] > 0) do={
+ :put ("Device $baseDisk found but $targetDisk is not available.")
+ :put "Format $baseDisk as ext4? ALL DATA WILL BE ERASED!"
+ :put "Press 'y' to confirm, any other key to cancel:"
+ :local key [/terminal/inkey timeout=30]
+ :if ($key = 121 || $key = 89) do={
+ :put "Formatting $baseDisk as ext4..."
+ /disk/format-drive $baseDisk file-system=ext4 label=$baseDisk
+ :delay 3s
+ :do { :set diskFree [/disk/get [find where mount-point=$targetDisk] free] } on-error={}
+ :if ($diskFree = 0) do={
+ :put ("ERROR: $targetDisk not found after formatting.")
+ :put "Check mount point: /disk/print"
+ :error ("Mount point $targetDisk not found after formatting")
+ }
+ :put ("Formatted OK. Free: " . ($diskFree / 1048576) . " MB")
+ } else={
+ :error "Formatting cancelled"
+ }
+ } else={
+ :put ("ERROR: Storage device $targetDisk not found.")
+ :put "Check available disks: /disk/print"
+ :error ("Storage not found: " . $targetDisk)
+ }
+ } else={
+ :put ("Storage OK: $targetDisk (" . ($diskFree / 1048576) . " MB free)")
+ }
+}
+
+# 1. Uninstall script
+/system/script/add name=awg2vds-uninstall comment=awg2vds source={
+ :put "Uninstallimg AmneziaWG..."
+ :log info "Uninstallimg AmneziaWG..."
+ :local prevDNS ""
+ :do { :set prevDNS [/container/envs/get [find where list="awg2vds-env" key="AWG_PREV_DNS"] value] } on-error={}
+ :local prevTmpdir ""
+ :do { :set prevTmpdir [/container/envs/get [find where list="awg2vds-env" key="AWG_PREV_TMPDIR"] value] } on-error={}
+ /ip/route/remove [find where comment=awg2vds-tunnel]
+ /ip/route/remove [find where comment=awg2vds-dns]
+ /container/stop [find where interface=veth-awg2vds]
+ :delay 7s
+ /container/remove [find where interface=veth-awg2vds]
+ /container/envs/remove [find where list="awg2vds-env"]
+ :if ($prevDNS != "") do={
+ :do { /ip/dns/set servers="$prevDNS" } on-error={}
+ :put ("DNS restored to: $prevDNS")
+ }
+ /container/config set tmpdir=$prevTmpdir
+ :put ("Container tmpdir restored to: $prevTmpdir")
+ /ip/firewall/nat/remove [find where out-interface="wg-awg2vds"]
+ /ip/firewall/nat/remove [find where src-address="172.20.200.68/30"]
+ /ip/address/remove [find where address="172.20.200.69/30"]
+ /interface/veth/remove [find where name="veth-awg2vds"]
+ /interface/wireguard/peers/remove [find where interface="wg-awg2vds"]
+ /ip/address/remove [find where interface="wg-awg2vds"]
+ /interface/wireguard/remove [find where name="wg-awg2vds"]
+ :do { /file/remove [find where name~"awg2vds.+tar"] } on-error={}
+ :do { /file/remove [find where name="usb1/awg2vds"] } on-error={}
+ :do { /file/remove [find where name="usb1/ru_ranges_timeout.rsc"] } on-error={}
+ :do { /file/remove [find where name~"usb1/pull"] } on-error={}
+ :put "Uninstall AmneziaWG Proxy complete!"
+ :log info "Uninstall AmneziaWG Proxy complete!"
+ /system/script/remove [find where name=awg2vds-uninstall]
+}
+
+# 2. Network infrastructure
+/interface/veth/add name=veth-awg2vds address=172.20.200.70/30 gateway=172.20.200.69
+/ip/address/add address=172.20.200.69/30 interface=veth-awg2vds
+/ip/firewall/nat/add chain=srcnat action=masquerade src-address=172.20.200.68/30
+
+# 3. WireGuard interface (MikroTik derives the public key automatically)
+/interface/wireguard/add name=wg-awg2vds private-key="4LNSJJNEDeT2LFXkFx0XyrNp2Mp7YXlS8SawhqNfKGQ=" listen-port=26084 disabled=yes
+/interface/wireguard/peers/add interface=wg-awg2vds public-key="qHFd72XDJJ5UrUZCZ0vRFQmzxP7eUYcOuaGL9ZbHtyg=" preshared-key="ckhzjCcr15ve+IeDRYveYITR7a/CMZCcOZ2Z0cABKD8=" endpoint-address=172.20.200.70 endpoint-port=51820 allowed-address=10.10.10.1/24,10.30.30.0/24,0.0.0.0/0 persistent-keepalive=10
+/ip/address/add address=10.10.10.2/24 interface=wg-awg2vds
+
+# 4. Container environment variables
+/container/envs/add list=awg2vds-env key=AWG_LISTEN value=":51820"
+/container/envs/add list=awg2vds-env key=AWG_REMOTE value="109.107.177.79:443"
+/container/envs/add list=awg2vds-env key=AWG_JC value="6"
+/container/envs/add list=awg2vds-env key=AWG_JMIN value="171"
+/container/envs/add list=awg2vds-env key=AWG_JMAX value="481"
+/container/envs/add list=awg2vds-env key=AWG_S1 value="50"
+/container/envs/add list=awg2vds-env key=AWG_S2 value="139"
+/container/envs/add list=awg2vds-env key=AWG_H1 value="1189447486-1189448396"
+/container/envs/add list=awg2vds-env key=AWG_H2 value="538303610-538304276"
+/container/envs/add list=awg2vds-env key=AWG_H3 value="101001960-101002598"
+/container/envs/add list=awg2vds-env key=AWG_H4 value="1783887443-1783887851"
+/container/envs/add list=awg2vds-env key=AWG_SERVER_PUB value="qHFd72XDJJ5UrUZCZ0vRFQmzxP7eUYcOuaGL9ZbHtyg="
+/container/envs/add list=awg2vds-env key=AWG_CLIENT_PUB value=[/interface/wireguard/get [find name=wg-awg2vds] public-key]
+/container/envs/add list=awg2vds-env key=AWG_S3 value="17"
+/container/envs/add list=awg2vds-env key=AWG_S4 value="6"
+/container/envs/add list=awg2vds-env key=AWG_I1 value="<b 0x000100182112a442><r 12><b 0x80220009706a70726f6a65637400000080280004><r 4>"
+/container/envs/add list=awg2vds-env key=AWG_I2 value="<r 32><t>"
+/container/envs/add list=awg2vds-env key=AWG_I3 value="<rd 16><r 24>"
+/container/envs/add list=awg2vds-env key=AWG_I4 value="<t><rc 20>"
+/container/envs/add list=awg2vds-env key=AWG_I5 value="<r 18>"
+
+# 5. DNS
+{ :local rawDNS [/ip/dns/get servers]; :local prevDNS ""; :foreach s in=[:toarray $rawDNS] do={ :if ([:len $prevDNS] > 0) do={ :set prevDNS "$prevDNS,$s" } else={ :set prevDNS $s } }; /container/envs/add list=awg2vds-env key=AWG_PREV_DNS value="$prevDNS" }
+# NOTE: replaces existing DNS configuration
+/ip/dns/set servers=10.10.10.1
+/ip/route/add dst-address=10.10.10.1/32 gateway=wg-awg2vds distance=1 comment=awg2vds-dns
+
+# 6. Download, create and start container
+:local prevTmpdir [/container/config/get tmpdir]
+/container/envs/add list=awg2vds-env key=AWG_PREV_TMPDIR value=$prevTmpdir
+/container/config set tmpdir=usb1/pull memory-high=200M
+{
+ :local arch [/system/resource/get architecture-name]
+ :local ver [/system/resource/get version]
+ :local dotPos [:find $ver "."]
+ :local rest [:pick $ver ($dotPos + 1) [:len $ver]]
+ :local endPos [:find $rest "."]
+ :if ([:typeof $endPos] = "nil") do={ :set endPos [:find $rest " "] }
+ :local minor [:tonum [:pick $rest 0 $endPos]]
+ :local suffix ""
+ :if ($minor <= 20) do={ :set suffix "-7.20-Docker" }
+ :local file ""
+ :if ($arch = "arm64") do={ :set file ("awg-proxy-arm64" . $suffix . ".tar.gz") }
+ :if ($arch = "arm") do={ :set file ("awg-proxy-arm" . $suffix . ".tar.gz") }
+ :if ($arch ~ "x86") do={ :set file ("awg-proxy-amd64" . $suffix . ".tar.gz") }
+ :if ($file = "") do={ :error "Unsupported architecture: $arch" }
+ #:local url "https://github.com/timbrs/amneziawg-mikrotik-c/releases/latest/download/$file"
+ :local url "https://ros.vados.ru/amneziawg/img/$file"
+ :local filePath ("usb1/pull/" . $file)
+ :do { /file/make-directory usb1/pull } on-error={}
+ :if ([:len [/file/find where name=$filePath]] = 0) do={
+ :local freeStorage 0
+ :do { :set freeStorage [/disk/get [find where mount-point="usb1"] free] } on-error={}
+ :if ($freeStorage < 262144) do={
+ :put ("WARNING: Low disk space (" . ($freeStorage / 1024) . "KB free). Need at least 256KB.")
+ :put "See: https://github.com/timbrs/amneziawg-mikrotik-c#insufficient-disk-space"
+ :error "Insufficient disk space"
+ }
+ :put ("Fetching: $url -> " . $filePath)
+ /tool/fetch url=$url dst-path=$filePath http-max-redirect-count=10
+ } else={
+ :put ("File already exists: " . $filePath)
+ }
+ /container/add file=$filePath interface=veth-awg2vds envlist=awg2vds-env hostname=awg2vds root-dir=usb1/awg2vds logging=no start-on-boot=yes comment=awg2vds
+ :if ($minor > 20) do={ [:parse "/container/set [find where interface=veth-awg2vds] shm-size=4M"] }
+ /file/remove $filePath
+ :local freeMem [/system/resource/get free-memory]
+ :if ($freeMem < 16777216) do={
+ :put ("WARNING: Low memory (" . ($freeMem / 1048576) . "MB free). 16MB+ recommended.")
+ }
+ /container/start [find where interface=veth-awg2vds]
+ :do { /file/remove [find where name="console-dump.txt"] } on-error={}
+ :put "Waiting for container to start..."
+ :delay 5s
+ /interface/wireguard/enable wg-awg2vds
+ :put "WireGuard interface enabled"
+ :put "Installation complete!"
+ :put "Ping test: 10.10.10.1 via AmneziaWG tunnel. repeat 10 times"
+ /ping 10.10.10.1 count=10 interval=1
+ :put ""
+ :put "======= NEXT STEPS ======="
+ :put ""
+ :put "Route specific traffic through the AmneziaWG tunnel:"
+ :put ""
+ :put " Route a single host:"
+ :put " /ip/route/add dst-address=8.8.8.8/32 gateway=wg-awg2vds comment=awg2vds-tunnel"
+ :put ""
+ :put " Route a subnet:"
+ :put " /ip/route/add dst-address=100.0.0.0/8 gateway=wg-awg2vds comment=awg2vds-tunnel"
+ :put ""
+ :put " Remove a route:"
+ :put " /ip/route/remove [find where comment=awg2vds-tunnel dst-address=8.8.8.8/32]"
+ :put ""
+ :put " Show all tunnel routes:"
+ :put " /ip/route/print where comment=awg2vds-tunnel"
+ :put ""
+ :put " Uninstall:"
+ :put " /system/script/run awg2vds-uninstall"
+ :put "========================="
+}
+
+# 7. Verification
+# /container/print
+# /interface/wireguard/print
+# /interface/wireguard/peers/print