Setting up your own 4G LTE Network (<$150) for your Embedded System & IoT Hacking Lab via Open5GS + CBRS eNodeB on Ubuntu 24.04

This is a long time coming and oh my god what a headache. But finally it’s over and I can share the steps it takes to set up your own private 4G / LTE network in your lab!

Best part is I was able to use a FreedomFi LTE CBRS [Link] – $100
Google Spectrum Access System (SAS) [Link] – $2.64 per month (Indoor)
Gialer 4g LTE Writable SIM Cards [Link] $37
ACS ACR39U N1 Pocketmate II USB-C SIM Writer/Reader [Link] $13
GMKtec M6 Ryzen 5 6600H Mini PC [Link] $300

Total: $452.64 (If you don’t have a box to run open5gs lying around) $152.64 if you do

So originally I attempted using Magma Core [Link] which honestly probably worked b/c of an issue I figured out weeks and weeks later, I ended up using Open5Gs [Link] which was most smoother anyway.

If you have an old laptop or whatever laying around you can probably get away with using that, especially if you don’t plan on having a large amount of user equipment (UE) aka cell devices connected to it. I just had that GMKTec from needing two NICs to run all the Magma pieces smoothly (and another mini PC but that’s a whole other story) so I ended up using it for this.

I’m not going to cover what each piece is or what most of the acronyms stand for, there are plenty of great video, articles, etc on that topic.

With that said, lets go from beginning to end and yes I’ll point out the issue that likely made me waste weeks on this projectโ€ฆ


1. Prepare Ubuntu Environment

sudo apt update && sudo apt upgrade -y
sudo apt install git wget curl net-tools iproute2 iptables ufw vim -y

1.1 Use Classic Network Interface Names (eth0)

sudo nano /etc/default/grub

Find:

GRUB_CMDLINE_LINUX=""

Change to:

GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0"
sudo update-grub
sudo reboot

After reboot, verify:

ip a

Your interface should now appear as eth0.

Make sure you disable wlan0 as well as you donโ€™t want anything to route through it instead of eth0.


2. Disable Netplan and Enable Classic Networking

Ubuntu 24.04 uses Netplan by default. Weโ€™ll disable it and enable the classic ifupdown system.

sudo systemctl mask systemd-networkd
sudo systemctl disable netplan.io
sudo systemctl unmask networking
sudo systemctl enable networking
sudo apt remove nplan netplan.io libnetplan0 -y
sudo apt remove nplan netplan.io libnetplan0 cloud-init -y
sudo apt purge nplan netplan.io libnetplan0 cloud-init -y
sudo apt install python3-dev apt-transport-https dnsutils -y
sudo apt install ifupdown net-tools ipcalc iptables-persistent -y

When prompted during iptables-persistent installation, select โ€œYesโ€ to automatically save IPv4 rules.


3. Interface Configuration

Now that classic networking is enabled, create the interface files manually.

I gave the open5gs core box a static IP via my openwrt appliance that runs my lab of 192.168.30.205 but you can set it statically on the box as well. It doesn’t hurt to give the enb a static IP at the same time as well, which in my case was 192.168.30.215.

sudo mkdir -p /etc/network/interfaces.d
sudo bash -c 'cat > /etc/network/interfaces <<EOF
source-directory /etc/network/interfaces.d
EOF'
sudo bash -c 'cat > /etc/network/interfaces.d/eth0 <<EOF
auto eth0
iface eth0 inet dhcp
  post-up ip route replace default via 192.168.30.1 dev eth0 metric 100
EOF'
sudo ifdown --exclude=lo -a || true
sudo ifup --exclude=lo -a

3.1 Create ogstun Interface

This virtual interface handles UE traffic (10.45.0.0/16).

sudo ip tuntap add name ogstun mode tun
sudo ip addr add 10.45.0.1/16 dev ogstun
sudo ip link set ogstun up

To make it persistent:

sudo bash -c 'cat > /etc/network/interfaces.d/ogstun <<EOF
auto ogstun
iface ogstun inet static
  address 10.45.0.1
  netmask 255.255.0.0
  pre-up ip tuntap add name ogstun mode tun
  post-down ip tuntap del name ogstun mode tun
EOF'
sudo ifup ogstun

4. Confirm DNS Is Functional

ping -c 1 google.com
nslookup github.com

If DNS fails, fix /etc/resolv.conf:

echo "nameserver 192.168.30.1" | sudo tee /etc/resolv.conf

5. TR-069 eNB Web Manager Activation

git clone https://github.com/xddxdd/freedomfi-cbrs-enable-webui.git
cd freedomfi-cbrs-enable-webui
sudo python3 tr069.py

Make sure you allow DNS rebinding and ‘poison’ or ensure that any DNS lookups to the ‘acs.freedomfi.com’ subdomain go to the box you’re running the tr069.py script on. So in my case, in my OpenWRT lab router, I allowed rebinding to a local IP for that subdomain and pointed it to 192.168.30.205

Also make sure you connect to the eNBs WAN port.

Once the eNodeB at 192.168.30.215 connects, youโ€™ll see CWMP Inform messages confirming ACS registration.


6. eNodeB Configuration via Web UI

In my case, the enb wasn’t reachable by my main box, so I used SSH to tunnel through to it: ssh -L 9443:192.168.30.215:443 nigel@192.168.30.205

username: sc_femto

password: tsFid2wz

Something else to keep in mind, you can also ssh to the box using the same credentials although you’ll be a limited user, there was some value when I was trouble shooting.

Make sure under TR098 –> MgntServer you uncheck ‘EnableCWMP’ after as well.

Login to http://192.168.30.215

LTE Parameters:

SAS Settings

