Skip to content

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)
  • sudo access 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

Open5GS System Architecture

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-gnb simulates the base station, nr-ue simulates 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.

Ubuntu Server 24.04.4 LTS Download

Figure 2. Ubuntu Server 24.04.4 LTS Download

Create a new virtual machine. You should see the New Virtual Machine Wizard.

Hyper-V New Virtual Machine Wizard

Figure 3. Hyper-V New Virtual Machine Wizard

Specify a name and location for the VM.

Specify Name and Location

Figure 4. Specify Name and Location

Specify the generation — choose Generation 1.

Specify Generation

Figure 5. Specify Generation

Assign memory — give it 4096 MB.

Assign Memory

Figure 6. Assign Memory

Connect a virtual hard disk — leave everything at its default.

Connect Virtual Hard Disk

Figure 7. Connect Virtual Hard Disk

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.

Installation Options

Figure 8. Installation Options

Review the summary, double-check your settings, and select Finish.

Summary

Figure 9. Summary

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

Check your Ubuntu version
cat /etc/lsb-release
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:

sudo systemctl start mongod
sudo systemctl status mongod

For a customized or more detailed installation, see MongoDB's official Ubuntu install guide.4

Step 2 — Install Open5GS

sudo add-apt-repository ppa:open5gs/latest
sudo apt update
sudo apt 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:

curl -fsSL https://open5gs.org/open5gs../assets/webui/install | sudo -E bash -

By default the WebUI listens on http://localhost:9999. To change the bind host/port permanently, edit the systemd service file:

sudo vim /lib/systemd/system/open5gs-webui.service
New to vim?
  1. Press i to enter insert mode.
  2. Use the arrow keys to move to the end of the Environment= line, past HOSTNAME=0.0.0.0 PORT=3000, and make your edits.
  3. Press Esc to leave insert mode.
  4. Type :wq and press Enter to 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:

  1. Open the WebUI (http://<CORE_VM_IP>:9999, or http://localhost:9999 if you're on the Core VM itself) and log in with the default credentials admin / 1423.
  2. Click + to add a new subscriber and enter:

    Field Value
    IMSI 999700000000001
    Key 465B5CE8B199B49FAA5F0A2EE238A6BC
    OPC value E8ED289DEBA952E4283B54E88E6183CA
    AMF 8000 (default)

    Table 1. 5GC Subscriber Configurations

  3. Add a session/slice profile with DNN internet (Open5GS's default APN).

  4. Save the subscriber.

Example 5GC Subscriber Configs

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:

/etc/open5gs/amf.yaml
...

ngap:
  server:
    - address: <CORE_VM_IP>

...

Edit /etc/open5gs/upf.yaml and change the GTP-U server address the same way:

/etc/open5gs/upf.yaml
...

gtpu:
  server:
    - address: <CORE_VM_IP>

...

Restart both:

sudo systemctl restart open5gs-amfd
sudo systemctl restart open5gs-upfd

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:

sudo sysctl -w net.ipv4.ip_forward=1
sudo sysctl -w net.ipv6.conf.all.forwarding=1

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)!
  1. make, gcc/g++, and cmake are only needed for building UERANSIM. libsctp-dev, lksctp-tools, and iproute2 are also required at runtime.
  2. Don't install cmake with sudo apt-get install cmake — it installs a very old version by default. Use sudo snap install cmake --classic, or build cmake from source.3
cd ~/UERANSIM
make # (1)!
  1. If it builds successfully, you'll find nr-gnb, nr-ue, and nr-cli inside ~/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

~/UERANSIM/config/open5gs-gnb.yaml
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:

~/UERANSIM/config/open5gs-ue.yaml
# 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:

cd ~/UERANSIM
./build/nr-gnb -c config/open5gs-gnb.yaml

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:

cd ~/UERANSIM
sudo ./build/nr-ue -c config/open5gs-ue.yaml

Watch for a line like:

[app] [info] PDU Session establishment is successful, TUN interface[uesimtun0, ...] is up.

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:

ping -I uesimtun0 8.8.8.8

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

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s 10.45.0.0/16 ! -o ogstun -j MASQUERADE

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:

sudo tcpdump -i <interface> -w capture.pcap
  • On the Core VM, capture on the interface facing the RAN VM to see NGAP and GTP-U.
  • On the RAN VM, uesimtun0 shows 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:

sudo journalctl -u open5gs-amfd -f

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:

./build/nr-gnb -c config/open5gs-gnb.yaml | tee gnb.log

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-amfd is actually running: sudo systemctl status open5gs-amfd
  • Confirm the PLMN in open5gs-gnb.yaml matches 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> in open5gs-gnb.yaml's amfConfigs is correct and reachable — try ping <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 supi in open5gs-ue.yaml exactly matches the IMSI registered in the WebUI
  • Confirm key/op/opType in the UE config match what was entered in the WebUI (K/OPc), and that opType is set to OPC if 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 gtpIp in open5gs-gnb.yaml is 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


  1. Lee, S. (n.d.). Quickstart. Open5GS. https://open5gs.org/open5gs/docs/guide/01-quickstart/ ↩↩

  2. Güngör, A. (n.d.). open5gs-ue.yaml [Source code]. UERANSIM, GitHub. https://github.com/aligungr/UERANSIM/blob/master/config/open5gs-ue.yaml ↩

  3. Güngör, A. (n.d.). Installation. UERANSIM Wiki, GitHub. https://github.com/aligungr/UERANSIM/wiki/Installation ↩↩

  4. 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/ ↩