Call 0330 520 4093

Lodestar’s story / Build your own network

Chapter 07 of 18

Build with VectorCore

Build the public VectorCore MME, HSS and serving gateway, with Open5GS as the packet gateway. Follow a separate LAN plan, source build, configuration and subscriber provisioning path.

Published 1 November 2026
About 20 minutes to read, plus build time

The early AzurePCS home PC and radio setup
The original AzurePCS setup, photographed by Blake. This historical Band 3 setup inspired the guide.
In this chapter
  1. Choose what VectorCore will do
  2. Use three clearly named Linux environments
  3. Connect the VMs and radio to the same wired network
  4. Install build tools that match the source
  5. Download a recorded version
  6. Build the programs without starting services
  7. Prepare the HSS database and protect management
  8. Configure the MME to find your HSS and gateways
  9. Configure the serving gateway
  10. Connect the Open5GS packet gateway
  11. Stage installation before enabling anything
  12. Create the APN, authentication record and subscriber
  13. Apply the firewall rules for this three host route
  14. Start in order and check each connection
  15. Prove data access before enabling voice

VectorCore branch: use the addresses, firewall peer rules and HSS provisioning in this chapter. The single-PC Open5GS firewall and WebUI chapters explain a different branch.

Choose what VectorCore will do

Source-verified reference build: this exact fresh three-VM installation has not been run end to end. Complete the peer, attachment, data and isolation tests on your equipment before relying on it.

VectorCore is another way to build the LTE core behind your Baicells radio. Its public projects provide a Mobility Management Entity, called the MME, a Home Subscriber Server, called the HSS, and a Serving Gateway split into control and user plane programs. The MME manages the phone's connection. The HSS stores the subscriber information needed to authenticate the SIM. The gateway moves traffic between the radio side and the packet gateway.

The build in this chapter combines those VectorCore components with the Open5GS SMF and UPF as the LTE packet gateway. The HSS also supplies the PCRF policy role. The public VectorCore organisation did not provide a separate packet gateway repository when checked on 1 November 2026, so cloning only its MME, HSS and SGW is not a complete internet access network.

Choose this route if you want to learn how these components fit together and use the VectorCore management interfaces. The Open5GS route is available as a complete alternative. The hybrid route described here is an integration recipe based on the checked public source. Its final checkpoint is a successful attach and data test on your own equipment. Read the VectorCore organisation and Open5GS's explanation of SMF and UPF providing the 4G packet gateway roles.

Use three clearly named Linux environments

You can host the environments as virtual machines on one Ubuntu PC. Give each a fixed address on a private core network and make sure they can reach one another before installing software. These example addresses belong to this chapter's example only. Replace them consistently if your network uses another subnet.

NameExample addressPrograms
vc-control10.77.0.10VectorCore HSS, PostgreSQL and MME
vc-sgw10.77.0.20VectorCore SGW-C and SGW-U
vc-pgw10.77.0.30Open5GS SMF and UPF

The radio uses 10.77.0.10 as its MME address. Its user traffic must also reach 10.77.0.20. The gateway environments must reach each other. This layout keeps MME and packet gateway control sockets on different hosts, avoiding an accidental conflict where two programs try to bind UDP port 2123 on the same address.

Keep this traffic on your protected core network. Carry any remote radio link through the secure backhaul described elsewhere in the guide. A private address alone does not encrypt traffic or authenticate a peer. Allow only the intended peers through the firewall, and keep management APIs on loopback addresses. Leave the radio's RF function disabled while completing the software build.

Connect the VMs and radio to the same wired network

Use a wired Ethernet connection for the radio network. A practical host has one connection for normal internet and management access and a separate Ethernet port connected to a small core network switch. Connect the Baicells Ethernet or PoE injector's LAN side to that switch. Use only the power supply or PoE type specified for your exact radio.

