Redundant WAN connection for your homeserver
TLDR: Using multiple Internet connections you can avoid being revealed though an Internet shutdown.
In this tutorial we're going to explain how to protect your homeserver against somebody who can shut down your internet connection and showcase how to implement failover to a backup connection to avoid being revealed.
Why use a redundant internet connection?
Context: You run a sensitive .onion service on your homeserver.
When the Attacker can shut down your connection, your .onion service will go down and since your server was at home β you have lost deniability.

However, they don't have to be active, they can notice when your service goes down, when you have an outage, passively. They can know when an ISP has an outage by looking at traffic levels from all ISPs in the world in various ways.

Now when you have multiple internet connections and your main connection is shut down, your homeserver can switch seamlessly over to your backup connection and your service remains online!

How can you solve this attack vector?
We can use a backup connection (a mobile phone with USB Tethering) and change the default route via a script (the default route indicates your active connection) when the main connection is down.
Acquiring a backup connection
You can get (not use) an anonymous eSIM in this tutorial. Before continuing, verify that mobile data works.
Enabling USB Tethering mode
First, connect a USB Data cable from your homeserver to your phone, then click these buttons on your phone.
NOTE: you have to be in your Owner profile when enabling USB Tethering.




Checking if USB Tethering works
Now login into your homeserver as root and run lsusb -t | grep cdc_ncm
[root@homeserver ~]# lsusb -t | grep cdc_ncm
|__ Port 004: Dev 005, If 0, Class=Communications, Driver=cdc_ncm, 480M
|__ Port 004: Dev 005, If 1, Class=CDC Data, Driver=cdc_ncm, 480M
Note: Should you get no output, your cable might be broken or have no physical data lines. Also, you can see the speed of the connection, USB 2.0 speed is enough.
Automatic connection switching
Now create the following files, note to configure your interfaces in the specified format:
File: /opt/failover.py
[root@homeserver ~]# cat <<EOF > /opt/failover.py
#!/usr/bin/env python3
import os
import re
import requests
import subprocess
import ipaddress
# Format: [[ifname, gateway v4, gateway v6], more interfaces with same format]
# Note: when running with ENABLE_V6 = False, still fill in dummy data for the v6 gateway, will get ignored
ENABLE_V6 = True # Set to False if no v6 support on ALL interfaces, will fully remove V6 connectivity if set to False!
INTERFACES = []
TARGETS = ['2620:fe::fe', '9.9.9.9', '2606:4700:4700::1111', '1.1.1.1', '2001:4860:4860::8888', '8.8.8.8'] # servers used for checking connectivity, these are public dns servers from big organisations
PING_COUNT = 1
PING_TIMEOUT = 1
def get_default_gateway():
try:
data = subprocess.Popen(['ip', 'route', 'show'], stdout=subprocess.PIPE).communicate()[0].decode('utf-8')
m = re.match(r'default via (\d*\.\d*\.\d*\.\d*) dev', data)
return m[1]
except:
return None
def set_default_gateway(ifname, ip4, ip6):
# remove default route(s)
subprocess.call(['ip', '-4', 'route', 'del', 'default'], stdout=open(os.devnull, 'w'))
if ENABLE_V6:
subprocess.call(['ip', '-6', 'route', 'del', 'default'], stdout=open(os.devnull, 'w'))
# add default route(s)
subprocess.call(['ip', '-4', 'route', 'add', 'default', 'via', ip4, 'dev', ifname], stdout=open(os.devnull, 'w'))
if ENABLE_V6:
subprocess.call(['ip', '-6', 'route', 'add', 'default', 'via', ip6, 'dev', ifname], stdout=open(os.devnull, 'w'))
# flush routing cache
subprocess.call(['ip', '-4', 'route', 'flush', 'cache'], stdout=open(os.devnull, 'w'))
if ENABLE_V6:
subprocess.call(['ip', '-6', 'route', 'flush', 'cache'], stdout=open(os.devnull, 'w'))
# kill all NATed connections, they're dead anyways
subprocess.call(['conntrack', '-F'], stdout=open(os.devnull, 'w'))
def add_route(ifname, ip, gateway):
subprocess.call(['ip', 'route', 'add', ip, 'via', gateway, 'dev', ifname], stdout=open(os.devnull, 'w'))
def remove_route(ifname, ip):
subprocess.call(['ip', 'route', 'del', ip, 'dev', ifname], stdout=open(os.devnull, 'w'))
def ping(ip):
return (subprocess.call(['ping', '-c%d' % (PING_COUNT), '-W%d' % (PING_TIMEOUT), ip], stdout=open(os.devnull, 'w')) == 0)
def test_gateway(ifname, g_4, g_6):
ok = False
for ip in TARGETS:
if ipaddress.ip_address(ip).version == 4:
add_route(ifname, ip, g_4)
elif ipaddress.ip_address(ip).version == 6:
add_route(ifname, ip, g_6)
ok = ping(ip)
remove_route(ifname, ip)
if ok: break
return ok
def main():
if not ENABLE_V6:
# disable V6
subprocess.call(['ip', '-6', 'route', 'del', 'default'], stdout=open(os.devnull, 'w'))
# Filter out V6 targets
TARGETS = [a for a in TARGETS if ipaddress.ip_address(a).version == 4]
current = get_default_gateway()
for i in range(len(INTERFACES)):
ifname = INTERFACES[i][0]
g_4 = INTERFACES[i][1]
g_6 = INTERFACES[i][2]
if test_gateway(ifname, g_4, g_6):
if g_4 != current:
print("changing gateway...")
set_default_gateway(ifname, g_4, g_6)
print(f'Changing gateway to {g_4} {g_6} on interface {ifname}')
break
return 0
if __name__ == "__main__":
os._exit(main())
EOF
Now to make it run periodically, set up the following service & timer using systemd:
File: /etc/systemd/system/failover.service
[root@homeserver ~]# cat <<EOF > /etc/systemd/system/failover.service
[Unit]
Description=failover
[Service]
Type=oneshot
ExecStart=/bin/python3 /opt/failover.py
EOF
File: /etc/systemd/system/failover.timer
[root@homeserver ~]# cat <<EOF > /etc/systemd/system/failover.time
[Unit]
Description=failover timer
[Timer]
OnUnitActiveSec=120s
OnBootSec=1s
[Install]
WantedBy=timers.target
EOF
Now, reload systemd and enable the script with the following command:
[root@homeserver ~]# systemctl daemon-reload && systemctl enable --now failover.timer
Testing WAN failover
Now, to test the failover, unplug either: 1. your LAN connection from your server 2. disconnect your router 3. power off any switches in between
And check that your host still has internet connectivity, if it hasn't worked, check your interface config or logs with:
[root@homeserver ~]# systemctl status failover.service
Conclusion
You have now achieved redundant WAN connectivity, now make sure to test this setup regularly so you know it's working when needed. Also check the phone regularly and make updates, but note that the interface and gateway setting will change, so you'll have to edit them after every reboot.
Suggest changes
plebis 2026-03-04
Donate XMR to the author:
42NXaBb36eVhjvcVu6wyW66DBE3WnhFZjFnqbPFZXjMvQ2vxbJ5NR3ZGBg9kjg4Kg2YLijBqcDkrbfsFZQZNE4VKUbjz6Yw