Building a Reticulum Mesh Network — Part 3

Date

Date

April 5, 2026

April 5, 2026

Author

Author

Lisa Zhao

Lisa Zhao

NomadNet, The Dead Testnet, and Hosting a Site Over LoRa

April 5, 2026

This is Part 3 of the Reticulum mesh network build. Part 1 covered getting the Pi and LilyGo RNode running. Part 2 covered Heltec nodes, MeshCore bridging, and I2P connectivity. If you haven't read those, start there.

Today's session started with a fresh SD card — the previous one had suffered repeated package corruption from a series of libllvm19 crashes that eventually took out libc-bin. Rather than trying to recover it, reflashing was the cleaner path. If your Pi starts throwing libc errors, don't fight it. Just reflash and start from a known good state.

With the Pi back online and services re-established, the goals for today were:

  • Set up NomadNet and host a page node visible on the global Reticulum network

  • Figure out why global connectivity was so unreliable

  • Sort out remote access to MeshChat

The first two turned out to be related in an unexpected way.

The Reticulum Testnet Is Gone

Part 2 ended with I2P as the confirmed working path to the global Reticulum network, because Shaw blocks non-standard TCP ports. That conclusion turned out to be only half right.

While troubleshooting the I2P connections today — both testnet peers kept showing Tunnel Unresponsive — I found this notice on the Reticulum GitHub:

The public testnet, including the Amsterdam Testnet entrypoint, has now been decommissioned. If your instances relied on this entrypoint for connectivity, transition to using the distributed backbone instead.

The testnet is dead. Not flaky — gone. Every I2P address we'd been trying to connect to (g3br23bvx..., ci3kku...) was a former testnet node that no longer exists. We weren't failing because of Shaw. We were failing because the destinations didn't exist.

This also meant the TCP failures from Part 2 needed re-examining. We assumed Shaw was blocking those connections, but we'd only tested against testnet nodes. Test against something that's actually running:

