Script to change NordVPN server address

I noticed after getting NordVPN to work with my router, you’re pretty much stuck with the same IP address for a long time. I am pretty weak on scripting but gathered enough info to write a script that changes the NordVPN server address, wait 2 seconds for it to happen, and then flush all active connections:

/ip ipsec peer set NordVPN address=us9296.nordvpn.com;
:delay 2000ms;
:foreach ENTRY in=[/ip firewall address-list find list="NordVPN"] do={
 :local IP [/ip firewall address-list get number=$ENTRY address ];
  :foreach CONN in=[/ip firewall connection find src-address~"$IP:"] do={
   /ip firewall connection remove $CONN;
  
   }
}

I would like to build an address list of NordVPN servers and have the script execute maybe once every couple days and pick a different one on the list. Is there a way to index to the next one on the list each time it runs? Maybe trigger off a keyword in the comments? Any guidance would be appreciated.

A small contribution:

{
:local update do={
:global dataNordVPN
:local data $dataNordVPN
  :do {
  :put "Reading and displaying from the JSON file, the values for the $valname field:"
   :while ([:len $data]!=0) do={
         :set $fieldname ($valname."\":\"")
         :set $delimiter "\""
         if ($numval = "yes") do={:set $fieldname ($valname."\":"); :set $delimiter ","}
         :local position ([:find $data "$fieldname"]+[len $fieldname])
         :put [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data "}}]}"])]) $delimiter ]))]
     :set $data [:pick $data ([:find $data "}}]}"]+5) [:len $data]]
   } ;  :put "Read field $valname from file: $url"
   } 
 }
:global dataNordVPN ([/ tool fetch http-header-field="User-Agent: Mozilla/4.0" "https://api.nordvpn.com/v1/servers/recommendations\?limit=3" output=user as-value ]->"data")
$update valname="hostname"
$update valname="load" numval="yes"
$update valname="station"
# erase and remove global variable $dataNordVPN
:set $dataNordVPN  
}

Hostname → nl752.nordvpn.com
numval → 0 (load)
station → 213.232.87.182

etc.

http://forum.mikrotik.com/t/strange-cert-error-with-some-nordvpn-connections/141019/3

Not tested but you get intention:

{
:local update do={
:local dataNordVPN
:local data $dataNordVPN
  :do {
  :put "Reading and displaying from the JSON file, the values for the $valname field:"
   :while ([:len $data]!=0) do={
         :set $fieldname ($valname."\":\"")
         :set $delimiter "\""
         if ($numval = "yes") do={:set $fieldname ($valname."\":"); :set $delimiter ","}
         :local position ([:find $data "$fieldname"]+[len $fieldname])
         :put [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data "}}]}"])]) $delimiter ]))]
     :set $data [:pick $data ([:find $data "}}]}"]+5) [:len $data]]
   } ;  :put "Read field $valname from file: $url"
   } 
 }
 
:local dataNordVPN ([/ tool fetch http-header-field="User-Agent: Mozilla/4.0" "https://api.nordvpn.com/v1/servers/recommendations\?limit=3" output=user as-value ]->"data")

:local oldname ([:pick [/ip ipsec peer  print as-value where address~"Nord"] 0]->"address")
:local newname ([$update valname="hostname"])
:local $ip ([:resolve $oldname])
/ip ipsec peer set NordVPN address=$newname
:delay 2000ms;
/ip ipsec active-peers remove [find id=$oldname]

  :foreach CONN in=[/ip firewall connection find src-address~"$IP:"] do={
    /ip firewall connection remove $CONN;
  }
}
}

Maybe, you don’t even need to remove the “oldname” from active-peers.

Thanks! That gives me a lot to work with. I tried running the script as is just to see what would happen and it produced no output in the environment. I tested the URL by copying directly in Firefox: https://api.nordvpn.com/v1/servers/recommendations?limit=3 and it gives a “not found message”. If I leave off the “\limit=3” in Firefox it will return a huge list of JSON data. Not sure what I’m doing wrong.