Install your hypervisor using Ubuntu's libvirt instructions. Create a bridge on the dedicated core Ethernet interface, following Ubuntu's bridge configuration reference. Give it a recognisable name such as br-core. Do not move your existing management connection into an example bridge without checking its configuration. The host can use 10.77.0.5/24 on this dedicated bridge, with no default gateway on that interface.

  1. In each VM's network settings, add a bridged adapter connected to br-core. In virt-manager, choose a bridge device as the source and enter the actual bridge name.
  2. Give the VM's core adapter its table address with a /24 prefix, equivalent to subnet mask 255.255.255.0. Exclude these addresses from any DHCP pool. Set no default gateway on the dedicated core adapter.
  3. If needed, give each VM a second adapter on the hypervisor's ordinary NAT network for software downloads and management. That adapter supplies the default route. The radio must reach the bridged core addresses directly, rather than depending on this outbound NAT.
  4. Set the radio's S1 network address to a unique address such as 10.77.0.40/24. Set its MME address to 10.77.0.10. If radio management and S1 addresses are separate settings, make sure the address used for S1 and GTP-U is reachable on the core network. Use a default gateway only if you have actually configured a router for it.
  5. From each VM, run ip -brief address and confirm its assigned core address. From vc-sgw, run ip route get 10.77.0.40 and record the interface name. That core interface, rather than the NAT adapter, is the SGW-U ifname to configure later.

For this layout, the radio, vc-control, vc-sgw and vc-pgw must all reach one another over the same core subnet. Check address uniqueness and switch connections before debugging telecom protocols. The libvirt bridge documentation explains that a bridged VM appears on the physical LAN. Apply the peer firewall rules below before starting services. Keep subscriber traffic isolation on vc-pgw, where packets leave the phone's tunnel; a bridge alone provides no such isolation.

Install build tools that match the source

Use Ubuntu 24.04 on an x86_64 PC for this example. Check the architecture with uname -m. The checked SGW generator includes an x86_64 Linux header path, so another architecture needs its own verification. On each environment that will compile VectorCore, install the common tools:

sudo apt update
sudo apt install git ca-certificates curl build-essential pkg-config clang llvm libbpf-dev linux-libc-dev libsctp-dev lksctp-tools libsqlite3-dev jq
sudo modprobe sctp
uname -r

The actual module files matter more than an older README requirement. The checked MME requires Go 1.26.1, the HSS requires Go 1.25.0 and the SGW requires Go 1.26.2. Install a supported Go toolchain at least as new as 1.26.2 using the official Go instructions and verify the archive checksum shown on Go's downloads page. The standard Ubuntu package should not be assumed to meet this requirement. Go 1.27.3 was the featured release when this chapter was checked.

Install a supported Node.js LTS release with npm from the official Node.js distribution on the environments building the HSS and MME web interfaces. Then check go version, node --version and npm --version. Keep their output in your build notes. The pinned MME module, HSS module and SGW module provide the exact requirements.

Download a recorded version

Create a source directory on the machine doing the builds. Git downloads the project. A detached checkout selects one recorded revision, identified by its full commit hash. These are the revisions inspected for this chapter:

mkdir -p vectorcore-src
cd vectorcore-src
git clone https://github.com/vectorcore-mobile/vectorcore-hss.git
git -C vectorcore-hss checkout --detach c8a4c0f2bf8b42176e4a89ccd979b4dd270ce037
git clone https://github.com/vectorcore-mobile/vectorcore-mme.git
git -C vectorcore-mme checkout --detach 04d436ed1589b0f0882e6a061a025a752d87376f
git clone https://github.com/vectorcore-mobile/vectorcore-sgw.git
git -C vectorcore-sgw checkout --detach ac7dc41724696a2d59b94b31c89769f9854c2873

Do not use a changing branch as the only record of what you installed. Save each result from git rev-parse HEAD, the build tool versions and the Open5GS version alongside your final configuration. When upgrading, review the new requirements and configuration changes, test them in a separate environment and keep a way to restore the previous working set. A version pin records a known source state; it does not remove the need for security updates.

Build the programs without starting services

Run each block inside the named repository. A successful build creates binaries in its bin directory. The commands below follow the checked Makefiles. They compile programs and run their tests; they do not configure a working subscriber or enable the radio.

cd vectorcore-hss
make build
go test ./...
cd ../vectorcore-mme
make
make test
cp config/mme.yaml.example config/mme.yaml
cd ../vectorcore-sgw
make
make verify

The HSS output is bin/hss. The MME output is bin/mme. The SGW produces bin/sgw-c, bin/sgw-u and bin/sgwctl. The SGW build generates an eBPF program, which is code the Linux kernel runs to forward gateway packets. A build that passes without privileges may skip some kernel runtime tests. It therefore does not prove that XDP can attach to your chosen network interface.

