Soundmodem, ax25d and uronode

This is mostly a repost of something that was on my now deceased wiki, spruced up a little for this platform.

Start at the top and work down, you should have a basic, working ax25 packet radio system by the end. I shall address netrom at a later date.

I’m using soundmodem as it presents me with an sm0 device I can easily configure in the following steps, however I have also tested direwolf for this successfully.

Note: While this specifies soundmodem, if you change the startup script’s kissattach line to contain a physical tnc or direwolf device, it should still work.

Note: Don’t use my callsign. That’d be bad & illegal.

Get Software

On Debian, I recommend installing the soundmodem, ax25-tools and ax25-apps packages:

sudo apt install ax25-tools ax25-apps soundmodem

Direwolf is also a great tool to replace soundmodem with - it is detailed below soundmodem.

Set up Soundmodem

Using a cheap USB sound interface and soundmodem worked best for me.

For quick reference:


is the alsa string for mine.

I use a Yaesu FT7900 as my data radio, and the interface for that has a usb device to key it which usually /dev/ttyUSB0

See below for my /etc/ax25/soundmodem.conf file - note my channel details: KISS, sm0, MM3ZRZ-5. These are important for later. You’re best off running soundmodemconfig to set these configuration details.

Select New->Configuration, name it and press ok. Highlight the configuration, and again select New->Channel to add a channel. Pull information from the config below to handle the rest…

Hint: The IP information is from Aberdeen University’s 44net allocation. I’d appreciate it if you used your own, or an RFC1918 address:)

<?xml version="1.0"?>
  <configuration name="UHF_Packet">
    <chaccess txdelay="150" slottime="100" ppersist="40" fulldup="0" txtail="10"/>
    <audio type="alsa" device="plughw:CARD=Device,DEV=0" halfdup="1" capturechannelmode="Mono"/>
    <ptt file="/dev/ttyUSB0" hamlib_model="" hamlib_params=""/>
    <channel name="Channel 0">
      <mod mode="afsk" bps="1200" f0="1200" f1="2200" diffenc="1"/>
      <demod mode="afsk" bps="1200" f0="1200" f1="2200" diffdec="1"/>
      <pkt mode="KISS" ifname="sm0" hwaddr="MM3ZRZ-5" ip="" netmask="" broadcast="" file="/dev/soundmodem0" unlink="1"/>

I find that when I’m running soundmodem and want to axcall as a regular user, I need to chmod 666 /dev/soundmodem0 - this makes it read/writable by all users. There’s possibly a bug here, I’m discussing changing the default behaviour so that all users in the dialout group are able to use the soundmodem device within the debian-hams group at the moment.

I run soundmodem as root and start it as sudo soundmodem most commonly

Set up Direwolf

Direwolf works with my usb sound interface also - the config is below.

ADEVICE plughw:CARD=Device,DEV=0



MODEM 1200

PTT /dev/ttyUSB0 RTS

# Uncomment to use Raspberry Pi GPIO number 23


By default, direwolf doesn’t spawn a pseudoterminal, you need to run with the -p flag. This creates /tmp/kisstnc as your device. Direwolf also has a hateful colour scheme by default, I utterly detest it. Use the -t 0 flag to sort that issue out.

My direwolf command ends up looking like:

direwolf -t 0 -p


This file contains information about each of the logical ‘ports’ and what alias and callsign you’re assigning to them. This is somewhat analogous to ports on IP, i.e: 22 for ssh or 443 for https.

It might be clever to name these ports after the service they’re going to provide - “node” and “bbs”, for example.

# /etc/ax25/axports
# The format of this file is:
# name callsign speed paclen window description
radio     MM3ZRZ-5  1200    255     2	General Packetry (1200  bps)


A port is ‘attached’ to a physical interface, like a hardware TNC, or virtual interface, as in soundmodem using a command called kissattach. kissattach is run by the root user and has the syntax kissattach tty port - in this case it’s

