Dual-WAN Router – Load Balancing & Failover Automation 🚀


This script configures your Debian router so that all clients use the router's IP 192.168.123.100 (assigned to the LAN interface, e.g. eth2) as their gateway. It deploys two WAN connections (via eth0 and eth1) with gateways 192.168.123.1 and 192.168.123.2 respectively. The setup supports both load balancing and automatic failover. 🌐

The router forwards all LAN traffic to the internet via NAT. If one WAN connection fails, the script automatically adjusts the routing table to use the available gateway—ensuring uninterrupted connectivity for all clients. 💻


How It Works

The script begins by enabling IP forwarding and then configures dedicated routing tables for each WAN interface. It sets up a combined default route that balances outbound traffic over both gateways. Should one gateway become unreachable, the script seamlessly falls back to the functioning connection. 🔄

Additionally, iptables rules are implemented to handle NAT (MASQUERADE) and proper packet forwarding between the LAN and WANs. A background process periodically checks the status of each gateway every 30 seconds and updates the default route accordingly, ensuring robust load balancing and failover. 🛡️


Dual-WAN Router Bash Script

Copy the code below and save it as /usr/local/sbin/dualwan_router.sh on your Debian router. Then, make it executable and run it as root to enable the dual-WAN functionality.


#!/bin/bash
# dualwan_router.sh – Dual-WAN Routing and NAT Configuration for Debian Router
#
# Description:
#   - LAN IP: 192.168.123.100 on interface eth2; all LAN clients use this router as their gateway.
#   - WAN Interfaces: eth0 with gateway 192.168.123.1 and eth1 with gateway 192.168.123.2.
#   - Features: Separate routing tables for each WAN, a combined default route for load balancing,
#               and automatic failover based on gateway reachability.
#
# Ensure IP forwarding is enabled and iptables rules are applied for NAT and traffic forwarding.

###############################
# Configuration
###############################
LOGFILE="/var/log/dualwan_router.log"
PIDFILE="/var/run/dualwan_router.pid"
CHECK_INTERVAL=30   # Check gateway reachability every 30 seconds

# WAN configuration
WAN_IF1="eth0"
WAN_IF2="eth1"
GW1="192.168.123.1"
GW2="192.168.123.2"

# LAN configuration
LAN_IF="eth2"
LAN_IP="192.168.123.100"
LAN_NET="192.168.123.0/24"

# Routing tables (IDs must not conflict with other rules)
TABLE1=1
TABLE2=2

###############################
# Functions
###############################
log() {
    echo "$(date '+%F %T') - $1" >> "$LOGFILE"
}

enable_ip_forwarding() {
    echo 1 > /proc/sys/net/ipv4/ip_forward
    log "IP forwarding enabled."
}

get_interface_ip() {
    local iface=$1
    ip -4 addr show "$iface" | grep -oP '(?<=inet\s)\d+(\.\d+){3}'
}

setup_routing_tables() {
    log "Configuring routing tables for WAN interfaces..."
    ip route flush table $TABLE1 2>/dev/null
    ip route flush table $TABLE2 2>/dev/null
    ip route add default via $GW1 dev $WAN_IF1 table $TABLE1
    ip route add default via $GW2 dev $WAN_IF2 table $TABLE2

    WAN_IP1=$(get_interface_ip $WAN_IF1)
    WAN_IP2=$(get_interface_ip $WAN_IF2)
    
    if [ -n "$WAN_IP1" ]; then
        ip rule add from $WAN_IP1 table $TABLE1 2>/dev/null
        log "Routing rule set for $WAN_IF1 ($WAN_IP1) in table $TABLE1."
    else
        log "Warning: No IPv4 address found on $WAN_IF1."
    fi

    if [ -n "$WAN_IP2" ]; then
        ip rule add from $WAN_IP2 table $TABLE2 2>/dev/null
        log "Routing rule set for $WAN_IF2 ($WAN_IP2) in table $TABLE2."
    else
        log "Warning: No IPv4 address found on $WAN_IF2."
    fi

    ip route replace default scope global \
      nexthop via $GW1 dev $WAN_IF1 weight 1 \
      nexthop via $GW2 dev $WAN_IF2 weight 1
    log "Combined default route (load balancing) configured."
}