Follow the output if a build fails. A complaint about the Go version means the toolchain is too old. A complaint about clang, BPF headers or architecture includes concerns the gateway build environment. Do not fix these by downloading an unexplained installer. The official MME, HSS and SGW Makefiles show exactly what these targets do.

Do not run the advertised installation targets yet. The checked MME and HSS targets enable and start services immediately. The checked SGW installation target also refers to a documentation file absent from that public checkout. The staged installation below avoids both problems.

Prepare the HSS database and protect management

On vc-control, install PostgreSQL and create a dedicated database account. Enter a new strong password when prompted. Do not reuse a sample password from a repository.

sudo apt install postgresql
sudo systemctl enable --now postgresql
sudo -u postgres createuser --pwprompt vectorcore_hss
sudo -u postgres createdb -O vectorcore_hss vectorcore_hss

Copy config/hss.yaml to a private working file called hss.local.yaml. Edit existing sections rather than adding a second copy of the same YAML key. Set database.db_type to postgresql, server to 127.0.0.1, port to 5432, and both username and database to vectorcore_hss. Enter your chosen password in the password field.

Set hss.MCC to the quoted string "999" and hss.MNC to "99" for this private example. Use hss.epc.mnc099.mcc999.3gppnetwork.org as OriginHost and epc.mnc099.mcc999.3gppnetwork.org as OriginRealm. Set BindAddress to 10.77.0.10 and leave BindPort at 3868. TCP Diameter is sufficient for these peers, so set EnableSCTP to false unless you deliberately choose SCTP throughout.

Set geored.enabled and gsup.enabled to false. Keep both 5GC UDM and PCF functions disabled for this LTE build. Set api.bind_address to 127.0.0.1, api.auth_enabled to true and configure a new random API key. Do not reuse the public sample's replication token. Keep api.bind_port at 8080. The sample configuration contains more services than this initial build needs.

Configure the MME to find your HSS and gateways

Edit the copied config/mme.yaml. Use the same quoted MCC and MNC in nf and every active nf.tai_list entry. Set Tracking Area Code, abbreviated TAC, to 1 for this example and configure the same TAC in the Baicells. Leave the example's MME group and code at 1 while running one MME.

SettingExample value
s1ap.bind_address10.77.0.10
s1ap.bind_port36412
s11.bind_address10.77.0.10
s11.bind_port2123
diameter.origin_hostmme.epc.mnc099.mcc999.3gppnetwork.org
diameter.origin_realmepc.mnc099.mcc999.3gppnetwork.org
diameter.peers first entryname hss-1, address 10.77.0.10:3868, transport tcp
gateway_selection.sgw.sgw_address10.77.0.20:2123
gateway_selection.pgw.pgw_address10.77.0.30:2123

For this first network, set gateway_selection.dns.enabled to false so gateway choice uses the explicit addresses. Set gateway_selection.pgw.prefer_s6a_static to false unless you also deliberately provision a packet gateway address in the HSS APN profile. Keep roaming and the optional SMS, location, inter-MME and public warning interfaces disabled while proving basic data access.

Bind the MME API to 127.0.0.1 on port 8085. Set operator.nitz.timezone to Europe/London. For normal authenticated service, use integrity algorithms EIA2 and EIA1 and ciphering algorithms EEA2 and EEA1, leaving the null algorithms out of this example's preference lists. Keep ims_voice_over_ps false until the IMS service is ready. The supported fields are documented in the MME configuration reference and example YAML.

Configure the serving gateway

On vc-sgw, copy configs/sgw-c.yaml and configs/sgw-u.yaml to sgw-c.local.yaml and sgw-u.local.yaml. Keep the current section structure. The parser rejects older layouts, including the old top-level s11 block.

In SGW-C, set sgwc.plmn.mcc to "999", MNC to "99", and sgwc.control_plane_ip to 10.77.0.20. Give the named control interface a listen address of 10.77.0.20:2123. Both gtpc.s11.bind and gtpc.s5c.bind must reference that interface's name. The name is a YAML label, not necessarily a Linux network card name.

