Dial-up internet connections may feel like a relic of the past, but modern telephony equipment makes it cheap & easy to set up your own dial-up ISP!
Forget about pricey interconnects with the phone company: with a few pieces of commodity hardware and an hour of setup, you can emulate a blazing fast 56 kbps  network connection between two or more clients.
- 1 Requirements
- 2 Setting up the Dial-in Server
- 3 The Telephone Network
- 4 The Dial-in Server
- 5 Connecting with a client
- 6 Troubleshooting
- 7 Notes
|Suggested hardware||Used in this guide|
|Dial-in server||Any computer that supports a Unix/Linux operating system||Raspberry Pi 3 model B|
|Server modem(s)||Any hardware modem(s) (see the Choosing Modem Hardware section below)|
|Client device(s)||Any computer with a dial-up modem||
|Telephony||Any device that can emulate a telephone line||4x Linksys SPA-2102 analog telephone adapters (ATA) (don't stack these — they get very hot!)|
|Connectors and adapters||Whatever you need to connect the server modems to the dial-in server||
|Suggested software||Used in this guide|
|Dial-in server||Any Linux/Unix operating system||Debian Buster (Raspbian Lite release)|
|Telephony||Real PSTN telephone lines, custom dial tone circuitry, or a software PBX||Asterisk v16.2.1|
|Tunnelling daemon||Any ppp daemon||Samba ppp v2.4.7|
|Terminal manager||Any terminal multiplexer with virtual terminal support||mgetty v1.2.1|
Choosing Modem Hardware
Despite variations in modem hardware, this guide should work with any dial-up modem that presents itself as a serial device to the operating system, whether it connects over USB, ISA, PCI, or RS-232.
However, you should avoid using software modems (sometimes called "softmodems" or "Winmodems") because they are error-prone and difficult to debug. This guide uses three external serial modems (with USB to RS-232 adapters) and one USB modem. Dedicated serial hardware is easy to troubleshoot, and scales to as many lines as you have USB/RS-232 ports.
Dial-up over VoIP can be unreliable so it is best to keep speeds low. If you don't already have a modem I would recommend looking for a 14.4k modem for the sake of reliability.
Setting up the Dial-in Server
The dial-in server will answer calls from the modems and act as a proxy for network resources.
Using a Raspberry Pi
- Download the latest version of Raspbian Lite from raspberrypi.org and follow the installation instructions
- Before installing the SD card in your Raspberry Pi, enable SSH to avoid needing a mouse and keyboard:
- Mount the Raspberry Pi boot partition (most operating systems will do this automatically after writing the image)
- Create an empty file named
ssh(with no extension) in the same folder as
- Safely eject the SD card
- Insert the SD card in your Raspberry Pi and connect the power and network cables
- Connect to the Raspberry Pi using SSH with the default username
- If you know the IP address of the Pi, you can connect to it directly using your operating system's built-in SSH client (on Windows, click here for instructions to install openssh, or use a standalone client like PuTTY)
- If you don't know the IP address of the Pi, use a utility like Adafruit's Pi Finder to find its IP address and log in
Using a PC or other hardware
Install a Linux or Unix distribution of your choice before proceeding. Installation instructions are beyond the scope of this guide; you should consult your distribution's instructions for help. The commands given in this guide may need to be changed if you're not using a Debian-derived Linux. (Click these links for installation instructions for Ubuntu and Debian).
The Telephone Network
We need a way to connect our ISP modem to clients. There are many ways to approach this:
- Use the actual PSTN (real phone lines)
- Use a PBX to provide local connectivity
- Build your own circuity
- Build a fake PSTN using VoIP ATAs and a software PBX
This guide builds a fake PSTN with SIP and ATAs. Here's the breakdown:
- Asterisk — a VoIP PBX on the dial-in server — accepts connections from multiple SIP client accounts and routes calls between them.
- Cisco-Linksys SPA-2102 ATAs — which support two phone lines each — act as SIP clients connected to the PBX.
- The ISP-side modem(s) each connect to one phone line, and a client device to a second line.
This design can scale up to as many modems and clients as desired: just add more ATAs!
- Install your Debian-based Linux distribution of choice (Raspbian covered above)
- Update to latest packages and reboot if required
- Install Asterisk:
- Append configuration for the SIP clients to the end of
This configuration is for 4 modems and 4 clients on 4 ATAs, but can be extended to as many or as few as you need.
[ata-modem1] context=default ; Using the default context because this is a simple design type=friend ; Allow calls to be placed and received to keep things simple secret=password ; Only the most secure passwords around here qualify=200 ; Qualify peer is no more than 200ms away host=dynamic ; This device registers with us directmedia=yes ; Send RTP directly to the peer to reduce latency and jitter nat=no ; Only use symmetric IP routing [ata-modem2] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no [ata-modem3] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no [ata-modem4] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no [ata-client1] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no [ata-client2] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no [ata-client3] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no [ata-client4] context=default type=friend secret=password qualify=200 host=dynamic directmedia=yes nat=no
/etc/asterisk/extensions.confand make two changes:
- Search for
[default](should be around line 672) and comment out
include => demoby prepending it with a semicolon (
- Underneath that line, add the new lines for the specific modems and the dial pool:
exten => 881,1,Dial(SIP/ata-modem1, 30) exten => 882,1,Dial(SIP/ata-modem2, 30) exten => 883,1,Dial(SIP/ata-modem3, 30) exten => 884,1,Dial(SIP/ata-modem4, 30) exten => _X!,1,Dial(SIP/ata-modem1&SIP/ata-modem2&SIP/ata-modem3&SIP/ata-modem4, 30)The
_X!tells this dial plan rule to match any number a client dials and send the call to all of the ata-modem[1-4] clients simultaneously with a 30 second timeout. To use a specific modemm, dial its extension and only that modem will ring.
- Search for
- Enable the asterisk service so it starts on boot:
sudo systemctl enable asterisk
sudo systemctl start asterisk
sudo apt-get update sudo apt-get upgrade sudo reboot
sudo apt install asterisk
These instructions use unlocked SPA-2102s with firmware versions 5.2.5 and 5.1.13. If your device is locked, follow these instructions to unlock it.
Client and modem lines are configured the same, just with different passwords.
Starting with a factory default configuration, to enable browser-based configuration:
Example of configuring a client line. (Same settings for modem line, just a different username/password)
Lets start with factory default configuration and enabling web-based management.
- Connect a phone to LINE 1
- Dial **** to enter the configuration menu
- Dial 73738# then 1# then hang up. The unit is now factory reset
- Connect the Internet ethernet connection to your local network
- Dial **** to enter the configuration menu
- Dial 7932# then 1# then 1 then hang up. The web interface is now accessible from the 'Internet' side of the ATA
- Dial **** to enter the configuration menu
- Dial 110# to hear the IP address of your ATA
Once browser-based configuration is enabled, navigate to the ATA's IP address and change the following options:
On a PC point your web browser at the IP of the ATA to load the web configuration. Several options need to be changed.
- Click "Admin Login"
- Click "Advanced"
- (Optiona) Click "WAN Setup" if you need to change the IP address of the ATA
- Click the "Voice" tab
- Click "Line 1"
- Change "Network Jitter Level" to "extremely high" or "high"
- Change "Jitter Buffer Adjustment" to "disable"
- Set "Proxy" to the IP address of the Raspberry Pi running askterisk
- Set "User ID" to the username of the SIP user you are configuring, "ata-client3"
- Set "Password" to the password of that user
- Change "Call Waiting Serv" to "no"
- Change "Three Way Call Serv" to "no"
- Change "Preferred Codec" to "G711u"
- Change "Use Pref Codec Only" to "yes"
- Change "Silence Supp Enable" to "no"
- Change "Silence Threshold" to "high"
- Change "Echo Canc Enable" to "no"
- Change "Echo Canc Adapt Enable" to "no"
- Change "Echo Supp Enable" to "no"
- Change "FAX CED Detect Enable" to "no"
- Change "FAX CNG Detect Enable" to "no"
- Change "FAX Process NSE" to "no"
- Change "FAX Enable T38" to "no"
- Click "Submit All Changes"
Repeat these instructions for Line 2 if you need to use both ports.
When your ATA first connects to the SIP proxy (Asterisk), you will see output like this on the Asterisk console (launched with
sudo asterisk -rvvvv):
raspberrypi*CLI> [Apr 27 04:08:29] NOTICE: chan_sip.c:24884 handle_response_peerpoke: Peer 'ata-client1' is now Reachable. (13ms / 200ms) [Apr 27 04:08:29] NOTICE: chan_sip.c:24884 handle_response_peerpoke: Peer 'ata-client2' is now Reachable. (5ms / 200ms)
- Open the Asterisk console (
sudo asterisk -rvvvv) to confirm your ATA lines are registered:
raspberrypi*CLI> sip show peers Name/username Host Dyn Forcerport Comedia ACL Port Status Description ata-client1/ata-client1 10.1.0.126 D No No 5060 OK (7 ms) ata-client2/ata-client2 10.1.0.126 D No No 5061 OK (7 ms) ata-client3/ata-client3 10.1.0.125 D No No 5060 OK (9 ms) ata-client4/ata-client4 10.1.0.125 D No No 5061 OK (10 ms) ata-modem1/ata-modem1 10.1.0.108 D No No 5060 OK (8 ms) ata-modem2/ata-modem2 10.1.0.108 D No No 5061 OK (7 ms) ata-modem3/ata-modem3 10.1.0.128 D No No 5060 OK (7 ms) ata-modem4/ata-modem4 10.1.0.128 D No No 5061 OK (8 ms) 8 sip peers [Monitored: 8 online, 0 offline Unmonitored: 0 online, 0 offline]If you make changes to your configuration after starting Asterisk or if the peers list is empty after changing the configuration, you can use the
reloadcommand in the console to reload the configuration.
- Confirm that clients can dial modems directly. Using a phone connected to one of the client lines, dial 881# (the # tells the ATA you are done dialing). The first modem line should ring.
- Confirm that clients can dial the modem pool. Dial 888# (or any number except the direct modem lines): all modem lines should ring at once.
If you take a look at the asterisk console when dialing the pool, you should see output like this:
raspberrypi*CLI> == Using SIP RTP CoS mark 5 > 0x73a18d80 -- Strict RTP learning after remote address set to: 10.1.0.125:16386 -- Executing [[email protected]:1] Dial("SIP/ata-client3-00000005", "SIP/ata-modem1&SIP/ata-modem2&SIP/ata-modem3&SIP/ata-modem4, 30") in new stack == Using SIP RTP CoS mark 5 == Using SIP RTP CoS mark 5 == Using SIP RTP CoS mark 5 == Using SIP RTP CoS mark 5 -- Called SIP/ata-modem1 -- Called SIP/ata-modem2 -- Called SIP/ata-modem3 -- Called SIP/ata-modem4 -- SIP/ata-modem3-00000008 is ringing -- SIP/ata-modem1-00000006 is ringing -- SIP/ata-modem4-00000009 is ringing -- SIP/ata-modem2-00000007 is ringing
Congratulations! You now have your own voice network.
The Dial-in Server
These instructions are specific to Debian-based Linux distributions, but should be similar for other distributions or Unixes.
- Connect a USB to RS-232 adapter and confirm it shows up as /dev/ttyUSBXXX (Run
dmesgto check). In my case, it presents as
(My serial adapters are "
QinHeng Electronics HL-340 USB-Serial adaptor" per
- Install ppp (and getty if your distribution doesn’t have it by default)
sudo apt-get install ppp mgetty
- Create a systemd service for mgetty, by editing
/lib/systemd/system/[email protected](note the @) with your text editor of choice as root or sudo.
[Unit] Description=External Modem %I Documentation=man:mgetty(8) Requires=systemd-udev-settle.service After=systemd-udev-settle.service [Service] Type=simple ExecStart=/sbin/mgetty /dev/%i Restart=always PIDFile=/var/run/mgetty.pid.%i [Install] WantedBy=multi-user.target
Configure mgetty by editing
Comment out everything except the debug level by prepending lines with a pound/hash (#), and append the section for configuring the serial devices: I have 3 USB to serial devices (ttyUSB0, ttyUSB1, ttyUSB2) and one USB modem ttyACM0:
debug 9 port ttyUSB0 port-owner root port-group dialout port-mode 0660 data-only yes ignore-carrier no toggle-dtr yes toggle-dtr-waittime 500 rings 1 speed 115200 modem-check-time 160 port ttyUSB1 port-owner root port-group dialout port-mode 0660 data-only yes ignore-carrier no toggle-dtr yes toggle-dtr-waittime 500 rings 2 speed 115200 modem-check-time 60 port ttyUSB2 port-owner root port-group dialout port-mode 0660 data-only yes ignore-carrier no toggle-dtr yes toggle-dtr-waittime 500 rings 3 speed 115200 modem-check-time 60 port ttyACM0 port-owner root port-group dialout port-mode 0660 data-only yes ignore-carrier no toggle-dtr yes toggle-dtr-waittime 500 rings 4 speed 115200 modem-check-time 60
ringsparameter tells mgetty to answer the call after that many rings. They increase in the config so that all the modems dont try to answer at once, and you can prioritize which modems you want to be used most often.
- Enable the mgetty service so it starts on boot for each device:
sudo systemctl enable [email protected] sudo systemctl enable [email protected] sudo systemctl enable [email protected] sudo systemctl enable [email protected]
sudo systemctl start [email protected] sudo systemctl start [email protected] sudo systemctl start [email protected] sudo systemctl start [email protected]
- Configure ppp by editing
Like above, comment out everything except these settings:
# Define the DNS server for the client to use ms-dns 184.108.40.206 # async character map should be 0 asyncmap 0 # Require authentication auth # Use hardware flow control crtscts # We want exclusive access to the modem device lock # Show pap passwords in log files to help with debugging show-password # Require the client to authenticate with pap +pap # If you are having trouble with auth enable debugging debug # Heartbeat for control messages, used to determine if the client connection has dropped lcp-echo-interval 30 lcp-echo-failure 4 # Cache the client mac address in the arp system table proxyarp # Disable the IPXCP and IPX protocols. noipx
- Create a device option file for each device by editing:
local lock nocrtscts 192.168.32.1:192.168.32.2 netmask 255.255.255.252 noauth proxyarp lcp-echo-failure 60
local lock nocrtscts 192.168.32.5:192.168.32.6 netmask 255.255.255.252 noauth proxyarp lcp-echo-failure 60
local lock nocrtscts 192.168.32.9:192.168.32.10 netmask 255.255.255.252 noauth proxyarp lcp-echo-failure 60
local lock nocrtscts 192.168.32.13:192.168.32.14 netmask 255.255.255.252 noauth proxyarp lcp-echo-failure 60
Ensure that the IP addresses do not overlap across the device configurations. I'm using small /30 subnets (4 IP addresses, 2 usable) to separate each client.
- Create the user for PAP authentication:
sudo useradd -G dialout,dip,users -m -g users -s /usr/sbin/pppd dial
- Set a password:
sudo passwd dial
/etc/ppp/pap-secretsand append the username and password (same as you entered above, quotes included):
dial * "dial" *
- Enable packet forwarding for IP4 by appending
- To enable the changes made in sysctl.conf
sysctl -p /etc/sysctl.conf
The last step for the dial-up server is to configure the firewall to allow traffic forwarding from PPP out onto the network (and off to the Internet).
- On Linux distributions with iptables-nf switch back to iptables-legacy by running
sudo update-alternatives --config iptablesand choosing iptables-legacy then follow the step below.
- On Linux distributions with iptables (legacy), you need to add a line to
/etc/rc.localto enable masquerading. If your Ethernet interface is named eth0, you would add this line:
iptables -t nat -A POSTROUTING -s 192.168.32.0/24 -o eth0 -j MASQUERADE
On modern Ubuntu installs, ufw is used as a front-end to iptables, so the procedure is a bit different. Follow this guide, but you can omit
-o eth0and use
- On Linux distributions with iptables-nf switch back to iptables-legacy by running
Connecting with a client
Connect a client device to a client line on an ATA and configure it to use PPP authentication with the username
dial and password
To dial a specific modem use the number
881# for modem one. To dial the modem pool dial any other number such as
When using an external modem, the choice of USB to RS-232 adapter seems to be crucial. There aren't many requirements, but you must use an adapter that supports hardware flow control.
If you need to purchase an adapter, you can either get one that explicitly says it supports hardware flow control ($$$), or play the eBay lottery and buy a half-dozen different models and hope one of them works.
To troubleshoot modem communication and baud rate settings, use minicom (or screen) to open a session over serial and try different settings (or read your modem's manual!). Sending the command 'AT' followed by a new line should result in your modem replying 'OK'.
If you're getting nothing at all out of your modem, perform a serial loopback test
If mgetty is not answering incoming calls, it may be having trouble communicating with your modem. Check the logs in
/var/log/mgetty/ to determine the problem. You may need to set a modem initialization string in the mgetty device config file, so check your modem's manual for help on this.
If you are having trouble with Asterisk please consult voip-info.org as Asterisk is quite complex and its troubleshooting is outside the scope of this guide.
That said here is a successful call to 888 (pool) as an example:
raspberrypi*CLI> == Using SIP RTP CoS mark 5 > 0x73a18d80 -- Strict RTP learning after remote address set to: 10.1.0.125:16386 -- Executing [[email protected]:1] Dial("SIP/ata-client3-00000005", "SIP/ata-modem1&SIP/ata-modem2&SIP/ata-modem3&SIP/ata-modem4, 30") in new stack == Using SIP RTP CoS mark 5 == Using SIP RTP CoS mark 5 == Using SIP RTP CoS mark 5 == Using SIP RTP CoS mark 5 -- Called SIP/ata-modem1 -- Called SIP/ata-modem2 -- Called SIP/ata-modem3 -- Called SIP/ata-modem4 -- SIP/ata-modem3-00000008 is ringing -- SIP/ata-modem1-00000006 is ringing -- SIP/ata-modem4-00000009 is ringing -- SIP/ata-modem2-00000007 is ringing > 0x73a31a78 -- Strict RTP learning after remote address set to: 10.1.0.108:16386 -- SIP/ata-modem2-00000007 answered SIP/ata-client3-00000005 -- Channel SIP/ata-modem2-00000007 joined 'simple_bridge' basic-bridge <3d2328ec-ef87-431e-be12-2dd9b84b6319> -- Channel SIP/ata-client3-00000005 joined 'simple_bridge' basic-bridge <3d2328ec-ef87-431e-be12-2dd9b84b6319> > Bridge 3d2328ec-ef87-431e-be12-2dd9b84b6319: switching from simple_bridge technology to native_rtp > Remotely bridged 'SIP/ata-client3-00000005' and 'SIP/ata-modem2-00000007' - media will flow directly between them > 0x73a31a78 -- Strict RTP learning after remote address set to: 10.1.0.108:16386 > 0x73a18d80 -- Strict RTP learning after remote address set to: 10.1.0.125:16386 [call proceeds then ends below] -- Channel SIP/ata-modem2-00000007 left 'native_rtp' basic-bridge <3d2328ec-ef87-431e-be12-2dd9b84b6319> -- Channel SIP/ata-client3-00000005 left 'native_rtp' basic-bridge <3d2328ec-ef87-431e-be12-2dd9b84b6319> == Spawn extension (default, 888, 1) exited non-zero on 'SIP/ata-client3-00000005' > 0x73a18d80 -- Strict RTP learning after remote address set to: 10.1.0.125:16386
- Depends on the ISP-side modems used; the hardware used in this guide can only reach a maximum of 33.6k
- This guide is very debian-centric and will need to be adapted for other platforms