Building a Reticulum Mesh Network — Part 2

Date

Date

March 31, 2026

March 31, 2026

Author

Author

Lisa Zhao

Lisa Zhao

Heltec Nodes, MeshCore Bridging, I2P Connectivity, and Proving LoRa Actually Works

This is Part 2 of the Reticulum mesh network build. Part 1 covered flashing a LilyGo LoRa32 as an RNode and setting up a Raspberry Pi relay with MeshChat. If you haven't done that yet, start there.

At the end of Part 1 we had a working Pi relay on the local network with a LilyGo RNode attached. Today we extend that into a real multi-network mesh:

  • Fix a DNS/connectivity problem caused by ISP port blocking (Shaw/Rogers Canada)

  • Connect to the global Reticulum network via I2P

  • Flash two Heltec v3 nodes — one as a MeshCore bridge, one as a portable RNode

  • Set up the MeshCore-to-Reticulum bridge

  • Prove LoRa is actually working with a real-world test

The Problem We Hit First: Shaw Blocks Everything

After getting the Pi relay working locally, the next goal was connecting it to the global Reticulum testnet so anyone on Reticulum worldwide could reach our node.

The standard approach is adding a TCP interface to the Dublin testnet hub:

[[RNS Testnet Dublin]

This didn't work. rnstatus showed the interface permanently Down.

What we discovered: Shaw (Rogers) in Canada does two things that break this:

  1. Intercepts all DNS queries — regardless of what nameserver you configure in /etc/resolv.conf, Shaw routes port 53 traffic through their own servers. Setting nameserver 8.8.8.8 has zero effect.

  2. Blocks outbound TCP on non-standard ports — ports 4965, 4242, 2424 and others all time out. Port 443 (HTTPS) works fine, but almost no Reticulum nodes run on port 443.

We tried many things that didn't work:

  • Changing nameservers in resolv.conf

  • Editing nsswitch.conf

  • Installing systemd-resolved with DNSOverTLS

  • Installing dnscrypt-proxy (the proxy-dns feature was removed in version 2026.2.0)

  • Hardcoding IP addresses to bypass DNS (the IPs were reachable via ping but TCP on port 4965 still timed out)

The lesson: If you're on Shaw or Rogers in Canada, don't spend time trying to fix DNS or find nodes on different ports. Go straight to I2P. It's the right solution and takes 10 minutes.

The Solution: I2P

Reticulum has built-in support for I2P (Invisible Internet Project) as a network transport. I2P routes traffic through encrypted tunnels across a distributed volunteer network. Its traffic looks like normal encrypted HTTPS to your ISP — Shaw can't block it without breaking a huge amount of other traffic.

Step 1 — Install i2pd

i2pd is a lightweight C++ I2P daemon. Install it on the Pi:


Verify it's running:

Step 2 — Add the I2P Interface to Reticulum

Add this in the [interfaces] section:

  [[RNS Testnet I2P Hub A]

Save, then restart rnsd:

Step 3 — Wait for the Tunnel

Run rnstatus:

You'll first see this — don't panic, it's normal:

I2PInterfacePeer[RNS Testnet I2P Hub A ...]

I2P takes 5-10 minutes on first run to integrate into the network and negotiate a tunnel path. Walk away, come back, and run rnstatus again. Eventually you'll see:

I2PInterfacePeer[RNS Testnet I2P Hub A ...]

That means you're connected to the global Reticulum network.

About the I2P errors in the logs: You may see errors like "key is invalid" and "bad file descriptor" in sudo journalctl -u rnsd. These are normal — I2P tunnels occasionally reset and rebuild automatically. It's noisy but self-healing.

Clean up your config: Remove any TCP testnet interfaces you added earlier (Dublin, noDNS etc.) — they won't connect through Shaw's port blocking and just add clutter.

Understanding What's Now Running

At this point the Pi has three systemd services running automatically:

  • rnsd.service — Reticulum transport daemon

  • meshchat.service — MeshChat web interface

  • i2pd.service — I2P daemon

Check all three are healthy:

And verify rnstatus shows everything up:

You should see AutoInterface, RNodeInterface, and I2PInterfacePeer all showing Status: Up.

Part 2: The Heltec v3 Nodes

The Heltec LoRa32 v3 is a better choice than the LilyGo LoRa32 for new nodes:

  • Uses the newer SX1262 chip vs LilyGo's SX1276

  • 22 dBm max transmit power vs LilyGo's 17 dBm

  • Actively supported by the RNode firmware project

  • Cheaper and easier to source (~$20-25 CAD from AliExpress)

We're using two Heltec v3 nodes with different roles:

  • Heltec #1 → MeshCore Companion firmware → bridge between MeshCore and Reticulum networks, plugged permanently into the Pi

  • Heltec #2 → RNode firmware → portable node, connects to Android phone via Sideband for field use

Flashing Heltec #1 as MeshCore Companion

Why MeshCore?

MeshCore is a newer mesh protocol with better routing than Meshtastic (hybrid routing vs flood routing). The bridge between MeshCore and Reticulum exists and works, making it possible to route Reticulum traffic through the MeshCore network and vice versa. MeshCore also has proper iOS and Android apps.

For the bridge role, we want Companion USB firmware — this is designed to connect to a host computer over serial USB, which is exactly how our Pi will communicate with it.

Flashing

Plug the Heltec into your Mac. Open Chrome and go to:

flasher.meshcore.co.uk

Select:

  • Device: Heltec LoRa32 v3

  • Firmware type: Companion USB (not Companion BLE — this node connects via USB, not Bluetooth)

Click Flash and follow the prompts.

When done, plug the Heltec into the Pi. With the LilyGo already on /dev/ttyACM0, the Heltec will appear as /dev/ttyUSB0. Verify:

You should see both devices.

Setting Up the MeshCore-to-Reticulum Bridge

The bridge is a custom Reticulum interface that treats the MeshCore network as a transport layer. Reticulum routes packets over MeshCore just like it routes over LoRa or WiFi.

Stability note: MeshCore firmware and the bridge software are still maturing. Packet delivery is not always guaranteed and may require retries. It's suitable for extending coverage but not yet for critical communication.

Step 1 — Install the Bridge


Step 2 — Add MeshCore to Reticulum Config

Add in the [interfaces] section:

  [[MeshCore]

Critical: The type must be MeshCore_Interface with an underscore. Using MeshCoreInterface (no underscore) will silently fail — the interface loads but never initialises, with no error message. This wasted significant debugging time.

Save, then restart rnsd:


You should see:

MeshCoreInterface[MeshCore]

Troubleshooting the Bridge

Interface not showing up in rnstatus: Check the type name in your config. It must exactly match the class name in the interface file:

Whatever class name that shows — use that exact string as your type = value.

Bridge silently hanging: The meshcore Python library changed its API between versions. The comms-engineer fork of RNS_Over_Meshcore is updated to work with the current library. If you're using the terminator513 fork, it may hang silently due to API incompatibility.

Serial port not accessible: Make sure your user is in the dialout group:

Log out and back in for it to take effect.

Flashing Heltec #2 as an RNode (Portable Node)

Open Chrome and go to:

liamcottle.github.io/rnode-flasher

Select:

  • Product: Heltec LoRa32 v3

  • Model: 868/915 MHz (915 MHz for North America)

Click Download Firmware, then Choose File, then Flash Now.

If flashing fails, use this sequence to enter download mode on the Heltec v3:

  1. Hold the BOOT button

  2. Press and release RST

  3. Release BOOT

  4. Then click Flash Now

Verify after flashing:

You should see:

  • Product: Heltec LoRa32 v3

  • Firmware version: 1.85

  • Modem chip: SX1262

  • Max TX power: 22 dBm

The "Device signature validation failed" warning is expected when checking from a different machine than the one that flashed it. Not a real problem.

Configuring the Portable Heltec in MeshChat

With Heltec #2 plugged into your Mac, run MeshChat:

Go to http://127.0.0.1:8000 → Interfaces → Add Interface.

Fill in:

  • Name: Portable Heltec (or any name)

  • Type: RNode Interface

  • Port: /dev/tty.usbserial-0001 (check your actual port with ls /dev/tty.*)

  • Frequency: 915000000

  • Bandwidth: 125000

  • TX Power: 14

  • Spreading Factor: 8

  • Coding Rate: 6

Save and restart MeshChat when prompted. The interface should show as green/Up.

Testing LoRa: Proving Radio Actually Works

At this point you might be wondering — are messages actually going over LoRa, or are they just using WiFi? This is a valid question and worth verifying properly.

The test: Disconnect your Mac from home WiFi so the only possible path between your Mac and the Pi is via LoRa radio.

Option A — Connect Mac to phone hotspot: Go to System Settings → WiFi on your Mac and connect to your phone's mobile hotspot. Your Mac and Pi are now on completely different networks. Any message delivery must go via radio.

Option B — Turn off Mac WiFi entirely: No network at all. Messages can only travel via the Heltec RNode's radio interface.

What to do:

  1. Make sure MeshChat is running on your Mac with the Portable Heltec interface active

  2. Switch networks (hotspot or WiFi off)

  3. Wait 30 seconds

  4. Open MeshChat and send a message to your Pi's identity

  5. If it delivers — that's LoRa

What success looks like:

  • The Pi still appears in the Network Visualiser even after switching networks

  • Messages deliver successfully

  • On the Pi, running python3 -m RNS.Utilities.rnstatus shows RNode traffic bytes increasing

Result from our test: Both scenarios — phone hotspot and WiFi completely off — delivered messages successfully. LoRa confirmed working.

Your Complete Setup at This Point

Run rnstatus on the Pi to see the full picture:

A fully working setup looks like:

AutoInterface[Default Interface]
   Status : Up
   Peers  : 1 reachable

I2PInterfacePeer[RNS Testnet I2P Hub A ...]
   Status : Up
   I2P    : Tunnel Active
   Traffic: ↑2.02 KB

MeshCoreInterface[MeshCore]
   Status : Up
   Rate   : 62.50 kbps

RNodeInterface[Home RNode]

Four interfaces, three different transport technologies, all running simultaneously. Reticulum handles routing between them automatically.

What the MeshCore Bridge Actually Does

It's worth being clear about what this achieves and what it doesn't.

What it does:

  • Your Pi appears as a node on the local MeshCore radio network

  • MeshCore nodes in LoRa range of your Pi can relay Reticulum packets through the MeshCore network

  • Reticulum treats MeshCore as just another radio transport — if a path through MeshCore nodes is available to reach a destination, Reticulum will use it automatically

What it doesn't do (yet):

  • MeshCore app users can't just open their app and message your Reticulum identity directly — the addressing systems are different

  • It's not a seamless chat bridge for end users; it's a transport layer bridge for Reticulum packets

Practically speaking: If there are active MeshCore nodes between you and someone else running Reticulum, those nodes extend your effective range without you needing to do anything extra. The more MeshCore infrastructure exists in your city, the more useful this bridge becomes.

Why Transport Mode Matters

With enable_transport = True in your Reticulum config, your Pi doesn't just serve its own traffic — it actively relays packets for any node that can reach it.

In practice this means:

  • A friend with a portable Heltec RNode who is out of direct LoRa range of their own gateway can route through your Pi

  • A global Reticulum user connecting via I2P can have their packets forwarded out over LoRa to local nodes

  • Your Pi bridges between the I2P internet-connected network and the local LoRa radio network automatically

Every transport node makes the mesh more resilient. You're building local infrastructure, not just using it.

Lessons From Today

On Shaw/Rogers ISP: If you're in Canada on Shaw or Rogers, plan for I2P from the start. DNS interception and non-standard port blocking will prevent direct TCP connections to any Reticulum testnet node. I2P bypasses both problems in one step and takes 10 minutes to set up. Don't waste time on DNS fixes.

On MeshCore bridge debugging: The type = MeshCore_Interface underscore matters. The bridge silently does nothing if the type name doesn't exactly match the class in the interface file. Always verify with grep "class.*Interface" on the interface file if an interface doesn't show up in rnstatus.

On testing LoRa: You can't confirm LoRa is working until you remove all other possible paths. Disconnecting from home WiFi and using a phone hotspot is the quickest real-world test. If messages still deliver, they went over radio.

On Heltec vs LilyGo: The Heltec v3's SX1262 chip and 22 dBm transmit power are meaningfully better than the LilyGo's SX1276 at 17 dBm. On flat terrain like Calgary, this could mean the difference between 12km and 18km range. For home relay use where the node is always plugged in, LilyGo is fine. For portable use, Heltec is the better choice.

What's Next

  • Android + Sideband — replacing the Mac with an Android phone for portable use, paired to Heltec #2 via Bluetooth

  • Range testing — measuring real-world LoRa range with the outdoor antenna at height

  • letsmesh.org — checking if the MeshCore node is visible on the community map

  • Adding more people — each person needs a Heltec v3 (~$25 CAD) and an Android phone running Sideband

The Reticulum manual is at reticulum.network and covers all interface types in detail.

Related posts

March 30, 2026

Lessons Learnt

Description

March 30, 2026

Lessons Learnt

Description

March 27, 2026

Getting Started with Reticulum: From Mac to Raspberry Pi

Description

March 27, 2026

Getting Started with Reticulum: From Mac to Raspberry Pi

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