4 min read
WAN failover & Ping Watchdog script on Ubiquiti Routers
What to do if your Ubiquiti router has 2 WAN interfaces and you want the backup interface to automatically switch when the main interface goes down? In this tutorial, I will show you how to automate WAN interface failover where one interface is connected directly to ISP and the other via OSPF using bash script.
Connecting via SSH
To get started, make sure that the SSH option in your router settings is enabled. To enable SSH, go to Settings, under Management Settings - toggle enable checkbox, assign port number, and click Save button.
SSH to your router via Putty or Terminal. In my case, I'm using MacOS Terminal:
ssh ubnt@192.168.1.100 -p 22
Replace 192.168.1.100
with your router's IP address, then enter your password at the prompt.
Then navigate to /config/scripts/
directory and create a file. Name this file as you like. In my case, I named it - 'failover.sh'
cd /config/scripts/ && touch failover.sh
NOTE: The script is stored in the config directory to prevent it from being lost during reboots and firmware upgrades.
Open file with vi editor:
vi failover.sh
Writing a script
#!/bin/bash
PING_COUNT=4
MAIN_IF=eth0
BACKUP_IF=eth1
WAN_IP=10.10.100.1
run=/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper
First, create variables with the following:
PING_COUNT=4
--- amount of ping packets to sendMAIN_IF=eth0
--- Main WAN interfaceBACKUP_IF=eth1
--- OSPF interfaceWAN_IP=10.10.100.1
--- WAN IP Addressrun=/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper
--- a cmd wrapper used for configuration (same as running configure from the EdgeOS command line)
Assign MAIN_IF
, BACKUP_IF
, and WAN_IP
variables with your values.
Now let's add a reusable function:
toggle_if_rt() {
$run begin
$run $1 interfaces ethernet $MAIN_IF disable
$run $1 protocols static route 0.0.0.0/0 next-hop $WAN_IP disable
$run commit
$run end
}
The toggle_if_rt()
function is used to disable/enable main WAN interface and its route + avoid code duplicates and improve code readability. Let's analyze this code:
$run
is a cmd wrapper variable declared previously$1
is the first passed argument to the function. Either set or delete.
Order:
- begin configuration
- disable/enable interface
- disable/enable static route
- commit - apply changes
- end configuration
Now it's time to write conditional statements:
if /sbin/ethtool $MAIN_IF | grep -q "Link detected: yes"; then
/bin/ping -c $PING_COUNT -I $MAIN_IF 8.8.8.8 > /dev/null 2>&1
if [ $? -ne 0 ]; then
toggle_if_rt set
sleep 5s
/bin/ping -c $PING_COUNT -I $BACKUP_IF 8.8.8.8 > /dev/null 2>&1
if [ $? -ne 0 ]; then
toggle_if_rt delete
logger -t "network_test" -- "ping via [$BACKUP_IF] failed. Switched back to WAN [$MAIN_IF]"
exit 1
else
logger -t "network_test" -- "WAN is down. Using OSPF interface [$BACKUP_IF]"
exit 0
fi
else
exit 0
fi
Let's break it down:
1. Check if Main WAN interface is up
- ping Google's DNS server
2. If ping doesn't succeed
- disable Main WAN interface
- wait 5 seconds for the OSPF to switch
- ping Google's DNS server via OSPF interface
- when succeeded - log "WAN is down. Using OSPF interface eth1"
3. If ping via OSPF doesn't succeed
- log "ping via eth1 failed. Switched back to WAN eth0"
Now you might think, if the main WAN interface is disabled, script won't check its availability. That's correct!
If the previous script execution stayed on the OSPF interface, we have to enable the main WAN to check if it's up:
else
toggle_if_rt delete
sleep 20s
/bin/ping -c $PING_COUNT -I $MAIN_IF 8.8.8.8 > /dev/null 2>&1
if [ $? -ne 0 ]; then
toggle_if_rt set
logger -t "network_test" -- "WAN interface [$MAIN_IF] is not up yet"
exit 1
else
exit 0
fi
fi
Full Code
Add the following contents to the script:
#!/bin/bash
PING_COUNT=4
MAIN_IF=eth0
BACKUP_IF=eth1
WAN_IP=10.10.100.1
run=/opt/vyatta/sbin/vyatta-cfg-cmd-wrapper
# Enable/Disable interface and static route
toggle_if_rt() {
$run begin
$run $1 interfaces ethernet $MAIN_IF disable
$run $1 protocols static route 0.0.0.0/0 next-hop $WAN_IP disable
$run commit
$run end
}
# checks if Main WAN interface is up
if /sbin/ethtool $MAIN_IF | grep -q "Link detected: yes"; then
# if up - do ping
/bin/ping -c $PING_COUNT -I $MAIN_IF 8.8.8.8 > /dev/null 2>&1
# if error - disable Main WAN interface, wait, and ping via OSPF
if [ $? -ne 0 ]; then
# disable Main WAN and route
toggle_if_rt set
# wait
sleep 5s
# do ping via OSPF
/bin/ping -c $PING_COUNT -I $BACKUP_IF 8.8.8.8 > /dev/null 2>&1
# if OSPF fails switch back to Main WAN
if [ $? -ne 0 ]; then
# enable Main WAN and route
toggle_if_rt delete
logger -t "network_test" -- "ping via [$BACKUP_IF] failed. Switched back to WAN [$MAIN_IF]"
exit 1
# else - stay on OSPF till Main WAN is available
else
logger -t "network_test" -- "WAN is down. Using OSPF interface [$BACKUP_IF]"
exit 0
fi
else
exit 0
fi
# If previous script execution stayed on OSPF interface, we have to enable WAN to check if it's up
else
toggle_if_rt delete
sleep 20s
/bin/ping -c $PING_COUNT -I $MAIN_IF 8.8.8.8 > /dev/null 2>&1
if [ $? -ne 0 ]; then
toggle_if_rt set
logger -t "network_test" -- "WAN interface [$MAIN_IF] is not up yet"
exit 1
else
exit 0
fi
fi
Don't forget to modify the permissions to allow the script to execute.
chmod +x /config/scripts/failover.sh
Scheduling script execution
To achieve script scheduling, we need to use task-scheduler. The task-scheduler feature is basically a "wrapper" for cron.
configure
set system task-scheduler task failover executable path /config/scripts/failover.sh
set system task-scheduler task failover interval 5m
commit ; save ; exit
That's it!
Now the script will execute every 5 minutes to check WAN interfaces and switch them automatically.
The script is tested on EdgeRouter Infinity v2.0.9-hotfix.5