Note that the Serial Number should obviously be the serial number on the back on the ENB and the UserID is in the box in yellow when you access the Google SAS interface:

Once it is given a ‘grant’ by Google SAS you’ll see in the Google SAS Portal:

Don’t forget the most annoying issue which is! That the PLMNID table has an option for ‘operator use’ and on stock SerComm firmware you keep that unchecked, but since FreedomFi runs slightly modified firmware, the CBRS will not change its PLMNID unless you check the operator use option. SO MAKE SURE YOU DO THAT BEFORE YOU SPENT WEEKS troubleshooting everything else.

Save and reboot the eNB.

6. Install Open5GS

sudo add-apt-repository ppa:open5gs/latest -y
sudo apt update
sudo apt install open5gs -y

7. Configure Open5GS Core

Configuration files live in /etc/open5gs/. Internal signaling uses 127.0.x.x, and the external S1 interface uses 192.168.30.205.

7.1 MME โ€“ /etc/open5gs/mme.yaml

logger:
  file:
    path: /var/log/open5gs/mme.log
mme:
  freeDiameter: /etc/freeDiameter/mme.conf
  s1ap:
    server:
      - address: 192.168.30.205
  gtpc:
    server:
      - address: 127.0.0.2
    client:
      sgwc:
        - address: 127.0.0.3
  gummei:
    - plmn_id:
        mcc: 315
        mnc: '010'
      mme_gid: 2
      mme_code: 1
  tai:
    - plmn_id:
        mcc: 315
        mnc: '010'
      tac: 1
  security:
    integrity_order: [ EIA2, EIA1, EIA0 ]
    ciphering_order: [ EEA0, EEA1, EEA2 ]

7.2 SGW โ€“ /etc/open5gs/sgwc.yaml

sgwc:
  gtpc:
    server:
      - address: 127.0.0.3
    client:
      smf:
        - address: 127.0.0.4
      sgwu:
        - address: 127.0.0.5

7.3 SGW-U โ€“ /etc/open5gs/sgwu.yaml

sgwu:
  gtpu:
    server:
      - address: 192.168.30.205
  gtpc:
    server:
      - address: 127.0.0.5

7.4 SMF โ€“ /etc/open5gs/smf.yaml

smf:
  pfcp:
    server:
      - address: 127.0.0.4
    client:
      upf:
        - address: 127.0.0.7
  gtpc:
    server:
      - address: 127.0.0.4
    client:
      sgwc:
        - address: 127.0.0.3
  gtpu:
    server:
      - address: 192.168.30.205
  pdn:
    - apn: internet
      type: ipv4
      dev: ogstun

7.5 UPF โ€“ /etc/open5gs/upf.yaml

upf:
  pfcp:
    server:
      - address: 127.0.0.7
  gtpu:
    server:
      - address: 192.168.30.205
  subnet:
    - addr: 10.45.0.1/16

Another great resource when troubleshooting is the ‘/rma_suport.htm’ page on the ENB. Here’s an exacmple when everything is working expected:


8. Enable NAT for UE Internet Access

Enable forwarding and NAT for the UE subnet (10.45.0.0/16):

sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE
sudo sysctl -w net.ipv4.ip_forward=1
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf

Once UE connectivity is verified, save the NAT rules permanently:

sudo netfilter-persistent save

9. WebUI & Subscriber Setup

sudo apt install mongodb -y
sudo systemctl enable mongodb --now
sudo systemctl restart open5gs-mmed open5gs-smfd open5gs-upfd
wget https://github.com/open5gs/open5gs-webui/archive/refs/heads/main.zip
unzip main.zip
cd open5gs-webui-main
npm install
npm run start

Access WebUI at http://192.168.30.205:3000

Default login: admin / 1423

Add a subscriber:

IMSI: 3150109999XXXXX
Ki: 465B5CE8B199B49FBA5F0A2EE238A6BC
OPc: E8EC289DEBA952E4283B54E88E6183CA
APN: internet

Use something like GRSIMWrite to write to the SIM card, making sure you include the IMSI, KI and OPc you put above. Link

10. Verify EPC Connectivity

sudo journalctl -u open5gs-upfd -u open5gs-smfd -n 50 --no-pager | egrep -i "PFCP|assoc|establish|heartbeat"

You should see:

[pfcp] INFO: Association established
[pfcp] INFO: Heartbeat response received

11. UE Attachment Test

sudo tail -f /var/log/open5gs/mme.log

Expected output:

MME-UE-S1AP-ID
Attach Request / Accept
E-RAB Setup
Bearer established

Your UE should receive an IP in 10.45.0.x range.


12. Test Connectivity

# From EPC
ping 10.45.0.2
# From UE
ping 8.8.8.8

If both succeed, your UE is connected through Open5GS via the Sercomm eNodeB.


Done!

You now have a complete EPC + eNodeB setup running on Ubuntu 24.04 with Open5GS, TR-069 management, SAS authorization, and a working UE data path.

Once everything works, donโ€™t forget to persist your NAT rules:

sudo netfilter-persistent save

For anything I might’ve missed the values you can copy paste and to see how I found out this was possible (and very generally followed his guides as they didn’t completely work for me), check out Lan Tian’s Two Posts: Link 1 Link 2

Here’s me successfully connected to GainSec Mobile Network:

And successfully browsing to GainSec on the LTE network:

Up next is to enable Wireshark/tcpdump on it, and set up a way to deploy eSIMs. But I need a break from this project for now. LOL.

END TRANSMISSION

2 thoughts on “Setting up your own 4G LTE Network (<$150) for your Embedded System & IoT Hacking Lab via Open5GS + CBRS eNodeB on Ubuntu 24.04

Leave a Reply