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

Hi, to unlock the GUI I developed a small Python script that can generate the SSH root password and enable the GUI debug mode.
https://github.com/iodn/freedomfi-sercomm-sce4255w
A much simpler method than modifying your router’s DNS settings.
Sick! Will def shout that out in the next post I make about these units.