Angry robot logo

Mumbling about computers

Homelab backup LTE connection

Posted on under [ ]

For quite a while I wanted to set up a backup connection into my homelab — at least once the router has dropped its DHCP lease when I was away and I had no way of fixing it.

Ideally, I'm never going to access the lab via this network, so I didn't want to have a monthly subscription for data I was probably not going to use.

I found a bunch of vendors that'd sell you a SIM which is valid for 1 year, but most of them required a VAT number, so they'd only sell to business.

Finally I found droam which sells to individuals and bought a 2GB prepaid SIM for €20.

To go with it, I bought a USB 4G modem, the ZTE MF79U.

Upon plugging in the modem, an ethernet interface showed up.

Basic setup

To set up the modem, I initially configured the interface in DHCP mode, as I didn't know in which subnet the modem itself was configured

Placing the following config into /etc/network/interfaces

auto enx344b50000000
iface enx344b50000000 inet dhcp

After running ifup enx344b50000000, the interface came up on; I brought it down by running ifdown enx344b50000000 and re-configured it in static mode:

auto enx344b50000000
iface enx344b50000000 inet static

I prefer a static config, as fewer things can go wrong, but also, my dhclient config would overwrite my DNS configuration otherwise, making all DNS queries go over the LTE interface.

With the interface up, I assumed I'd be able to configure the modem with a browser, so I set up an SSH tunnel to my router to access it

ssh -D 1337 -q -N router

I use FoxyProxy to configure rules, so that only the LTE subnet is proxied via the router.

With the proxy set up, I was greeted by this lovely message:

The auto-update feature is enabled by default, which seems crazy to me. Pressing REJECT just logs you out.

I clicked a bunch on the settings, disabling the auto-update feature, DHCP server and Wifi access point.

Testing the interface

$ ping -I enx344b50000000
PING ( from enx344b50000000: 56(84) bytes of data.
--- ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 28ms

Looking at the kernel logs (dmesg) I see that all the packets are getting dropped

IPv4: martian source from 78.46.233.xx, on dev enx344b50000000

A packet is considered martian if it arrives on an unexpected interface; looking at the routing table

$ ip route
default via dev wan dev enx344b50000000 proto kernel scope link src 

the kernel expects a packet with src= to come from wan:

$ ip route get via dev wan src uid 0 

To allow for reply packets coming on non-optimal interfaces, I set the reverse-path filtering policy to "loose" with a sysctl setting:

$ sysctl -w net.ipv4.conf.enx344b50000000.rp_filter=2

and now it can successfully ping the internet.

Configuring Wireguard

As the LTE interface is behind a NAT which I don't control, it can only be an initiator in a Wireguard connection.

The goal is to only route packets from the VPN through the interface, we can do this by:

# Create a routing table which defaults to the LTE interface
ip route add default via dev enx344b50000000 table 123

# Create a rule to move any IP packet tagged as coming from Wireguard into the "LTE" routing table
ip rule add fwmark 0x7b table 123

Now Wireguard needs to mark all packets, which can be achieved with

FwMark = 0x7b

Now, testing from my VPS I can connect over the LTE link (the non-LTE connection has ~25ms of latency).

$ ping
PING ( 56(84) bytes of data.
64 bytes from icmp_seq=1 ttl=64 time=122 ms
64 bytes from icmp_seq=2 ttl=64 time=192 ms
64 bytes from icmp_seq=3 ttl=64 time=128 ms
64 bytes from icmp_seq=4 ttl=64 time=127 ms


I left the interface up and came back to check the next day, to my surprise, I could not ping the LTE modem anymore over the Wireguard connection.

I assume that as these 4g connections are NAT'd, the conntrack rule expired and my packets started getting dropped.

Luckily, Wireguard has a feature to work around this very thing, sending keep-alive messages on an interval.

I experimented with the highest value that wouldn't drop my connection and settled with


Which boils down to something like 1KB/hour =~ 10MB/year.