sudo kissattach /dev/soundmodem0 radio

for Soundmodem, and for Direwolf:

sudo kissattach /tmp/kisstnc radio

This provides us a rather useful functionality - you can run multiple ports on the same system. I could have a 1200bd VHF and 9600bd UHF port, kissattached to /dev/soundmodem1 and /dev/ttyUSB1 respectively. This would provide 2 RF points of access to the same packet node!

Note how I’m using radio as my port and assigning it the callsign MM3ZRZ-5 at 1200baud, max packet length of 255 (bytes) and window of 2, whatever that last one means.


Ax25d distributes data from incoming axports and spawns a program to receive it, analogous to inetd or xinetd.

Note how it works: all requests to MM3ZRZ-5 via interface radio - here is how to deal with them. No callsign, ignore, default case, send to uronode.

The man page for ax25d.conf is an enlightening read and describes how it functions in great detail. It’s worth a read if you’re going to set up a complicated system - it can do much more than I have mine doing. For example, you can use it to lock out specific callsigns from using the system, or create a whitelist of callsigns who can get access. You can also push specific calls to different programs.

# /etc/ax25/ax25d.conf
# ax25d Configuration File.
# AX.25 Ports begin with a '['.
[MM3ZRZ-5 VIA radio]
NOCALL   * * * * * *  L
default  * * * * * *  - root  /usr/local/sbin/uronode uronode
# Uncomment to enable netrom
#parameters 1    10  *  *  *   *   *
#NOCALL     *     *  *  *  *   *   L
#default    *     *  *  *  *   *   0        root /usr/sbin/node node

ax25d is run by root using /usr/sbin/ax25d or, alternatively, sudo ax25d.


Avahi tends to spam the port with info, so I disabled it. Stopping the publishing function might be neater, check the ubuntuhams resource to get a better idea of that.


If you don’t intend to run the system as a node, you can effectively ignore this bit.

If you don’t know what a node is, it’s essentially a frontend for using the computer remotely. It presents a simplified interface that can be transmitted and controlled over a remote, low speed, high latency link while maintaining usability. It opens up commands and functions of the remote computer and is generally quite efficient on the channel, compared to say, ssh.

Uronode had a couple of config files to sort out There’s quite a lot going on in uronode.conf - the timeouts and the callsign replacement bits are important to get it up and running as a basic starting point. I’ve got an amprnet allocation, so I can fill that out in line with what was in the soundmodem config.

There’s lots of advanced things going on here - the aliases for telnetting Callbook, Convers etc are all configurable, as is the passthrough for external commands like netstat. Thats really cool. There are also a pile of netrom things that I’ll look into later.

# /etc/ax25/uronode.conf - URONode example configuration file   12-8-13
# see uronode.conf(5)

# Idle timeout (seconds).
# This is how long we hold onto a dead link. 0 disables (this is NOT
# recommended! Time is in seconds.

IdleTimeout	900

# Timeout when gatewaying (seconds).
# This (in seconds) is a keep-alive for dead connects out of the node.

ConnTimeout	600

# Visible hostname. Will be shown at telnet login.
# set this to your hostname.

HostName	<callsign>

# SysOp email address
# Set this to your email address - preferred to use an email.

Email <>

# "Local" network.
# This is your local amprnet subnet in full. Do NOT use!

LocalNet	44.x.x.x/32

# Command aliases. See uronode.conf(5) for the meaning of the uppercase
# letters in the name of the alias. Examples below:

Alias		CAllbook "telnet %{3:} 2000 %1 s"
Alias		CONVers  "telnet %{2:} 3600 \"/n %u %{1:1}\""
Alias		DXCluster "connect dxuro s"
Alias		WX	"telnet %{3:} %1 s"

# Hidden ports.
# List interfaces you wish not to display. Not suggested.

#HiddenPorts	inet

