Eighteen Lines, One PBX, and a Very Long Day

I already had a 2-port ATA in place, and for a while, that was enough. But as more phones started coming in—especially additional rotary phones, a pair of teletype machines, and a pair of crank phones being brought to life—it quickly became clear that two lines wasn’t going to cut it.
I had been using a simple 5-way splitter that acts like a party line, which works fine in a pinch, but it introduces limitations:
- only a couple of people can realistically use the system at once
- everything shares the same line behavior
- no room for experimentation
The bigger goal isn’t just connectivity—it’s interaction.
I want different phones to behave differently. Dialing the same number from different phones can produce different responses, opening the door to puzzle-style interactions and layered experiences.
That kind of design needs independent lines.
The Cost vs Value
I picked up both 8-port ATAs on eBay for $105.28 total. For comparison, a new 2-port ATA alone was $56.59.
The listing warned that the devices were auto-provisioned and didn’t include power adapters. The adapters ended up being easy—I found a 2-pack of 12V 2A supplies for about $10. (Higher amperage is fine; the device only draws what it needs.)
So the cost per line dropped significantly—but it came with a steep setup curve.
The Reset That Didn’t Fix It
Each ATA has a small reset hole on the back. I assumed that using a SIM ejector tool to factory reset them would clear everything.
It didn’t.
Even after resetting, the devices would reach out to remote servers and pull down configuration changes—including the admin password. The manufacturer’s provisioning system can uniquely identify the devices and reapply settings automatically.
So resetting alone wasn’t enough. I needed to control what the devices could reach.
Cutting Off the Provisioning Servers
Instead of blocking all internet access, I took a more targeted approach.
I redirected provisioning-related domains to a “black hole” using dnsmasq:
address=/acs.gdms.cloud/0.0.0.0address=/fm.grandstream.com/0.0.0.0address=/stun1.gdms.cloud/0.0.0.0
This allowed:
- the Pi to keep internet access
- the ATAs to stay local
- provisioning attempts to silently fail
Between DNS blackholing and firewall rules later on, the ATAs were effectively isolated without breaking the Pi’s ability to function as a gateway.
From Tunneling to a Real Network Gateway
At first, my laptop didn’t have a direct connection to the ATA network.
The Raspberry Pi sat between two networks:
- WiFi (
192.168.23.x) → my normal network - Ethernet (
192.168.50.x) → the ATA network
Initially, I tunneled into devices through the Pi. That worked with one device, but didn’t scale. Every new ATA meant more tunnels, more ports, and more overhead just to load a web interface.
So I changed direction:
Turn the Raspberry Pi into a proper gateway.
Turning the Raspberry Pi into a Router
First, enable IP forwarding:
sudo sysctl -w net.ipv4.ip_forward=1
Then allow traffic between interfaces:
sudo iptables -F FORWARDsudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPTsudo iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT
Now traffic could move freely between networks.
The NAT Direction Mistake
I initially set up NAT in the wrong direction:
POSTROUTING -o eth0 -j MASQUERADE ❌ wrong
POSTROUTING -o wlan0 -j MASQUERADE âś… correct
This was one of those issues where everything looked correct at first glance, but traffic was quietly failing in one direction. Once NAT was applied to the WiFi interface, things immediately started working.
The Critical Fix: Reverse Path Filtering
Even after routing and NAT were configured, things still weren’t quite right.
The fix was disabling reverse path filtering:
sudo sysctl -w net.ipv4.conf.all.rp_filter=0sudo sysctl -w net.ipv4.conf.default.rp_filter=0sudo sysctl -w net.ipv4.conf.eth0.rp_filter=0sudo sysctl -w net.ipv4.conf.wlan0.rp_filter=0
Without this, the Pi silently dropped valid return traffic between networks.
Teaching the Mac How to Reach the ATA Network
Once routing worked, the laptop still didn’t know how to reach the 192.168.50.x network. The Raspberry Pi was accessible from the laptop at 192.168.23.177. Adding a route fixed it:
sudo route -n add 192.168.50.0/24 192.168.23.177
After that:
http://192.168.50.100
http://192.168.50.101
http://192.168.50.102
No more tunnels.
A Classic Networking Trap
Some devices wouldn’t respond to ping at all—even though their web interfaces worked fine.
At the same time:
- they were reachable from the Pi
- but not from the Mac (until routing was fixed)
It was a good reminder:
“Can’t ping” doesn’t always mean “can’t connect.”
When the ATA Is a Router (and You Don’t Want It To Be)
The 8-port ATAs weren’t just adapters—they were routers.
They were:
- running DHCP
- creating their own subnet
- NAT’ing traffic internally
So instead of:
- Pi → ATA → phones
I had:
- Pi → ATA (router) → hidden subnet → phones
That explained a lot of the weird behavior. I had dnsmasq running on the Pi—but the ATAs could also hand out IPs.
The fix:
- disable NAT
- disable DHCP
- switch to bridge mode
Switching to bridge mode didn’t just fix the network—it removed an entire layer of complexity I didn’t need.
The WAN vs LAN MAC Trap
Each ATA had two MAC addresses:
- WAN
- LAN
Only one was labeled on the underside of the device.
Using the wrong one for DHCP reservations meant the device never received the expected IP address.
When Even iptables Was Missing
At one point, basic tools weren’t even installed:
sudo: iptables: command not found
Fix:
sudo apt install iptables -y
ARP Told the Truth
At one point:
192.168.50.102 at <incomplete>
That turned out to be a key clue—the device wasn’t actually reachable on the network.
Restricting ATA Internet Access
I didn’t want the ATAs reaching the internet, but the Pi still needed access.
So I allowed established traffic but blocked new outbound connections:
sudo iptables -A FORWARD -i eth0 -o wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPTsudo iptables -A FORWARD -i eth0 -o wlan0 -j REJECT
Combined with DNS blackholing, this kept provisioning disabled.
Making It All Persistent
To survive reboot:
sudo nano /etc/sysctl.conf
Add:
net.ipv4.ip_forward=1net.ipv4.conf.all.rp_filter=0net.ipv4.conf.default.rp_filter=0net.ipv4.conf.eth0.rp_filter=0net.ipv4.conf.wlan0.rp_filter=0
Apply:
sudo sysctl -p
Persist firewall rules:
sudo apt install iptables-persistent -ysudo netfilter-persistent save
Asterisk Had Opinions Too
Once the network was stable, Asterisk still had its own quirks.
I ran into:
- duplicate
_1XXdialplan entries - endpoints going unreachable during reload
- calls to the same extension returning busy instead of voicemail
For example, duplicate dialplan patterns caused reload warnings, and voicemail behavior needed separate handling for self-calls.
Each issue was small, but they added up over the course of the day.
Where This Landed
Moving from SSH tunnels to a routed gateway made everything simpler:
- direct browser access to every device
- no per-device setup overhead
- predictable networking
- full control over traffic
It stopped feeling like a workaround and started feeling like infrastructure.
Where This Is Going Next
Right now, adding a number involves:
- creating a SIP endpoint
- adding a mailbox
- updating the dialplan
- mapping to a port
- assigning audio
It works—but it’s manual.
The next step is building an interface that:
- assigns extensions
- generates configuration
- outputs copy/paste-ready Asterisk snippets
What This Is
I now have a system with three different ATA devices, where phones from one device can dial any phone on any other device. They can also dial their own extension to reach the voicemail manager and review messages. It sounds simple, but the path to get to this point was not. Going forward, adding phones and additional ATA devices will be easier, but it is unlikely unless the director proposes a large exhibit of phones.
What This Enables
With 18 independent lines:
- phones can behave differently
- shared numbers can produce different results
- puzzle mechanics can be layered in
- everything runs locally
It’s no longer just a phone setup—it’s becoming an interactive system, where the network, hardware, and behavior all work together to create something intentional.
Regarding shared numbers producing different results, the old crank phones can be set up to play a different audio file, perhaps an older way of speaking or references to events long-forgotten. The Roaring Twenties is something I could lean into.
The Physical Layer
The final piece is the presentation.
The goal is to build out a phone nook:
- a light
- calendar
- clock
- memo pad
- cork board
- rolodex
- printed phone book
Not just phones on a table—but an environment that feels real. The environment may provide clues for finding audio within the system.