Because SGW-C and SGW-U share this environment, use 127.0.0.1:8805 for the SGW-C PFCP endpoint and 127.0.0.2:8805 for the SGW-U endpoint. Match the SGW-C peer's node_id to sgwu.node_id. Put 127.0.0.1 in SGW-U's pfcp.allowed_sgwc list.

Find the actual Linux interface with ip -brief address. In SGW-U, set the user interface's ifname to that name and its listen to 10.77.0.20:2152. Reference the named interface from both gtpu.s1u.bind and gtpu.s5u.bind. Use xdp-generic initially, keep cleanup_on_exit enabled, and bind API and metrics listeners to 127.0.0.1. The user plane needs a concrete IPv4 address, not 0.0.0.0. Validate both edited files:

./bin/sgwctl validate -sgwc sgw-c.local.yaml -sgwu sgw-u.local.yaml

Do not continue until validation succeeds. The SGW configuration reference explains the current schema, Linux interface handling and privileges needed by the eBPF dataplane.

Connect the Open5GS packet gateway

On vc-pgw, complete the Open5GS software installation described in the Open5GS chapter, then configure only its SMF and UPF for this route. Subscriber and policy data come from VectorCore HSS. Avoid running a second HSS, PCRF, MME or serving gateway for the same network. Record the Open5GS package version and retain its matching configuration templates.

On a new dedicated vc-pgw with the packaged Open5GS installation, stop and disable the components supplied by VectorCore. Run this only on vc-pgw, not on an existing network serving users:

sudo systemctl disable --now open5gs-mmed open5gs-hssd open5gs-sgwcd open5gs-sgwud open5gs-pcrfd

Keep open5gs-smfd and open5gs-upfd for the packet gateway. Preserve open5gs-nrfd and open5gs-scpd if the installed SMF template points to them. This command deliberately leaves those dependencies alone. Check the actual service list with systemctl list-unit-files 'open5gs-*'. For a source installation without packaged service units, stop the equivalent replaced processes through the supervisor you installed. Do not run duplicate functions because a package installation happened to start them.

In /etc/open5gs/smf.yaml, change the SMF GTP-C server address to 10.77.0.30, which is the packet gateway address entered in the MME. Keep SMF and UPF PFCP endpoints distinct on their shared host, for example the installed defaults 127.0.0.4 and 127.0.0.7. The SMF's UPF peer must point at the UPF's PFCP endpoint.

In /etc/open5gs/upf.yaml, change its GTP-U server address to 10.77.0.30 so vc-sgw can reach it. Use the same phone address pool and gateway in both SMF and UPF. For an internet APN example, use 10.45.0.0/16 with gateway 10.45.0.1, then apply the guide's forwarding, TUN interface, DNS and restricted internet egress instructions on vc-pgw. Avoid overlap with your LAN, VPN or any other phone address pool. Keep one IPv4 APN initially.

In /etc/freeDiameter/smf.conf, replace the default PCRF peer with your VectorCore HSS identity and address. Edit the existing identity, realm, ListenOn and ConnectPeer statements; preserve the installed dictionary extension paths:

Identity = "smf.epc.mnc099.mcc999.3gppnetwork.org";
Realm = "epc.mnc099.mcc999.3gppnetwork.org";
ListenOn = "10.77.0.30";
ConnectPeer = "hss.epc.mnc099.mcc999.3gppnetwork.org" {
    ConnectTo = "10.77.0.10";
    Port = 3868;
    No_SCTP;
    No_TLS;
};

This explicit TCP example relies on the protected core transport. Do not expose unencrypted Diameter to the internet. Configure local name resolution for those identities, and make sure the HSS OriginHost exactly matches ConnectPeer. The official Open5GS SMF template, UPF template and Diameter template show the supported fields. Package templates are already expanded, so do not copy literal build placeholders such as @sysconfdir@ into an installed configuration.

Stage installation before enabling anything

On vc-control, from each appropriate repository, install the built binary and your edited configuration. Create the persistent database and log directories before starting the MME. The following commands deliberately do not start a service:

sudo install -d /opt/vectorcore/bin /opt/vectorcore/etc /opt/vectorcore/log /opt/vectorcore/var
# From vectorcore-hss:
sudo install -m 755 bin/hss /opt/vectorcore/bin/hss
sudo install -m 600 hss.local.yaml /opt/vectorcore/etc/hss.yaml
sudo install -m 644 systemd/vectorcore-hss.service /etc/systemd/system/vectorcore-hss.service
# From vectorcore-mme:
sudo install -m 755 bin/mme /opt/vectorcore/bin/mme
sudo install -m 600 config/mme.yaml /opt/vectorcore/etc/mme.yaml
sudo install -m 644 systemd/vectorcore-mme.service /etc/systemd/system/vectorcore-mme.service
sudo systemctl daemon-reload

On vc-sgw, from its repository, install the gateway files and the supplied service units:

sudo install -d /opt/vectorcore/bin /opt/vectorcore/etc /opt/vectorcore/log /var/lib/vectorcore-sgw /var/log/vectorcore/sgw
sudo install -m 755 bin/sgw-c bin/sgw-u bin/sgwctl /opt/vectorcore/bin/
sudo install -m 600 sgw-c.local.yaml /opt/vectorcore/etc/sgw-c.yaml
sudo install -m 600 sgw-u.local.yaml /opt/vectorcore/etc/sgw-u.yaml
sudo install -m 644 deploy/systemd/vectorcore-sgw-c.service /etc/systemd/system/vectorcore-sgw-c.service
sudo install -m 644 deploy/systemd/vectorcore-sgw-u.service /etc/systemd/system/vectorcore-sgw-u.service
sudo systemctl daemon-reload

The supplied SGW-U unit grants privileges needed for eBPF attachment and sets the memory lock limit. Review the upstream unit rather than guessing capabilities. Preserve API loopback bindings and restrict configuration files because the HSS file contains credentials. Use the log paths recorded in your edited files.

Create the APN, authentication record and subscriber

Start the HSS on vc-control with sudo systemctl start vectorcore-hss. Confirm it connects to PostgreSQL before provisioning. Reach management through an SSH tunnel from your own computer, using your actual administrative SSH user:

ssh -N -L 18080:127.0.0.1:8080 YOUR_ADMIN_USER@10.77.0.10

Leave the tunnel terminal open and use the local address http://127.0.0.1:18080. The current API documentation is at /api/v1/docs and the schema at /api/v1/openapi.json. Supply the configured key in the X-API-Key header when using the API. Avoid putting that key in a URL, screenshot or shared command history.

  1. Create an APN named internet at POST /api/v1/apn. Use IPv4, represented by ip_version 0 in the current API. Record the returned apn_id.
  2. Create an authentication record at POST /api/v1/subscriber/auc. Enter the IMSI, Ki, OPc and AMF supplied for your own SIM. Record the returned auc_id. Ki and OPc are secret key material. Do not use the public README's test keys for your own network.
  3. Create the EPC subscriber at POST /api/v1/subscriber. Use the same IMSI, the returned auc_id, the APN ID as default_apn and that ID in apn_list. Add only the services you intend to provide.
  4. Set the phone's APN to internet and make sure the SIM identity uses the chosen private PLMN. Recheck every digit before testing.

The short README examples use older paths, so follow the current API reference and current authentication routes. APN, authentication and subscriber are three linked records. Creating only one does not complete provisioning. This initial data build does not require an IMS subscriber. Add IMS provisioning when you follow the voice chapter.

Apply the firewall rules for this three host route

The single computer Open5GS firewall example elsewhere in this guide cannot be copied unchanged into this three host route. Traffic that used loopback now crosses the bridge. Write peer rules for these actual source and destination addresses, on both the guest firewalls and any intervening firewall. Preserve your administrative SSH path before applying restrictions.

Receiving hostAllowed sourceTransport and portPurpose
vc-control 10.77.0.10Radio 10.77.0.40SCTP 36412S1 signalling to MME
vc-control 10.77.0.10vc-sgw 10.77.0.20UDP 2123Serving gateway control and notifications
vc-control 10.77.0.10vc-pgw 10.77.0.30 and the local MMETCP 3868Diameter policy and authentication
vc-sgw 10.77.0.20vc-control 10.77.0.10 and vc-pgw 10.77.0.30UDP 2123Gateway control signalling
vc-sgw 10.77.0.20Radio 10.77.0.40 and vc-pgw 10.77.0.30UDP 2152GTP-U phone traffic
vc-pgw 10.77.0.30vc-sgw 10.77.0.20UDP 2123 and 2152Packet gateway control and phone traffic
Each hostYour approved management address onlyTCP 22Administrative SSH