# External commands. See uronode.conf(5) for the meaning of the uppercase
# letters in the name of the extcmd.
# Flags:	1	Run command through pipe
#		2	Reconnected flag
#		3	Run through pipe and reconnect
ExtCmd		MAil	1	root	/usr/sbin/axmail axmail %u
ExtCmd		NEstat	1	nobody	/bin/netstat netstat --inet

# Node ID.
# This displays before all output texts when the user connects into
# your node via NetRom. Set to "" to leave blank.
# Note: This -must- be defined or will display as "(null)". A space
# is hardcoded in. Example: UROHUB:N1URO-2 do NOT add the bracket
# afterwards "}" this is predefined in URONode.

# Ax25/Flex ID.
# This displays before some strings and at logout to the end user when
# they connect in via ax25 as defined in your ax25d.conf file. If
# you don't define this "(null)" will be presented to the end user. Its
# suggested you take this from your ax25d config which either faces a
# flexnet system OR your 2-meter user interface. Note: do NOT make this
# ssid the same as your NetRom SSID here or in ax25d.conf.

FlexId		<CALLSIGN>-2

# Netrom port name. This port is used for outgoing netrom connects.

NrPort		nr0

# Syslog Logging level - suggest leaving this at 3 for debugging. 0
# halts logging. Best for Pi on SD card is 0.

LogLevel	0

# The default escape character (CTRL-T)
EscapeChar      ^T

Uronode has uronode.motd, uronode.perms and more for further configuration. Go explore - if you’re setting up a node it’s worth taking the time to produce a good quality product.

Running the full stack

All you need to do is start soundmodem or Direwolf, configure an axport, kissattach it, configure and start ax25d, prepare your services and optionally start mheardd.

I’ve brought this together in a script below.

#Shut up avahi, no one likes you.
#systemctl stop avahi.service
#systemctl disable avahi.service

# start ax25 with the soundmodem driver using the port
# defined in /etc/ax25/axports
/usr/sbin/soundmodem /etc/ax25/soundmodem.conf -M >/dev/null 2>/dev/null&
#make soundmodem usable by users
chmod 666 /dev/soundmodem0
#alternatively, start ax25 with direwolf
#direwolf -t 0 -p -c /etc/direwolf.conf&
sleep 1
#attach soundmodem device to axport
/usr/sbin/kissattach /dev/soundmodem0 radio
#attach direwolf device to axport
#/usr/sbin/kissattach /tmp/kisstnc radio

# listen for stations heard
sleep 1

# listen for various incoming connections like PMS, node, etc.
sleep 1

Running the partial stack

If you don’t plan on dealing with incoming connections to go to a node or anything, you can run a cut down stack.

All you need to run is soundmodem or direwolf, configure an axport and kissattach. On my home station, I run as root

# start ax25 with the soundmodem driver using the port
# defined in /etc/ax25/axports
/usr/sbin/soundmodem /etc/ax25/soundmodem.conf -M >/dev/null 2>/dev/null&
#make soundmodem usable by users
chmod 666 /dev/soundmodem0
sleep 1
#attach soundmodem device to axport
/usr/sbin/kissattach /dev/soundmodem0 radio
# listen for stations heard

I like to run mheardd as it collects stats on what is happening around my station, they’re quite nice to look at.

Making Packet Calls

To connect to another packet station run

axcall port callsign

This means, to connect from another station to the node above, it’s

axcall radio mm3zrz-5

This initiates a direct, point to point connection from your station to mm3zrz-5. mm3zrz-5 is what we have just configured - if you come in on the radio axport, then you’ll get uronode. axcall enables you to define relay stations - if you know the best path to the remote node, you can be repeated by them to get to it. If you don’t know the best route, the node might have a “recently heard” option on it.

I’ll document my netrom adventures soon - this alleviates some of the routing issue by implementing beacons, routing and aliases.


Most of my config understanding came from here - it was invaluable

This post was edited to include Direwolf on 2017-02-19 after experimentation! I have also split out the ‘partial’ and ‘full’ stack to make setting up a home station easier