nc -zv rmap.world 4242
Connection to rmap.world (217.154.9.220) 4242 port [tcp/*]

TCP works fine. Shaw isn't blocking it. The previous failures were entirely because the testnet was dead.

Lesson: If your Reticulum TCP connections fail, check whether the destination node actually exists before assuming your ISP is the problem. The community node list has changed significantly since the testnet was decommissioned.

Connecting to the Actual Network

The Reticulum project now points to a distributed backbone run by volunteers. The community node list lives at the Reticulum GitHub wiki and changes regularly.

I tested a handful and settled on three reliable ones:

[[rmap.world]]
  type = TCPClientInterface
  interface_enabled = yes
  target_host = rmap.world
  target_port = 4242

[[dismail.de]]
  type = TCPClientInterface
  interface_enabled = yes
  target_host = rns.dismail.de
  target_port = 7822

[[reticulum.n7ekb.net]

The N7EKB node in particular has been running for months with 47+ clients connected — it's a well-maintained community node with an LXMF propagation node alongside it.

I also enabled interface discovery, which lets Reticulum automatically find and connect to new peers as the network grows:

[reticulum]

I kept the I2P interfaces as backup since I already had i2pd running, swapping the dead testnet addresses for active community ones:

[[0rbit-Net-I2P]]
  type = I2PInterface
  enabled = yes
  peers = 3amqekrikkrvfoyor75tjnlxmswmxiprqx7wknrwsnb46x7kjwuq.b32.i2p

[[Rhein Ruhr I2P]

After restarting rnsd, rnstatus showed TCP connections coming up within seconds. The MeshChat network visualiser started filling with global nodes — SRRTH, cometdust @akihabara, RNS Faultline.dev, Styrene Community Hub, and others.

NomadNet: Hosting Pages on the Mesh

NomadNet is a terminal application built on Reticulum and LXMF. It has two main functions: encrypted messaging (like a Reticulum-native messaging client), and a page server — essentially a mini dark-web-style site that other Reticulum nodes can browse, over LoRa or I2P or anything else Reticulum supports.

Install it the same way as everything else:

pip install nomadnet --break-system-packages

Run it once to generate the config:

Then quit. The config lives at ~/.nomadnetwork/config. Find these two settings and update them:


Run NomadNet in daemon mode so it serves pages in the background without a terminal UI:

nomadnet --daemon

Check the log to confirm it started and get your node's identity hash — you'll need this to browse your own node:

head -20

Look for the line that says Created new Primary Identity <hash> or Loaded Primary Identity <hash>. That hash is your node's address on the Reticulum network.

To keep NomadNet running automatically, add a crontab entry:

crontab -e

Add:

This checks every minute and restarts NomadNet if it's not running.

Writing NomadNet Pages in Micron

Pages are stored in ~/.nomadnetwork/storage/pages/. The root page is index.mu. The markup language is called Micron — a minimal format designed to work over extremely low-bandwidth links.

Key formatting codes (all prefixed with a backtick):

Code

Effect

`c

Center align

`l

Left align

`!

Toggle bold

`*

Toggle italic

`_

Toggle underline

`Frrr

Set foreground colour (3-digit hex)

`Brrr

Set background colour (3-digit hex)

`f

Reset foreground to default

`b

Reset background to default

``

Reset all formatting

>

Heading

---

Horizontal divider

Links use this syntax:

For internal pages, the path must include /page/:


A simple index page looks like:

`c`Bd00`Ffff  POUTINE NODE
`c`Bfff`Fd00  Calgary, Alberta, Canada
``

>What's Here

A few things I learned the hard way:

Bold is ! not *. The * code toggles italic. Using * inside link labels causes the parser to interpret it as a formatting command and break the link. If your links render as plain text with a stray ] at the end, this is why.

Colour reset after coloured headers. If you set a background colour for a header block, all following text inherits it unless you explicitly reset. Add `` after the header to clear everything.

MeshChat's browser doesn't support form fields. NomadNet's TUI (terminal interface) supports interactive input fields — visitors can type into them and submit forms. MeshChat's built-in NomadNet browser does not implement this. Form-based guestbooks and interactive pages only work for visitors using the actual NomadNet TUI, not MeshChat.

Dynamic Pages

Any page file in the pages directory that is marked executable gets run as a script rather than served as static content. The script prints Micron markup to stdout, and NomadNet serves the output. This works with Python, bash, or anything executable.

A visitor counter that increments on every page load:

#!/usr/bin/env python3
import os

COUNTER_FILE = os.path.expanduser("~/.nomadnetwork/storage/visitor_count.txt")

count = 1
if os.path.isfile(COUNTER_FILE):
    with open(COUNTER_FILE, "r") as f:
        try:
            count = int(f.read().strip()) + 1
        except:
            count = 1

with open(COUNTER_FILE, "w") as f:
    f.write(str(count))

print("`c You are visitor number", count)
print("`[Home`:/page/index.mu]")

Save this as counter.mu, then make it executable:

chmod

NomadNet detects the executable bit and runs it on each request. No config changes needed.

Browsing Your Node From MeshChat

MeshChat has a built-in NomadNet page browser. Once your node is running and announcing, it will appear automatically in the Announces tab under Nomad Network. Double-clicking it loads your index page.

You can also navigate directly by entering your node's address in the URL bar:

Other people on the global Reticulum network — connected via TCP community nodes, I2P, or LoRa — can discover your node the same way. It shows up in their announces list within minutes of yours going out. The node address is permanent (it's derived from your cryptographic identity), so once someone saves it they can always reach you.

Automated Backups

One thing the SD card failure from earlier this build taught me: config and identity files are worth protecting. A backup script:

tar -czf ~/backups/config_$(date +%Y%m%d_%H%M)

Add it to crontab to run daily at 2am:

0 2 * * * tar -czf ~/backups/config_$(date +\%Y\%m\%

The tar: Removing leading '/' from member names warning is harmless — tar is just noting it's stripping absolute paths, which is normal behaviour.

Remote Access: WireGuard

One remaining gap: MeshChat is accessible at pizza.local:8000 on the local network, but not from outside. The goal was to fix this without relying on third-party services.

WireGuard is a modern VPN protocol — lightweight, fast, and well-audited. The setup:

On the Pi, install WireGuard and generate keys:

sudo apt install wireguard
mkdir -p ~/.wireguard && chmod 700 ~/.wireguard
wg genkey | tee

Create /etc/wireguard/wg0.conf on the Pi:

[Interface]
Address = 10.0.0.1/24
PrivateKey = YOUR_PI_PRIVATE_KEY
ListenPort = 51820

[Peer]
PublicKey = YOUR_MAC_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32

Do the same on your Mac (using Homebrew's wireguard-tools), with the Pi as the peer:

[Interface]
Address = 10.0.0.2/24
PrivateKey = YOUR_MAC_PRIVATE_KEY

[Peer]
PublicKey = YOUR_PI_PUBLIC_KEY
Endpoint = YOUR_HOME_IP:51820
AllowedIPs = 10.0.0.1/32
PersistentKeepalive = 25

Start on both ends:

sudo

The tunnel came up immediately and ping worked:

ping 10.0.0.1
# 64 bytes from 10.0.0.1: icmp_seq=0 ttl=64 time=2.9 ms

MeshChat at http://10.0.0.1:8000 is the next step — getting that accessible over the tunnel requires port forwarding on the router, which is a todo for the next session.

What's Running Now

Services on the Pi:

  • rnsd.service — Reticulum transport daemon

  • meshchat.service — MeshChat web interface

  • i2pd.service — I2P daemon (backup global connectivity)

  • nomadnet — page server via crontab watchdog

Interfaces:

  • AutoInterface — local WiFi/Ethernet peer discovery

  • RNodeInterface[Calgary RNode] — LilyGo LoRa32 v2.1 on 868 MHz

  • MeshCoreInterface[MeshCore] — Heltec v3 MeshCore bridge

  • TCPClientInterface[rmap.world] — global backbone

  • TCPClientInterface[dismail.de] — global backbone

  • TCPClientInterface[reticulum.n7ekb.net] — global backbone with LXMF propagation

  • I2PInterfacePeer × 2 — backup I2P connectivity

Lessons From Today

The Reticulum testnet is gone. If you're following guides that reference dublin.connect.reticulum.network or frankfurt.connect.reticulum.network, those are dead. Go straight to the community node list on the Reticulum GitHub wiki.

Test TCP before assuming ISP blocking. We wasted time on I2P workarounds in Part 2 based on a wrong assumption. Shaw does do DNS interception, but it doesn't block standard community node ports. Test with nc -zv hostname port before concluding anything about your ISP.

Bold in Micron is !, not *. Italic is *. Using the wrong one inside link labels silently breaks the link in ways that are annoying to debug.

NomadNet forms don't work in MeshChat's browser. Form fields are a NomadNet TUI feature. If you want interactive pages accessible to MeshChat users, design around this limitation — use LXMF messaging for interactivity instead of forms.

Dynamic pages are simple. Any executable file in the pages directory gets run and its stdout served. No framework, no config, no special setup beyond chmod +x.

What's Next

  • Complete the WireGuard setup so MeshChat is accessible remotely

  • Android Sideband setup with Heltec #2

  • Real-world range testing in Calgary

  • Expanding the friend network — each person needs a Heltec v3 (~$25 CAD) and either NomadNet or Sideband

The Poutine Node is live on the global Reticulum network. If you're running NomadNet or MeshChat, it should appear in your announces within a few minutes. Node address: 99c72beeccc9395effa7ec7105f29f59.

Related posts

March 31, 2026

Building a Reticulum Mesh Network — Part 2

Description

March 31, 2026

Building a Reticulum Mesh Network — Part 2

Description

March 30, 2026

Lessons Learnt - Part 1

Description

March 30, 2026

Lessons Learnt - Part 1

Description

Got questions?

I’m always excited to collaborate on innovative and exciting projects!

Got questions?

I’m always excited to collaborate on innovative and exciting projects!

Lisa Zhao, 2025

XX

Lisa Zhao, 2025

XX