Allow the corresponding replies through your stateful firewall. Do not allow an entire subnet just because one peer is permitted. Keep SGW-C and SGW-U PFCP on local 127.0.0.1 and 127.0.0.2 using UDP 8805. Keep SMF and UPF PFCP on local 127.0.0.4 and 127.0.0.7 using UDP 8805. Those pairs need no external PFCP opening in this placement.

On vc-control, management ports 8080 and 8085 stay on loopback. On vc-sgw, APIs 8080 and 8081 and metrics 9090 and 9091 stay on loopback. Keep vc-pgw's management and metrics local too. The checked sgwctl defaults are http://127.0.0.1:8080 for SGW-C and http://127.0.0.1:8081 for SGW-U, so its health and PFCP commands work locally with the earlier configuration.

Apply the guide's subscriber egress policy at vc-pgw's ogstun and outbound path. Preserve the intended restriction against phone access to the management network and private LANs. Core signalling ACLs protect network components; they do not replace the policy on the phone's decoded traffic. Test those restrictions as well as permitted internet traffic.

Start in order and check each connection

Start PostgreSQL and the HSS first. Start Open5GS UPF and SMF on vc-pgw after their configuration and TUN interface are ready. On vc-sgw, start SGW-U before SGW-C. Then start the MME on vc-control:

# On vc-pgw, for a package installation:
sudo systemctl start open5gs-upfd open5gs-smfd
# On vc-sgw:
sudo systemctl start vectorcore-sgw-u
sudo systemctl start vectorcore-sgw-c
/opt/vectorcore/bin/sgwctl health
/opt/vectorcore/bin/sgwctl pfcp
# On vc-control:
sudo systemctl start vectorcore-mme
sudo systemctl status vectorcore-hss vectorcore-mme --no-pager

On vc-control, the MME should establish its Diameter connection to the HSS. On vc-pgw, the SMF should connect to the same HSS for Gx policy and associate with its UPF over PFCP. On vc-sgw, SGW-C and SGW-U should associate over PFCP. Check journalctl -u SERVICE_NAME -n 100 --no-pager and each program's configured log file. A systemd status of running proves only that the process remains alive.

Useful peer rules for this example are the Baicells to vc-control on SCTP 36412, Baicells to vc-sgw on UDP 2152, vc-control to vc-sgw on UDP 2123, and vc-sgw to vc-pgw on UDP 2123 and 2152. Diameter on TCP 3868 reaches vc-control only from the intended MME and SMF peers. The two local PFCP pairs can remain on their respective hosts' loopback addresses. Do not open management ports to make a signalling connection work.

The sgwctl implementation provides health, PFCP, peer, session, bearer and BPF inspections. A skipped BPF runtime test or a failed XDP attach is a gateway problem to resolve before attempting radio service.

Prove data access before enabling voice

With your spectrum licence in force and the radio configured within its conditions, enable RF and register one authorised test phone. Confirm the base station connects to the MME, the SIM authenticates, a default bearer is created and the phone receives an address from the intended pool. Then test a permitted public HTTPS destination and check internet routing and DNS separately. Confirm that private management and LAN destinations remain blocked by the intended subscriber isolation policy. These checks locate the failure instead of treating every symptom as a radio problem.

If attach works but data does not, inspect the SGW sessions and BPF counters, the UPF session, forwarding and return routes. If authentication fails, recheck the actual SIM's IMSI, Ki, OPc, AMF and sequence synchronisation. Do not repeatedly replace secret keys with values copied from another guide. If the eNB cannot connect, check its PLMN, TAC, MME address, SCTP reachability and the MME's served tracking area.

After the baseline succeeds, enable the verified services at boot on each appropriate host and perform a controlled restart test. Keep the same source revisions and back up PostgreSQL, configuration files and any persistent MME state. Restore a backup into an isolated environment before relying on it. Add the IMS APN, IMS subscriber records, voice policy and device carrier configuration as a separate step. A working LTE data session is the foundation for that work, and does not by itself establish VoLTE or emergency calling.