You past it into a terminal and the press enter twice. It needs DNS and port 443.

Got it. That works. Thanks for your patience. I have a lot to learn…

So after going cross eyed and studying script syntax, I made a couple changes to your last script for testing since it wasn’t setting the newname:

{
:global update do={
:global dataNordVPN
:global newname
:global data $dataNordVPN
  :do {
  :put "Reading and displaying from the JSON file, the values for the $valname field:"
   :while ([:len $data]!=0) do={
         :set $fieldname ($valname."\":\"")
         :set $delimiter "\""
         if ($numval = "yes") do={:set $fieldname ($valname."\":"); :set $delimiter ","}
         :local position ([:find $data "$fieldname"]+[len $fieldname])
         :set newname [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data "}}]}"])]) $delimiter ]))]
     :set $data [:pick $data ([:find $data "}}]}"]+5) [:len $data]]
   } ;  :put "Read field $valname from file: $url"
   } 
 } 
:global dataNordVPN ([/ tool fetch http-header-field="User-Agent: Mozilla/4.0" "https://api.nordvpn.com/v1/servers/recommendations\?limit=1" output=user as-value ]->"data")
:local oldname ([:pick [/ip ipsec peer print as-value where name~"NordVPN"] 0]->"address")
$update valname="hostname"
:put "old name = $oldname"
:put "new name = $newname"
}

It seems to work as it gives me a proper value. Here’s the output from the terminal:

[XXXXX@FXXXXX] > {
{… :global update do={
{{… :global dataNordVPN
{{… :global newname
{{… :global data $dataNordVPN
{{… :do {
{{{… :put “Reading and displaying from the JSON file, the values for the $valname field:”
{{{… :while ([:len $data]!=0) do={
{{{{… :set $fieldname ($valname.“":"”)
{{{{… :set $delimiter “"”
{{{{… if ($numval = “yes”) do={:set $fieldname ($valname.“":”); :set $delimiter “,”}
{{{{… :local position ([:find $data “$fieldname”]+[len $fieldname])
{{{{… :set newname [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data “}}]}”])]) $delimiter ]))]
{{{{… :set $data [:pick $data ([:find $data “}}]}”]+5) [:len $data]]
{{{{… } ; :put “Read field $valname from file: $url”
{{{… }
{{… }
{… :global dataNordVPN ([/ tool fetch http-header-field=“User-Agent: Mozilla/4.0” "> https://api.nordvpn.com/v1/servers/recommendations?limit=1> " output=user as-value
]->“data”)
{… :local oldname ([:pick [/ip ipsec peer print as-value where name~“NordVPN”] 0]->“address”)
{… $update valname=“hostname”
{… :put “old name = $oldname”
{… :put “new name = $newname”
{… }
Reading and displaying from the JSON file, the values for the hostname field:
Read field hostname from file:
old name = us9296.nordvpn.com
new name = us9324.nordvpn.com

You really got me off ground zero and I am learning a lot about scripting. I just need to take this another step and set the peer to the new name.

Here’s the final version that seems to work. Just need to add it to the scheduler:

EDIT: I simplified a bit for my specific needs.

{
:global dataNordVPN ([/ tool fetch http-header-field="User-Agent: Mozilla/4.0" "https://api.nordvpn.com/v1/servers/recommendations\?limit=1" output=user as-value ]->"data")
:global newname
:global data $dataNordVPN
  :do {
   :local valname "hostname"
   :put "Reading and displaying from the JSON file, the values for the $valname field:"
   :while ([:len $data]!=0) do={
         :set $fieldname ($valname."\":\"")
         :set $delimiter "\""
         if ($numval = "yes") do={:set $fieldname ($valname."\":"); :set $delimiter ","}
         :local position ([:find $data "$fieldname"]+[len $fieldname])
         :set newname [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data "}}]}"])]) $delimiter ]))]
     :set $data [:pick $data ([:find $data "}}]}"]+5) [:len $data]]
   } ;  :put "Read field $valname from file: $url"
   } 
:local oldname ([:pick [/ip ipsec peer print as-value where name~"NordVPN"] 0]->"address")
:put "old name = $oldname"
:put "new name = $newname"
/ip ipsec peer set NordVPN address=$newname
:delay 5000ms;
#erase and remove global variables
:set $dataNordVPN  
:set $newname
:set $data
}

And that optimized not tested on your script:

{
:local newname
:local data ([/tool fetch http-header-field="User-Agent: Mozilla/4.0" "https://api.nordvpn.com/v1/servers/recommendations\?limit=2" output=user as-value ]->"data")
  :do {
   :local valname "hostname"
   :local encryption "ikev2"
   :put "Reading and displaying from the JSON file, the values for the $valname field and searching for $encryption encryption:"
   :while ([:len $data]!=0) do={
         :set $fieldname ($valname."\":\"")
         :set $delimiter "\""
:if (([:find ([:pick $data 0 ([find $data "}}]}"])]) $encryption ])) do={
         if ($numval = "yes") do={:set $fieldname ($valname."\":"); :set $delimiter ","}
         :local position ([:find $data "$fieldname"]+[len $fieldname])
         :set newname [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data "}}]}"])]) $delimiter ]))]
}
     :set $data [:pick $data ([:find $data "}}]}"]+5) [:len $data]]
   } 
  } 
:local oldname ([:pick [/ip ipsec peer print as-value where name~"NordVPN"] 0]->"address")
:put "old name = $oldname"
:put "new name = $newname"
:if ([:len $newname] > 0) do={/ip ipsec peer set NordVPN address=$newname}
}

Uses only :local variables so no need to erase them as cleaning :global. Local variables are automatically erased when the script ends.

Updated the script to not set the newname if it is empty. And I have added the encryption type so you can select IKEv2 or at a later time wireguard_udp. To find those, I had increase the number of records to be retrieved to …ers/recommendations?limit=2

Nice to see a script being made just for fun, now is actually being used.

It works! Thanks for all your help. It’s been a great learning experience.

HI there! Is it just me or the script is no longer working?

I mean, with the current code it provides an empty output, while removing the “as value” at the end it prints the full JSON. I guess something in the JSON structure has changed and the current script cannot locate the hostname anymore in the JSON blob?

I’m using this on 6.49.2 and appreciate the help from anyone who can make this work. Thanks!

Try it without the: ?limit=2

Thanks but without the limit it takes a much longer time but still provides no value for the new server.

Without the as-value parameter this is the output (hopefully it helps finding out what’s different in the JSON structure):

status: finished
  downloaded: 6KiBC-z pause]
        data: [{"id":970313,"created_at":"2020-08-04 07:53:38","updated_at":"2021-12-27 20:32:10","name":"Italy #184","station":"84.17.59.150","ipv6_station":"",
              "hostname":"it184.nordvpn.com","load":13,"status":"online","locations":[{"id":3978,"created_at":"2018-06-18 11:48:51","updated_at":"2018-06-18 11:48:51","latitude":45.466667,
              "longitude":9.2,"country":{"id":106,"name":"Italy","code":"IT","city":{"id":4542737,"name":"Milan","latitude":45.466667,"longitude":9.2,"dns_name":"milan","hub_score":0}}}],
              "services":[{"id":1,"name":"VPN","identifier":"vpn","created_at":"2017-03-21 12:00:45","updated_at":"2017-05-25 13:12:31"},{"id":5,"name":"Proxy","identifier":"proxy",
              "created_at":"2017-05-29 19:38:30","updated_at":"2017-05-29 19:38:30"}],"technologies":[{"id":1,"name":"IKEv2/IPSec","identifier":"ikev2","created_at":"2017-03-21 12:00:24",
              "updated_at":"2017-09-05 14:20:16","metadata":[],"pivot":{"technology_id":1,"server_id":970313,"status":"online"}},{"id":3,"name":"OpenVPN UDP","identifier":"openvpn_udp",
              "created_at":"2017-05-04 08:03:24","updated_at":"2017-05-09 19:27:37","metadata":[],"pivot":{"technology_id":3,"server_id":970313,"status":"online"}},{"id":5,"name":"OpenVPN 
              TCP","identifier":"openvpn_tcp","created_at":"2017-05-09 19:28:14","updated_at":"2017-05-09 19:28:14","metadata":[],"pivot":{"technology_id":5,"server_id":970313,
              "status":"online"}},{"id":21,"name":"HTTP Proxy (SSL)","identifier":"proxy_ssl","created_at":"2017-10-02 12:45:14","updated_at":"2017-10-02 12:45:14","metadata":[],
              "pivot":{"technology_id":21,"server_id":970313,"status":"online"}},{"id":23,"name":"HTTP CyberSec Proxy (SSL)","identifier":"proxy_ssl_cybersec","created_at":"2017-10-02 
              12:50:49","updated_at":"2017-10-02 12:50:49","metadata":[],"pivot":{"technology_id":23,"server_id":970313,"status":"online"}},{"id":35,"name":"Wireguard",
              "identifier":"wireguard_udp","created_at":"2019-02-14 14:08:43","updated_at":"2019-02-14 14:08:43","metadata":[{"name":"public_key",
              "value":"FgxaycYZ4t1kp4x7LDv60sczNTAl0h/d4pyyUNHhgBc="}],"pivot":{"technology_id":35,"server_id":970313,"status":"online"}}],"groups":[{"id":11,"created_at":"2017-06-13 
              13:43:00","updated_at":"2017-06-13 13:43:00","title":"Standard VPN servers","identifier":"legacy_standard","type":{"id":3,"created_at":"2017-06-13 13:40:17",
              "updated_at":"2017-06-13 13:40:23","title":"Legacy category","identifier":"legacy_group_category"}},{"id":15,"created_at":"2017-06-13 13:43:38","updated_at":"2017-06-13 
              13:43:38","title":"P2P","identifier":"legacy_p2p","type":{"id":3,"created_at":"2017-06-13 13:40:17","updated_at":"2017-06-13 13:40:23","title":"Legacy category",
              "identifier":"legacy_group_category"}},{"id":19,"created_at":"2017-10-27 14:17:17","updated_at":"2017-10-27 14:17:17","title":"Europe","identifier":"europe","type":{"id":5,
              "created_at":"2017-10-27 14:16:30","updated_at":"2017-10-27 14:16:30","title":"Regions","identifier":"regions"}}],"specifications":[{"id":8,"title":"Version",
              "identifier":"version","values":[{"id":257,"value":"2.1.0"}]}],"ips":[{"id":408903,"created_at":"2021-10-19 11:23:55","updated_at":"2021-10-19 11:23:55","server_id":970313,
              "ip_id":74832,"type":"entry","ip":{"id":74832,"ip":"84.17.59.150","version":4}}],"cpt":0},{"id":972647,"created_at":"2020-08-18 08:25:41","updated_at":"2021-12-27 20:32:11",
              "name":"Italy #197","station":"217.138.197.51","ipv6_station":"","hostname":"it197.nordvpn.com","load":13,"status":"online","locations":[{"id":3978,"created_at":"2018-06-18 
              11:48:51","updated_at":"2018-06-18 11:48:51","latitude":45.466667,"longitude":9.2,"country":{"id":106,"name":"Italy","code":"IT","city":{"id":4542737,"name":"Milan",
              "latitude":45.466667,"longitude":9.2,"dns_name":"milan","hub_score":0}}}],"services":[{"id":1,"name":"VPN","identifier":"vpn","created_at":"2017-03-21 12:00:45",
              "updated_at":"2017-05-25 13:12:31"},{"id":5,"name":"Proxy","identifier":"proxy","created_at":"2017-05-29 19:38:30","updated_at":"2017-05-29 19:38:30"}],
              "technologies":[{"id":1,"name":"IKEv2/IPSec","identifier":"ikev2","created_at":"2017-03-21 12:00:24","updated_at":"2017-09-05 14:20:16","metadata":[],
              "pivot":{"technology_id":1,"server_id":972647,"status":"online"}},{"id":3,"name":"OpenVPN UDP","identifier":"openvpn_udp","created_at":"2017-05-04 08:03:24",
              "updated_at":"2017-05-09 19:27:37","metadata":[],"pivot":{"technology_id":3,"server_id":972647,"status":"online"}},{"id":5,"name":"OpenVPN TCP","identifier":"openvpn_tcp",
              "created_at":"2017-05-09 19:28:14","updated_at":"2017-05-09 19:28:14","metadata":[],"pivot":{"technology_id":5,"server_id":972647,"status":"online"}},{"id":21,"name":"HTTP 
              Proxy (SSL)","identifier":"proxy_ssl","created_at":"2017-10-02 12:45:14","updated_at":"2017-10-02 12:45:14","metadata":[],"pivot":{"technology_id":21,"server_id":972647,
              "status":"online"}},{"id":23,"name":"HTTP CyberSec Proxy (SSL)","identifier":"proxy_ssl_cybersec","created_at":"2017-10-02 12:50:49","updated_at":"2017-10-02 12:50:49",
              "metadata":[],"pivot":{"technology_id":23,"server_id":972647,"status":"online"}},{"id":35,"name":"Wireguard","identifier":"wireguard_udp","created_at":"2019-02-14 14:08:43",
              "updated_at":"2019-02-14 14:08:43","metadata":[{"name":"public_key","value":"FgxaycYZ4t1kp4x7LDv60sczNTAl0h/d4pyyUNHhgBc="}],"pivot":{"technology_id":35,"server_id":972647,
              "status":"online"}}],"groups":[{"id":11,"created_at":"2017-06-13 13:43:00","updated_at":"2017-06-13 13:43:00","title":"Standard VPN servers","identifier":"legacy_standard",
              "type":{"id":3,"created_at":"2017-06-13 13:40:17","updated_at":"2017-06-13 13:40:23","title":"Legacy category","identifier":"legacy_group_category"}},{"id":15,
              "created_at":"2017-06-13 13:43:38","updated_at":"2017-06-13 13:43:38","title":"P2P","identifier":"legacy_p2p","type":{"id":3,"created_at":"2017-06-13 13:40:17",
              "updated_at":"2017-06-13 13:40:23","title":"Legacy category","identifier":"legacy_group_category"}},{"id":19,"created_at":"2017-10-27 14:17:17","updated_at":"2017-10-27 
              14:17:17","title":"Europe","identifier":"europe","type":{"id":5,"created_at":"2017-10-27 14:16:30","updated_at":"2017-10-27 14:16:30","title":"Regions",
              "identifier":"regions"}}],"specifications":[{"id":8,"title":"Version","identifier":"version","values":[{"id":257,"value":"2.1.0"}]}],"ips":[{"id":400164,
              "created_at":"2021-09-30 13:14:53","updated_at":"2021-09-30 13:14:53","server_id":972647,"ip_id":85398,"type":"entry","ip":{"id":85398,"ip":"217.138.197.51","version":4}}],
              "cpt":0}]

Update: with no change to the original script or the RouterOS version, today the script is working again (returning a value for the best server).

Got inspired by the initiative and the contribution here in this thread, so worked out a changed script which gives flexibility in looking for any specific NordVPN servers of any preference, with the options like offered on NordVPNs web site when searching manually for recommended server. Furthermore, I changed the output to the system log, useful if running the script automatically via scheduler.

credits on the one hand to john4669 for having had the idea, but most credit goes to msatter for the base script mine is derived from.

PS: apologizes for any errors in terms of scripting best practices and standards, I’m actually not a developer but I gave my best to get it into the right shape.


{
:local newname
:local VPNlimit "1"

# Declare the name of your ipsec peer as set in your router configuration
:local VPNPeerName "NordVPN"

# Values for country id (numeric code):
# 2-Albania, 10-Argentina, 13-Australia, 14-Austria, 21-Belgium, 27-Bosnia and Herzegovina, 30-Brazil, 33-Bulgaria, 38-Canada, 43-Chile, 47-Colombia,
# 52-Costa Rica, 54-Croatia, 56-Cyprus, 57-Czech Republic, 58-Denmark, 68-Estonia, 73-Finland, 74-France, 80-Georgia, 81-Germany, 84-Greece, 97-Hong Kong,
# 98-Hungary, 99-Iceland, 101-Indonesia, 104-Ireland, 105-Israel, 106-Italy, 108-Japan, 119-Latvia, 125-Lithuania, 126-Luxembourg, 131-Malaysia, 140-Mexico,
# 142-Moldova, 153-Netherlands, 156-New Zealand, 128-North Macedonia, 163-Norway, 174-Poland, 175-Portugal, 179-Romania, 192-Serbia, 195-Singapore,
# 196-Slovakia, 197-Slovenia, 200-South Africa, 114-South Korea, 202-Spain, 208-Sweden, 209-Switzerland, 211-Taiwan, 214-Thailand, 220-Turkey, 225-Ukraine,
# 226-United Arab Emirates, 227-United Kingdom, 228-United States, 234-Vietnam
:local VPNcountry "228"

# Values for server type [...]:
# Double VPN [legacy_double_vpn], Onion Over VPN [legacy_onion_over_vpn], Ultra fast TV [legacy_ultra_fast_tv], Anti DDoS [legacy_anti_ddos],
# Dedicated IP [legacy_dedicated_ip], Standard VPN servers [legacy_standard], Netflix USA [legacy_netflix_usa], P2P [legacy_p2p],
# Obfuscated Servers [legacy_obfuscated_servers], Europe [europe], The Americas [the_americas], Asia Pacific [asia_pacific], Africa, the Middle East and India],
# Anycast DNS [anycast-dns], Geo DNS [geo_dns], Grafana [grafana], Kapacitor [kapacitor], Socks5 Proxy [legacy_socks5_proxy], FastNetMon [fastnetmon]
:local VPNservtype "legacy_standard"

# Values for security protocol [...]:
# IKEv2/IPSec [ikev2], OpenVPN UDP [openvpn_udp], OpenVPN TCP [openvpn_tcp], Socks 5 [socks], HTTP Proxy [proxy], PPTP [pptp], L2TP/IPSec [l2tp],
# OpenVPN UDP Obfuscated [openvpn_xor_udp], OpenVPN TCP Obfuscated [openvpn_xor_tcp], HTTP CyberSec Proxy [proxy_cybersec], HTTP Proxy (SSL) [proxy_ssl],
# HTTP CyberSec Proxy (SSL) [proxy_ssl_cybersec)], IKEv2/IPSec IPv6 [ikev2_v6], OpenVPN UDP IPv6 [openvpn_udp_v6], OpenVPN TCP IPv6 [openvpn_tcp_v6],
# Wireguard [wireguard_udp], OpenVPN UDP TLS Crypt [openvpn_udp_tls_crypt], OpenVPN TCP TLS Crypt [openvpn_tcp_tls_crypt],
# OpenVPN UDP Dedicated [openvpn_dedicated_udp], OpenVPN TCP Dedicated [openvpn_dedicated_tcp], Skylark [skylark], Mesh Relay [mesh_relay]
:local VPNsecprot "ikev2"

:log info "Requesting recommended NordVPN server with preferences: country code $VPNcountry, server type $VPNservtype and security protocol $VPNsecprot"
:local data ([/tool fetch http-header-field="User-Agent: Mozilla/4.0" ("https://api.nordvpn.com/v1/servers/recommendations\?limit=" . $VPNlimit . "&filters[country_id]=" . $VPNcountry . "&filters[servers_groups][identifier]=" . $VPNservtype . "&filters[servers_technologies][identifier]=" . $VPNsecprot) output=user as-value ]->"data")
  :do {
   :local valname "hostname"
   :while ([:len $data]!=0) do={
         :set $fieldname ($valname."\":\"")
         :set $delimiter "\""
         if ($numval = "yes") do={:set $fieldname ($valname."\":"); :set $delimiter ","}
         :local position ([:find $data "$fieldname"]+[len $fieldname])
         :set newname [:pick $data $position (position + ([:find ( [:pick $data $position ([find $data "}}]}"])]) $delimiter ]))]
     :set $data [:pick $data ([:find $data "}}]}"]+5) [:len $data]]
   } 
  } 
:local oldname ([:pick [/ip ipsec peer print as-value where name~"$VPNPeerName"] 0]->"address")
#:put "old server = $oldname"
#:put "new server = $newname"
:if ([:len $newname] > 0) do={
		:if ($newname != $oldname) do={
			:log info "Updating address for ipsec peer $VPNPeerName to $newname (old: $oldname)"
			/ip ipsec peer set $VPNPeerName address=$newname
		} else={:log info "No update of peer addresss required"}
	} else={:log info "There was no server recommended by NordVPN"}
}

{

:local VPNPeerName “NordVPN”

:local VPNcountry “228”
:local VPNservtype “legacy_standard”
:local VPNsecprot “ikev2”

:local VPNlimit “1”
:local strstart “"hostname":"”
:local strend “"”
:local newname “”
:local oldname “”
:local dataurl “”
:local dataqry “”
:local data “”

:log info “Requesting recommended NordVPN server with: country id $VPNcountry, server group $VPNservtype and technology $VPNsecprot”
:set dataurl “https://api.nordvpn.com/v1/servers/recommendations
:set dataqry “limit=$VPNlimit&filters[country_id]=$VPNcountry&filters[servers_groups][identifier]=$VPNservtype&filters[servers_technologies][identifier]=$VPNsecprot”
:set data ([/tool fetch url=“$dataurl\3F$dataqry” output=user as-value ]->“data”)
:set data [:pick $data ([:find $data $strstart -1] + [:len $strstart]) [:len $data]]
:set data [:pick $data 0 [:find $data $strend -1]]
:set newname $data
:set oldname [/ip ipsec peer get $VPNPeerName address]

:if ([:typeof $newname] = “nil”) do={
:log info “There was no server recommended by NordVPN”
} else={
:if ($newname = $oldname) do={
:log info “No update of peer addresss required”
} else={
:log info “Updating address for ipsec peer $VPNPeerName from old $oldname to new $newname”
/ip ipsec peer set $VPNPeerName address=$newname
}
}

}

Wow, thank you very much, your version looks so lightweight :open_mouth: , and it's simply blasting our stuff above away while doing the same job. :blush:

What about rest api?
It’s very simple to find the first hostname with curl and jq from the API using:

curl -s  "https://api.nordvpn.com/v1/servers/recommendations?limit=3"| jq -r  ".[0] | .hostname"

Then using a simple rest api query you can verify if there is a change needed and if so change it with a single POST or PATCH query.

Where can I put it within RouterOS?
In a container?..

Why complicate things involving other peripherals and other more complex systems, when it can all be done from this script?

Hi guys, is it possible to make a variation of this script for Nordlynx (Wireguard)?