Recently there was maintenance in our area by our broadband service provider which meant tethering to our phones to enable us to work from home. Me being me I thought, “I know how I can solve this for the future – build an LTE router with a Raspberry Pi”. What follows is the outcome of a painful two months of tinkering on and off.
1. The kit
First things first, you’ll obviously need a spare Raspberry Pi. If you don’t already have one, good luck with that. Thankfully I had the Pi 4 that I’d built as a Retropi machine that, well, we all know how that goes: build it, set it up, tinker, store it in a drawer.
For the LTE modem, I initially bought the Waveshare SIM7600 USB dongle, for reasons unknown. After getting severely hacked off with it seemingly recognising the dongle at random, either directly plugged in or using the extension lead, I decided to… double down and buy the hat version. This connected without fail.
2. Basic setup
To set the pie up, I took the opportunity to test out the network install feature that is now part of the Pi bootloader. To sort that out it was nessessary for me to put a basic Lite image on an SD card, update the bootloader and set the boot order to
Network Boot in the
Advanced Options menu of
With this set up, its the usual dance of updating and upgrading as soon as you log into your Pi for the first time:
:~ $ sudo apt update && sudo apt upgrade -y
Then a brief soujorn into
raspi-config to set up the serial interace:
1 Interface Options > I6 Serial Port > Login shell accessible over SSH: No > Serial port hardware enabled: Yes
Once done I moved on to setting up the folder and file for the public SSH key:
:~ $ mkdir ~/.ssh :~ $ touch ~/.ssh/authorized_keys :~ $ chmod 700 ~/.ssh :~ $ chmod 600 ~/.ssh/authorized_keys :~ $ ls -lna ~/.ssh drwx------ . -rw------- authorized_keys
After adding my public key to the
authorized_keys file, I edited the
/etc/ssh/sshd_config file – probably overkill in this instance, though good practice all the same:
Port $[ssh-port-number] AddressFamily inet […] LoginGraceTime 20 PermitRootLogin no […] MaxAuthTries 3 […] PubkeyAuthentication yes […] PasswordAuthentication no PermitEmptyPasswords no […] ChallengeResponseAuthentication no […] KerberosAuthentication no […] GSSAPIAuthentication no […] AllowAgentForwarding no […] X11Forwarding no […] PermitUserEnvironment no […] PermitTunnel no
Although some guides recommend it, setting
no will mean you can’t connect via Visual Studio Code.
Once configured, the service needed to be restarted:
:~ $ sudo systemctl restart sshd
Ordinarily at this point I would have installed then configured UFW and Fail2Ban however, as “most mobile carriers take care of firewalls”:https://www.reddit.com/r/AskNetsec/comments/ce0n03/firewall_needed_for_lte/, this was unnecessary.
The last step was disabling and uninstalling
ModemManager which will by default try to manage the LTE modem:
:~ $ sudo systemctl unmask ModemManager.service # may not need this :~ $ sudo systemctl disable ModemManager.service :~ $ sudo apt remove modemmanager -y
3. Setting up the LTE modem
Getting the LTE modem to be recognised by the Pi is relatively hard work and thankfully the lovely people of the Raspberry Pi forums have solved this. In combination with a great article by Jeff Geerling, I was able to get the LTE interface up and running fairly painlessly, on boot.
There were three checks to do to make sure the modem was being seen by the Pi. The first was to check that it appeared as a USB device:
:~ $ lsusb Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub Bus 001 Device 003: ID 1e0e:9001 Qualcomm / Option SimTech, Incorporated Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
The second was to check that it was appearing as a CDC device,
:~ $ ls /dev/cdc* /dev/cdc-wdm0
The last check is to make sure it was appearing as a network interface, at
:~ $ ip a […] 4: wwan0: […] […]
With the checks complete, I could move on to installing the necessary software:
:~ $ sudo apt install libqmi-utils udhcpc -y
Once done, I quickly checked to make sure the modem was online:
:~ $ sudo qmicli -d /dev/cdc-wdm0 --dms-set-operating-mode='online'
After this, it was necessary to set the modem’s protocol to
:~ $ sudo ip link set wwan0 down :~ $ echo 'Y' | sudo tee /sys/class/net/wwan0/qmi/raw_ip :~ $ sudo ip link set wwan0 up
If you need to confirm the setting, you can run the following:
:~ $ sudo qmicli -d /dev/cdc-wdm0 --wda-get-data-format […] Link layer protocol: 'raw-ip' […]
Most guides now recommend you run a commnand to set the APN, username and password. For some reason the GiffGaff sim I was using did not require this. What was required was actually starting the device:
:~ $ sudo qmi-network /dev/cdc-wdm0 start
This brought me to the first moment of truth – trying to connect the device to the GiffGaff network. Running the following gave the LTE modem it’s default IP and route:
:~ $ sudo udhcpc -q -f -i wwan0
If everything was successful, running
ip a again should display an IP address for
wwan0, probably in the private
The connection was then tested by pinging Google:
:~ $ ping -I wwan0 www.google.com -c 3 […] --- www.google.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 4006ms rtt min/avg/max/mdev = 31.199/46.540/58.827/8.962 ms
As all of the above modem config is necessary after a reboot, the easiest way to have it come online automatically was to set up a config file in
/etc/network/interfaces.d. From a lot (a lot) of reading, I gather that this is one of about 25 million ways of configuring networks on Linux, and not necessarily the most recent one. But whatever, it worked for me:
:~ $ sudo nano /etc/network/interfaces.d/wwan0 auto wwan0 iface wwan0 inet manual pre-up ifconfig wwan0 down pre-up echo Y > /sys/class/net/wwan0/qmi/raw_ip pre-up for _ in $(seq 1 10); do /usr/bin/test -c /dev/cdc-wdm0 && break; /bin/sleep 1; done pre-up for _ in $(seq 1 10); do /usr/bin/qmicli -d /dev/cdc-wdm0 --nas-get-signal-strength && break; /bin/sleep 1; done pre-up /usr/bin/qmi-network /dev/cdc-wdm0 start pre-up udhcpc -i wwan0 post-down /usr/bin/qmi-network /dev/cdc-wdm0 stop
On rebooting, the LTE modem worked successfully, getting an IP address, and allowing pings to Google. This worked flawlessly for the hat, but this was always the stage where the dongle would randomly crap out – I never did figure out why.
4. Sharing the LTE connection with the ethernet port
This is where it got complicated, for two reasons. Firstly most guides are old, for pre-Buster versions of RaspberryPi OS. Secondly, most guides assume you want to share the Wifi connection,
wlan, with the ethernet port,
eth0 as I was trying to do. Simply replacing
wwan didn’t seem to work when I tried.
The first thing to do is install
:~ $ sudo apt-get install dnsmasq
Having already configured the
wwan0 interface, I just needed to configure the
eth0 interfaces. The reason for configuring
wlan was because I later went rogue and turned off
dhcpcd as I was doing everything through
:~ $ sudo nano /etc/network/interfaces.d/wlan0 allow-hotplug wlan0 iface wlan0 inet static wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf metric 0 address $[ip-address] netmask $[subnet] network $[ip] router $[router-ip-address]
Then for the
:~ $ sudo nano /etc/network/interfaces.d/eth0 auto eth0 iface eth0 inet static metric 200 address 192.168.2.1 netmask 255.255.255.0 network 192.168.2.0 broadcast 192.168.2.255
It was also necessary to enable packet forwarding, by uncommenting
:~ $ sudo nano /etc/sysctl.conf […] net.ipv4.ip_forward=1 […]
Downloading the script and making it executable with
chmod +x was the last step – I placed the script in my home directory, updated the variables to use capitals, and the commands in it to use
ip instead of
NETMASK="24" […] sudo ip link set dev $ETH down sudo ip link set dev $ETH up sudo ip addr add $IP_ADDRESS/$NETMASK dev $
With all of that done, it was time to run the script and plug the laptop into the Pi ethernet port. Nervously I turned Wifi off, and… success – I was able to browse the web via the LTE connection on my Pi. Speeds were not great, but usable, though turning off iCloud Private Relay seemed to improve them. The big test will be plugging this into my network setup – we’ll see how that goes.