This is a practical walkthrough for linking multiple AllStarLink repeater nodes through a single public hub node using a hub-and-spoke topology. The goal is to have two (or more) repeater nodes connect privately to a central hub, with the hub being the only publicly-listed node. Audio from any repeater is distributed to all connected nodes.
Configuring the AllStarLink -> Repeater interface will be covered in another article which will be linked here when complete.
This was written based on a real working deployment connecting two 220 MHz repeaters (W3PGH and W3EXW) for the NHARC 220 MHz repeater network, running ASL3 3.8.3 on Raspberry Pi hardware with a Debian-hosted hub.
Topology
[W3PGH repeater Pi] ──┐
node 1998 (private) ├──► [Hub node 29370] ◄── public connections
[W3EXW repeater Pi] ──┘ pa220.nharc.org
node 1999 (private)
- Hub node: Public-facing, no RF, runs on a remote Debian server. This is the only node listed in the AllStar directory.
- Spoke nodes: Private/unlisted, each running on a Raspberry Pi connected directly to a repeater. They initiate a persistent outbound connection to the hub at startup.
Prerequisites
- Two or more Raspberry Pis running ASL3, each already configured and working with their respective repeaters
- A remote server (VPS or dedicated) with Debian 12, root access, and ASL3 installed
- UDP port 4569 open/reachable on the hub server (IAX2)
- ASL3 version 3.8.3 or later on all nodes — earlier versions have a critical bug where
rpt cmd,rpt fun, andstartup_macrosilently fail due to anao2_container_dupassertion error inapp_rpt.so
Upgrade to ASL3 3.8.3
As of this writing, 3.8.3 is in the ASL3 beta repo. Enable it on each machine:
sudo nano /etc/apt/sources.list.d/allstarlink.list
Uncomment the beta line:
deb [signed-by=/etc/apt/keyrings/allstarlink.gpg] https://repo.allstarlink.org/public bookworm main beta
Then upgrade:
sudo apt update
sudo apt install asl3-asterisk asl3-asterisk-modules asl3-asterisk-config
sudo systemctl restart asterisk
Do this on all three machines before proceeding.
Node Number Plan
Repurpose your existing registered node number for the hub. The spoke nodes use private (unregistered) node numbers in the 1000–1999 range — these are never routed through the AllStar network and are invisible to the outside world.
| Role | Node | Location |
|---|---|---|
| Hub | 29370 | pa220.nharc.org (Debian server) |
| W3PGH spoke | 1998 | Raspberry Pi at repeater site |
| W3EXW spoke | 1999 | Raspberry Pi at repeater site |
If you’re repurposing a node number from one of the Pi nodes (as we did here — 29370 originally lived on the W3PGH Pi), log into allstarlink.org and update the server IP for that node to point to your hub server before proceeding.
Hub Node Configuration (Debian server)
/etc/asterisk/rpt.conf
Add or replace the node stanza. The hub has no RF interface — rxchannel=dahdi/pseudo and duplex=0.
[29370]
rxchannel = dahdi/pseudo
duplex = 0
idtime = 0
politeid = 0
idrecording =
idtalkover =
callsign =
hangtime = 1000
althangtime = 4000
totime = 180000
accountcode = RADIO
linktolink = no
nounkeyct = 1
holdofftelem = 1
telemdefault = 1
telemdynamic = 1
lnkactenable = 1
In the [nodes] section, add entries for both spokes:
[nodes]
29370 = [email protected]/29370,NONE
1998 = iax2/[email protected]/1998,NONE
1999 = iax2/[email protected]/1999,NONE
/etc/asterisk/iax.conf
Add a peer account the spokes will authenticate against. The host=dynamic means the hub doesn’t need to know the spokes’ IPs in advance.
[asl]
type = friend
auth = md5
secret = YourSharedSecret
host = dynamic
disallow = all
allow = ulaw
context = radio-secure
requirecalltoken = no
Replace YourSharedSecret with a password of your choosing. You’ll use the same value on the spoke nodes.
/etc/asterisk/extensions.conf
Ensure the radio-secure context routes to app_rpt:
[radio-secure]
exten => _XXXX!,1,Set(NODENUM=${CALLERID(num)})
same => n,rpt(${EXTEN})
The default ASL3 extensions.conf already has a suitable radio-secure context — verify it exists and handles incoming connections correctly.
Firewall
Open UDP 4569 for IAX2:
# ufw
ufw allow 4569/udp
# or iptables
iptables -A INPUT -p udp –dport 4569 -j ACCEPT
Spoke Node Configuration (Raspberry Pis)
The configuration is identical for each spoke — just swap the node number. These steps show node 1998 (W3PGH); repeat for 1999 (W3EXW).
/etc/asterisk/rpt.conf
In the [nodes] section, add your local node and the hub:
[nodes]
1998 = [email protected]/1998,NONE
29370 = [email protected]/29370,NONE
In the node stanza, key settings are duplex=2, public=0 (unlisted), and startup_macro to auto-connect at boot. Also uncomment the *813 permanent connect command which is required for startup_macro to work:
813 = ilink,13 ; Permanently connect specified link — transceive
Then in your [1998](node-main) stanza:
[1998](node-main)
rxchannel = Radio/1998 ; keep whatever was working before
duplex = 2
idtime = 0
politeid = 0
idrecording =
idtalkover =
callsign =
public = 0
startup_macro = pppppppppppppppppppp*81329370
The p characters are 500ms pauses each — 20 of them gives a 10-second delay before attempting the connection, which ensures the network stack is fully up before IAX2 tries to dial out. *813 is the permanent transceive connect command, followed by the hub node number.
/etc/asterisk/iax.conf
Add a peer definition pointing to the hub:
[pa220]
type = friend
auth = md5
secret = YourSharedSecret
host = pa220.nharc.org
disallow = all
allow = ulaw
context = radio-secure
requirecalltoken = no
Use the same YourSharedSecret as on the hub.
Startup and Verification
Start the hub first, then restart each spoke. The spokes will initiate the connection at startup via startup_macro.
# On the hub
systemctl restart asterisk
# On each spoke Pi
sudo systemctl restart asterisk
After about 15–20 seconds, verify both sides:
# On the hub
asterisk -rx “rpt lstats 29370”
# On a spoke
sudo asterisk -rx “rpt lstats 1998”
A working connection looks like:
NODE PEER RECONNECTS DIRECTION CONNECT TIME CONNECT STATE
—- —- ———- ——— ———— ————-
1998 66.207.128.40 0 IN 00:00:03:722 ESTABLISHED
1999 71.245.177.59 0 IN 00:00:03:763 ESTABLISHED
Both spokes should show ESTABLISHED. The hub should show both spokes connected IN; each spoke should show the hub connected OUT.
Expanding to Additional Repeaters
Adding a third (or fourth) repeater to the network is straightforward:
- Assign it a private node number (e.g., 2000)
- Configure it identically to the existing spokes, pointing
startup_macroat the hub - Add a
[nodes]entry on the hub for the new node - No changes needed on existing spokes — the hub handles distribution
Troubleshooting Notes
rpt cmd / rpt fun crashes with ao2_container_dup assertion — this is a bug in ASL3 prior to 3.8.3. Upgrade to 3.8.3 from the beta repo.
startup_macro silently does nothing — same root cause as above. Also verify that the *813 ilink command is uncommented in rpt.conf; it’s commented out by default in ASL3 and startup_macro won’t fire without it.
Packets reach the hub but IAX2 drops them with “Silently dropping frame without existent call number” — usually an auth mismatch between the [asl] peer on the hub and the [pa220] peer on the spoke. Verify the secret= values match exactly on both sides.
Node shows in rpt localnodes but rpt stats returns nothing — the node loaded but isn’t fully active, usually because the USB radio interface isn’t coming up. Check sudo asterisk -rx "radio show settings" and verify the USB device is present with lsusb.
DNS lookup for hub node returns wrong IP — if you repurposed an existing node number, update the server IP in your allstarlink.org account. Verify with dig 29370.nodes.allstarlink.org and dig pa220.nharc.org — they should resolve to the same address.
