Building a Self-Contained Phone Network with Asterisk and Grandstream ATAs

Eighteen Lines, One PBX, and a Very Long Day
Three black Grandstream devices with many labels for phone extensions and IP addresses sitting in a tangled mess of phone cords and network cables.
Photo 1. Grandstream HT818 & HT802 for VoIP

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:

/etc/dnsmasq.conf
address=/acs.gdms.cloud/0.0.0.0
address=/fm.grandstream.com/0.0.0.0
address=/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 FORWARD
sudo iptables -A FORWARD -i wlan0 -o eth0 -j ACCEPT
sudo 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=0
sudo sysctl -w net.ipv4.conf.default.rp_filter=0
sudo sysctl -w net.ipv4.conf.eth0.rp_filter=0
sudo 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 ACCEPT
sudo 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:

/etc/sysctl.conf
net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.eth0.rp_filter=0
net.ipv4.conf.wlan0.rp_filter=0

Apply:

sudo sysctl -p

Persist firewall rules:

sudo apt install iptables-persistent -y
sudo netfilter-persistent save

Asterisk Had Opinions Too

Once the network was stable, Asterisk still had its own quirks.

I ran into:

  • duplicate _1XX dialplan 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.

Discover more from Lewis Moten

Subscribe now to keep reading and get access to the full archive.

Continue reading