setup_nat() {
    log "Setting up NAT and forwarding rules..."
    iptables -t nat -F
    iptables -t nat -A POSTROUTING -s $LAN_NET -o $WAN_IF1 -j MASQUERADE
    iptables -t nat -A POSTROUTING -s $LAN_NET -o $WAN_IF2 -j MASQUERADE
    iptables -F FORWARD
    iptables -A FORWARD -i $LAN_IF -o $WAN_IF1 -j ACCEPT
    iptables -A FORWARD -i $LAN_IF -o $WAN_IF2 -j ACCEPT
    iptables -A FORWARD -i $WAN_IF1 -o $LAN_IF -m state --state ESTABLISHED,RELATED -j ACCEPT
    iptables -A FORWARD -i $WAN_IF2 -o $LAN_IF -m state --state ESTABLISHED,RELATED -j ACCEPT
    log "NAT and forwarding rules applied."
}

check_gateways() {
    log "Checking gateway reachability..."
    if ping -c 3 -W 2 $GW1 > /dev/null 2>&1; then
        GW1_UP=true
        log "Gateway $GW1 is reachable."
    else
        GW1_UP=false
        log "Gateway $GW1 is NOT reachable."
    fi

    if ping -c 3 -W 2 $GW2 > /dev/null 2>&1; then
        GW2_UP=true
        log "Gateway $GW2 is reachable."
    else
        GW2_UP=false
        log "Gateway $GW2 is NOT reachable."
    fi
}

update_default_route() {
    check_gateways
    if $GW1_UP && $GW2_UP ; then
        ip route replace default scope global \
            nexthop via $GW1 dev $WAN_IF1 weight 1 \
            nexthop via $GW2 dev $WAN_IF2 weight 1
        log "Both gateways are up – load balancing route set."
    elif $GW1_UP ; then
        ip route replace default via $GW1 dev $WAN_IF1
        log "Only gateway $GW1 is up – failover to $GW1."
    elif $GW2_UP ; then
        ip route replace default via $GW2 dev $WAN_IF2
        log "Only gateway $GW2 is up – failover to $GW2."
    else
        log "Warning: No WAN gateways reachable!"
    fi
}

start_check_loop() {
    log "Starting gateway check loop (Interval: $CHECK_INTERVAL seconds)..."
    while true; do
        update_default_route
        sleep $CHECK_INTERVAL
    done
}

stop_dualwan() {
    if [ -f "$PIDFILE" ]; then
        PID=$(cat "$PIDFILE")
        kill $PID && rm -f "$PIDFILE"
        log "DualWAN service stopped (PID $PID)."
    else
        log "No active DualWAN service found."
    fi
}

start_dualwan() {
    if [ "$EUID" -ne 0 ]; then
        echo "Please run as root."
        exit 1
    fi

    log "Starting DualWAN configuration..."
    enable_ip_forwarding
    setup_routing_tables
    setup_nat
    update_default_route

    start_check_loop &
    echo $! > "$PIDFILE"
    log "DualWAN service started (PID $(cat "$PIDFILE"))."
}

usage() {
    echo "Usage: $0 {start|stop|restart|status}"
}

status_dualwan() {
    if [ -f "$PIDFILE" ]; then
        PID=$(cat "$PIDFILE")
        if ps -p $PID > /dev/null; then
            echo "DualWAN service running (PID $PID)."
        else
            echo "Stale PIDFILE – no active service."
        fi
    else
        echo "DualWAN service is not active."
    fi
}

case "$1" in
    start)
        start_dualwan
        ;;
    stop)
        stop_dualwan
        ;;
    restart)
        stop_dualwan
        sleep 2
        start_dualwan
        ;;
    status)
        status_dualwan
        ;;
    *)
        usage
        exit 1
        ;;
esac
      

Installation & Usage Instructions

Step 1: Save the script above as /usr/local/sbin/dualwan_router.sh on your Debian router. 📁

Step 2: Make the script executable by running: chmod +x /usr/local/sbin/dualwan_router.sh 🔧

Step 3: Execute the script as root (or with sudo) to start the Dual-WAN service: sudo /usr/local/sbin/dualwan_router.sh start 🚀

Step 4: To stop, restart, or check the status of the service, use:

  • sudo /usr/local/sbin/dualwan_router.sh stop
  • sudo /usr/local/sbin/dualwan_router.sh restart
  • sudo /usr/local/sbin/dualwan_router.sh status

Ensure that all your LAN clients are configured to use 192.168.123.100 as their default gateway. 💡


With this setup, your Debian router dynamically balances your outbound traffic over both WAN connections and automatically fails over in the event that one gateway becomes unreachable. This robust configuration ensures a reliable internet connection for all connected devices. 👍

This detailed guide—complete with thorough explanations and a ready-to-use script—provides you with everything you need to implement and customize dual-WAN routing on your Debian router. 🚀