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 send
  • MAIN_IF=eth0 --- Main WAN interface
  • BACKUP_IF=eth1 --- OSPF interface
  • WAN_IP=10.10.100.1 --- WAN IP Address
  • run=/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:

  1. begin configuration
  2. disable/enable interface
  3. disable/enable static route
  4. commit - apply changes
  5. 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