Try 5G Yourself¶
Summary
- Open5GS is an open-source implementation of the 5G Core (5GC) — AMF, SMF, UPF, AUSF, UDM, and the rest of the Service-Based Architecture — plus a legacy 4G/5G NSA core.
- UERANSIM is an open-source gNB and UE simulator — it speaks the same NGAP/NAS/RRC protocol messages a real base station and phone would, but entirely in software, over ordinary IP sockets instead of radio.
- Together, they let you run a complete, working 5G SA network — registration, PDU session establishment, and actual internet connectivity through a simulated UE — across two VMs on your own machine, with no SDR hardware.
Why do this lab?
Real 5G RF hardware and licensed spectrum access are expensive and slow to set up. This lab reproduces the full signalling flow — RACH, RRC, registration, PDU session establishment — entirely in software, for free, in under an hour.
What You'll Need¶
- 2 VMs, each running Ubuntu — one for the Core (Open5GS), one for the RAN (UERANSIM)
- Each VM: at least 2 vCPUs, 4 GB RAM
- Network connectivity between the two VMs, and outbound internet access on both (to pull packages and source)
sudoaccess on both VMs- Roughly 45–60 minutes
Minimum Ubuntu version
UERANSIM itself only needs Ubuntu 16.04+, but MongoDB 8.0 (used by Open5GS) requires Ubuntu 20.04 or later — so that's the real floor for this lab, on the Core VM at minimum. Using the same version on both VMs is simplest.
Throughout this guide, <CORE_VM_IP> and <RAN_VM_IP> refer to each VM's actual IP address on the network you set up below — you'll fill these in once your VMs exist.
Architecture Overview¶
Figure 1. Open5GS (5GC) System Architecture1
Two VMs, two roles:
- Core VM — runs Open5GS: AMF, SMF, UPF, AUSF, UDM, and the rest of the 5GC.
- RAN VM — runs UERANSIM:
nr-gnbsimulates the base station,nr-uesimulates the device.
The two VMs talk to each other over NGAP (control plane, gNB↔AMF) and GTP-U (user plane, gNB↔UPF) — exactly the N2 and N3 reference points covered on the 5GC page, just running over a VM network instead of a real Uu/NG interface.
Virtual Machines Setup¶
I'm using Hyper-V here, but any hypervisor (VirtualBox, VMware) or two real Linux machines work the same way — the only hard requirement is that the two VMs can reach each other over the network.
Create Hyper-V Virtual Machine¶
Install Ubuntu Server 24.04.4 LTS from the official download page. You'll get an ubuntu-24.04.4-live-server-amd64.iso file.
Figure 2. Ubuntu Server 24.04.4 LTS Download
Create a new virtual machine. You should see the New Virtual Machine Wizard.
Figure 3. Hyper-V New Virtual Machine Wizard
Under installation options, choose Install an operating system from a bootable CD/DVD-ROM, then select Image file (.iso) and point it at the ISO you downloaded in Step 1.
Figure 8. Installation Options
Configure the Server¶
Start the server and follow the default Ubuntu Server installation flow. Everyone sets this up a little differently depending on their environment, but leaving everything at its default is fine for this lab. A reboot is required after setup completes.
Repeat this entire procedure for the second virtual machine.
Open5GS Setup¶
Run this on: Core VM
Step 1 — Install MongoDB¶
sudo apt-get install gnupg curl
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org
sudo apt-get install gnupg curl
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org
sudo apt-get install gnupg curl
curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \
sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \
--dearmor
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org
Start MongoDB and check its status:
For a customized or more detailed installation, see MongoDB's official Ubuntu install guide.4
Step 2 — Install Open5GS¶
Step 3 — Install the WebUI¶
The WebUI lets you interactively edit subscriber data — not essential (a CLI tool exists for advanced users), but much easier when starting out.
Install Node.js:
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg
NODE_MAJOR=20
echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | sudo tee /etc/apt/sources.list.d/nodesource.list
sudo apt update
sudo apt install nodejs -y
Install the WebUI itself:
By default the WebUI listens on http://localhost:9999. To change the bind host/port permanently, edit the systemd service file:
New to vim?
- Press
ito enter insert mode. - Use the arrow keys to move to the end of the
Environment=line, pastHOSTNAME=0.0.0.0 PORT=3000, and make your edits. - Press
Escto leave insert mode. - Type
:wqand pressEnterto save and quit.
# /lib/systemd/system/open5gs-webui.service
[Unit]
Description=Open5GS WebUI
Wants=mongodb.service mongod.service
[Service]
Type=simple
WorkingDirectory=/usr/lib/node_modules/open5gs
Environment=NODE_ENV=production HOSTNAME=0.0.0.0 PORT=3000
ExecStart=/usr/bin/node server/index.js
Restart=always
RestartSec=2
[Install]
WantedBy=multi-user.target
Then reload and restart:
sudo systemctl daemon-reload
sudo systemctl restart open5gs-webui.service
sudo systemctl status open5gs-webui.service
You should see Ready on http://0.0.0.0:3000 (or whatever host/port you configured) in the status output.
Once it's running, open the WebUI in your browser at http://<CORE_VM_IP>:3000.
Step 4 — Register a Test Subscriber¶
UERANSIM's bundled UE config (open5gs-ue.yaml) ships with a fixed test identity and key set,2 so the simplest path is to register a subscriber in the WebUI that matches it exactly:
- Open the WebUI (
http://<CORE_VM_IP>:9999, orhttp://localhost:9999if you're on the Core VM itself) and log in with the default credentialsadmin/1423. -
Click + to add a new subscriber and enter:
Field Value IMSI 999700000000001Key 465B5CE8B199B49FAA5F0A2EE238A6BCOPC value E8ED289DEBA952E4283B54E88E6183CAAMF 8000(default)Table 1. 5GC Subscriber Configurations
-
Add a session/slice profile with DNN
internet(Open5GS's default APN). - Save the subscriber.
Figure 10. Example 5GC Subscriber Configs
This is the subscriber that Step 7's config table and the Troubleshooting section below both refer to.
Step 5 — Expose the Core to the RAN VM¶
By default, Open5GS binds its AMF (NGAP) and UPF (GTP-U) to loopback addresses (127.0.0.5 and 127.0.0.4), which only work for a single-machine setup. For two VMs, both need to bind to the Core VM's real, reachable IP instead.
Edit /etc/open5gs/amf.yaml and change the NGAP server address:
Edit /etc/open5gs/upf.yaml and change the GTP-U server address the same way:
Restart both:
Step 6 — Add a Route for the UE to Reach the Internet¶
To bridge between the UPF and the WAN (internet), you must enable IP forwarding and add a NAT rule to your iptables.
Enable IPv4/IPv6 forwarding:
Add the NAT rule:
sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE
sudo ip6tables -t nat -A POSTROUTING -s 2001:db8:cafe::/48 ! -o ogstun -j MASQUERADE
Make sure the firewall isn't blocking traffic. Some OSes (Ubuntu included) enable firewall rules by default that will block this:
sudo ufw status
# Status: active
sudo ufw disable
# Firewall stopped and disabled on system startup
sudo ufw status
# Status: inactive
Optionally, for better security once things are working, consider:
# Accept packets in the INPUT chain arriving on the ogstun interface
sudo iptables -I INPUT -i ogstun -j ACCEPT
# Prevent UEs from connecting directly to the host running the UPF
sudo iptables -I INPUT -s 10.45.0.0/16 -j DROP
sudo ip6tables -I INPUT -s 2001:db8:cafe::/48 -j DROP
# If your core network spans multiple hosts, block UE-originated traffic
# from reaching other network functions. Replace x.x.x.x/y with the
# relevant NF's IP/subnet.
sudo iptables -I FORWARD -s 10.45.0.0/16 -d x.x.x.x/y -j DROP
UERANSIM Setup¶
Run this on: RAN VM
Requirements:
- Ubuntu 16.04+
- CMake 3.17+
- gcc 9.0.0+
- g++ 9.0.0+
WSL and NAT-based guest-to-host networking won't work here
Windows Subsystem for Linux (WSL) can't be used as a VM for this lab, and guest-to-host NAT configurations may not work on Windows for the same underlying reason. VirtualBox with a bridged adapter works fine on Windows, as does the Hyper-V External Switch setup above.
Step 1 — Build UERANSIM¶
cd ~
git clone https://github.com/aligungr/UERANSIM
cd UERANSIM
sudo apt install make gcc g++ libsctp-dev lksctp-tools iproute2 # (1)!
sudo snap install cmake --classic # (2)!
make,gcc/g++, andcmakeare only needed for building UERANSIM.libsctp-dev,lksctp-tools, andiproute2are also required at runtime.- Don't install cmake with
sudo apt-get install cmake— it installs a very old version by default. Usesudo snap install cmake --classic, or build cmake from source.3
- If it builds successfully, you'll find
nr-gnb,nr-ue, andnr-cliinside~/UERANSIM/build.3
Step 2 — Configure the gNB & UE¶
Unlike a single-machine setup, the default config files won't work as-is — they point at loopback addresses that don't mean anything across two VMs.
Edit ~/UERANSIM/config/open5gs-gnb.yaml:
| Setting | Change to | Why |
|---|---|---|
linkIp |
<RAN_VM_IP> |
The gNB's own address, as the AMF/UPF need to reach it |
ngapIp |
<RAN_VM_IP> |
Same — NGAP-specific binding |
gtpIp |
<RAN_VM_IP> |
Same — GTP-U-specific binding |
amfConfigs[0].address |
<CORE_VM_IP> |
Where the AMF actually is now (was 127.0.0.5) |
Table 2. gNB Configurations
mcc: '999' # Mobile Country Code value
mnc: '70' # Mobile Network Code value (2 or 3 digits)
nci: '0x000000010' # NR Cell Identity (36-bit)
idLength: 32 # NR gNB ID length in bits [22...32]
tac: 1 # Tracking Area Code
linkIp: <RAN_VM_IP> # gNB's local IP address for Radio Link Simulation (usually same as local IP)
ngapIp: <RAN_VM_IP> # gNB's local IP address for the N2 interface (usually same as local IP)
gtpIp: <RAN_VM_IP> # gNB's local IP address for the N3 interface (usually same as local IP)
# List of AMF address information
amfConfigs:
- address: <CORE_VM_IP>
port: 38412
# List of supported S-NSSAIs by this gNB
slices:
- sst: 1
# Indicates whether or not SCTP stream number errors should be ignored.
ignoreStreamIds: true
# Cell access type. When set to one of the satellite types (nr-leo, nr-meo,
# nr-geo, nr-othersat), the gNB attaches the NR-NTN TAI Information extension
# to every UserLocationInformationNR it sends to the AMF. Defaults to "nr".
cellAccessType: nr
In ~/UERANSIM/config/open5gs-ue.yaml, update the gNB search list to point at the RAN VM:
# List of gNB IP addresses for Radio Link Simulation
gnbSearchList:
- <RAN_VM_IP>
Nothing else in open5gs-ue.yaml needs to change — its supi (imsi-999700000000001) already matches the subscriber you registered, and it doesn't need to know either VM's IP directly beyond the gNB search list above.
Running & Testing¶
Run this on: RAN VM (both steps)
Step 1 — Run It¶
In one terminal, start the simulated gNB:
You should see the SCTP connection to the AMF come up successfully, followed by an NG Setup exchange — this is the gNB-to-core equivalent of the state described in RRC states.
In a second terminal, start the simulated UE:
Watch for a line like:
That uesimtun0 interface is your simulated UE's data path — exactly what a real UE's cellular data interface represents, just implemented as a Linux TUN device.
Step 2 — Test Connectivity¶
Ping through the tunnel to confirm the full path (UE → gNB → UPF) actually carries traffic:
This next part runs on: Core VM
To let that traffic actually reach the internet (not just the UPF), enable IP forwarding and add a NAT rule on the Core VM (if you haven't already done this in Step 5):1
If that ping succeeds, you have a complete, working 5G SA data path — Registration → PDU Session Establishment → user-plane traffic — running across two VMs, with no physical radio involved anywhere.
Debugging & Log Collection¶
Once things are running, here's how to actually see what's happening at each layer.
Wireshark¶
On either VM, capture the interface carrying the traffic you care about:
- On the Core VM, capture on the interface facing the RAN VM to see NGAP and GTP-U.
- On the RAN VM,
uesimtun0shows the UE's actual user-plane traffic post-decapsulation.
Open the resulting .pcap in Wireshark and filter on ngap, gtpv2, or nas-5gs to isolate the signalling you're interested in — this is a good way to see the RRC and NAS messages from earlier pages as real captured packets rather than diagrams.
Open5GS Debug Logs¶
Each Open5GS NF logs independently via systemd. To follow the AMF live, for example:
For more verbose output, set logger: level: debug in the relevant NF's config file (e.g., /etc/open5gs/amf.yaml) and restart that NF.
UERANSIM Logs¶
UERANSIM logs directly to the terminal it's running in — the nr-gnb/nr-ue output you already saw in Step 8. To keep a copy for later, redirect it:
Log verbosity
UERANSIM may expose additional logging configuration beyond what's shown here — check the UERANSIM Configuration Wiki for the current options rather than relying on this guide, since it isn't something I've independently verified.
Troubleshooting¶
SCTP connection to the AMF times out
- Confirm
open5gs-amfdis actually running:sudo systemctl status open5gs-amfd - Confirm the PLMN in
open5gs-gnb.yamlmatches the AMF's configured PLMN (/etc/open5gs/amf.yaml) — a mismatch here is the single most common cause of NG Setup failure - Confirm
<CORE_VM_IP>inopen5gs-gnb.yaml'samfConfigsis correct and reachable — tryping <CORE_VM_IP>from the RAN VM first - Confirm nothing else (like
ufw) is blocking the SCTP port on the Core VM
UE registration fails / subscriber not found
- Double-check the
supiinopen5gs-ue.yamlexactly matches the IMSI registered in the WebUI - Confirm
key/op/opTypein the UE config match what was entered in the WebUI (K/OPc), and thatopTypeis set toOPCif you entered an OPc value rather than an OP value
PDU session comes up, but there's no internet through uesimtun0
- Confirm IP forwarding is enabled and the NAT rule above was applied on the Core VM
- Confirm
ufw(or another firewall) isn't blocking forwarded traffic on the Core VM - Confirm
gtpIpinopen5gs-gnb.yamlis set to<RAN_VM_IP>and that UDP 2152 is open on the Core VM
Lab use only
This setup uses default credentials (admin/1423) and, once exposed beyond loopback, real network-reachable services. Don't expose the WebUI or any 5GC network function to an untrusted network without changing the defaults and adding proper access controls.
Useful Resources¶
- Open5GS Quickstart — official install and configuration guide
- Open5GS GitHub
- UERANSIM Installation Wiki
- UERANSIM Configuration Wiki
- MongoDB 8.0 on Ubuntu — official install guide
- 3GPP TS 23.501 — 5G System architecture, the specification both projects implement
- 3GPP TS 38.413 — NGAP, the protocol carrying gNB ↔ AMF signalling you'll see in the logs
-
Lee, S. (n.d.). Quickstart. Open5GS. https://open5gs.org/open5gs/docs/guide/01-quickstart/ ↩↩
-
Güngör, A. (n.d.). open5gs-ue.yaml [Source code]. UERANSIM, GitHub. https://github.com/aligungr/UERANSIM/blob/master/config/open5gs-ue.yaml ↩
-
Güngör, A. (n.d.). Installation. UERANSIM Wiki, GitHub. https://github.com/aligungr/UERANSIM/wiki/Installation ↩↩
-
MongoDB, Inc. (n.d.). Install MongoDB Community Edition on Ubuntu. MongoDB Documentation, v8.0. https://www.mongodb.com/docs/v8.0/tutorial/install-mongodb-on-ubuntu/ ↩









