How to build a Raspberry Pi APRS Tracker using Direwolf

🗓 Posted


This is a follow up to my last post about getting my Amateur Radio Basic Qualification (with Honours) and being interested in APRS. Since then, I’ve made some progress in my ham radio journey and setup my own APRS tracker that I run in my truck.

What lies beyond is mostly just a brain dump of notes I made over the course of putting this project together so that in the future I can refer back to it when I forget some things. Hopefully it helps you setup your own APRS tracker using some open-source software called Direwolf and some other relatively inexpensive hardware.

It’s worth noting that this post does not cover any of the hardware setup required with a VHF radio, antenna, power requirements, etc.; In the future I may put together a part two post outlining my setup and how I have everything configured.


There are some things you need to get started:

  • A Raspberry Pi 3 B+ (or newer, it’s what I had on hand). You may be able to accomplish this with a lower-powered Raspberry Pi device, like a Zero W, but your mileage may vary.
  • A Baofeng UV-5R or other VHF (2 meter, 144MHz band) radio
  • A DigiRig v1.9 all-in-one audio device to receive and transmit audio to and from your radio.
    • Alternatibely you could build your own with a CM108-based audio device. The upside of using the DigiRig is that it can also control some radios using the CAT interface over a serial connection (I won’t get into how that works in this post).
      • 3.5mm headphone/microphone audo splitter to get the audio and microphone into the Raspberry Pi if building your own cable.
      • A PTT-control circuit for the Raspberry Pi to be able to trigger PTT if you don’t go with the DigiRig above. It is possible to build your own using a 5V optocoupler which I have done with good success.
  • USB GPS device — practically any USB GPS device should work but this is the one I purchased and I can confirm works for this project (with a caveat).

Install OS Dependencies #

sudo apt-get install -y vim git gcc gpsd gpsd-clients g++ make cmake ntp screen \
  avahi-daemon libasound2-dev libudev-dev libavahi-client-dev libgps-dev

GPS config (for Direwolf) #

Create /etc/udev/rules.d/49-usb-gps.rules and add:

# Force USB to specific `tty` if more than one serial device present on system (GPS and DigiRig compete)
KERNEL=="ttyACM[0-9]*", SUBSYSTEM=="tty", ATTRS{idVendor}=="1546", ATTRS{idProduct}=="01a7", SYMLINK="ttyGPS"

Edit /etc/default/gpsd to add:


After configuring the GPS dependencies, we need to initialize the service with:

sudo systemctl enable gpsd
sudo systemctl start gpsd

Now’s a good time to upgrade gpsd to a version without a very worrisome bug.

To ensure we have accurate time on the device, as it will unlikely be connected to a time server over a network, we can run sudo vim /etc/ntp.conf to edit the NTP service config file to pull extremely accurate time from the GPS receiver instead:

server 4
fudge time1 0.340 refid GPS
server prefer
fudge refid GPS1

Install Direwolf #

cd ~
git clone && cd direwolf
git checkout dev
mkdir build && cd build
cmake .. && make -j4 && sudo make install && make install-conf

Modify the script and append -l /var/log/direwolf to the commandline arguments variable.

DigiRig config (for Direwolf) #

Next, create a shortcut for the Digirig USB device by creating /etc/udev/rules.d/85-usb-digirig.rules:

SUBSYSTEM=="tty", GROUP="dialout", MODE="0660", ATTRS{product}=="CP2102N USB to UART Bridge Controller", SYMLINK+="ttyDigiRig"

Don’t forget to run:

sudo chmod 0644 /etc/udev/rules.d/85-usb-digirig.rules && sudo udevadm control --reload-rules && sudo reboot

Boot config (specific for rPi 3) #

Edit /boot/config.txt to modify the boot-time configuration for the DigiRig and GPS to play nice with USB stack:

dtoverlay=dwc2 # Add this below previous dtoverlay for gpio pins, enables new usb stack

Sound (Alsamixer) config #

You may have to add the user you’re using for this setup to the audio and dialout groups in order to work with audio and serial devices, so YMMV here:

usermod -a -G audio <USERNAME>
usermod -a -G dialout <USERNAME>



then press F6 to show all devices. Select the the DigiRig sound device. Press F5 to show all options, then set the sound to 10, unmute the Mic and set to 10 as well, then set the Capture to 10. Disable the Automatic Gain by pressing m when highlighted. Esc to exit, then store the settings with

alsactl store

The above settings are only important when using an un-attenuated homebrew cable.

RaspAP config #

Install and configu raspAP

sudo raspi-config # Set Localisation for WiFi country

curl -sL | bash

During the install of RaspAP, respond Y to everything except VPN-related questions.

Once RaspAP installed, Login to the UI with admin/secret, then change:

  • Toggle Dark mode in the top bar
  • System > Advanced tab > Web server port to 8080, Save, go back to tab and restart lighttp
  • Authentication > Update password
  • Hotspot > Basic tab > SSID, change to preferred name
  • Hotspot > Basic tab > Wireless Mode, change to “802.11n”
  • Hotspot > Security tab > Change PSK to preferred value
  • Hotspot > Advanced tab > Toggle “Hide SSID in broadcast” to on
  • Hotspot > Advanced tab > Change Maximum number of clients to 5

Direwolf config #

Empty the /home/aprs/direwolf.conf file and replace it with the contents below. Remember to replace the callsign with your own!

ADEVICE  plughw:1,0
MODEM 1200
PTT /dev/ttyDigiRig RTS

DIGIPEAT 0 0 ^WIDE[3-7]-[1-7]$|^TEST$ ^WIDE[12]-[12]$ TRACE

# Enable GPS beaconing
SMARTBEACONING  60 2:00  5 15:00  0:15 30 255

To auto-run on boot, add this to crontab -e:

* * * * *  $HOME/  >/dev/null  2>&1

Ublox GPS caveat #

If using a UBlox-based GPS puck, modify the script and append the following before Direwolf is started. It will reset the GPS device state prior to starting Direwolf.

ubxtool -p RESET

The reason for this is because of an issue with the UBlox-based GPS puck I used not updating past the first location lock. This issue took me days to diagnose and pin down a bandaid fix for. It is optional to include it in the command above here, so if you’re not using a UBlox-based GPS device your mileage may vary.

Hardening #

Disable bluetooth #

Let’s disable the Bluetooth modem as it’s not needed for our purposes. Add the following to the /boot/config.txt:

# Disable Bluetooth

then disable any bluetooth-related services and uninstall packages with:

sudo systemctl disable hciuart.service
sudo systemctl disable bluealsa.service
sudo systemctl disable bluetooth.service
sudo apt-get purge bluez -y
sudo apt-get autoremove -y

Firewall #

Setup a simple firewall to keep people from abusing connecting to the rPi wireless network. There is a lot more that could be done here but this is not a linux server ssh hardening article.

sudo apt-get install -y ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw limit 2022/tcp comment 'SSH port rate limit'
sudo ufw limit 8001/tcp comment 'KISS port for Direwolf'
sudo ufw logging on
sudo ufw enable

Don’t forget to disable IPV6 in UFW, change IPV6=yes to IPV6=no:

sudo vim /etc/default/ufw
sudo ufw disable && sudo ufw enable

Disable the swapfile #

We want to write as little to the SD card as possible, and 4GB of memory is more than enough to run things without swapping.

sudo systemctl stop dphys-swapfile
sudo systemctl disable dphys-swapfile
sudo apt-get purge dphys-swapfile

Watchdog #

It’s advisable to protect against random lockups and issues using the hardware “watchdog” built into the Raspberry Pi. This is a piece of hardware built into the SoC that continually counts down a counter — if it ever reaches zero, a hard reset of the system is generated.

There is a watchdog daemon that “feeds” the watchdog by reseting the counter periodically. Run the following enable the daemon:

sudo apt-get install watchdog

Modify /etc/watchdog to set the device line as follows:

watchdog-device = /dev/watchdog

Edit the /etc/systemd/system/watchdog.service file to include autostart by copying as follows:

sudo cp /lib/systemd/system/watchdog.service /etc/systemd/system/watchdog.service

Then edit the file to add this line:


Edit /etc/sysctl.conf to add the line:


Which forces a reboot 10 seconds after a kernel panic.

Resources #

Here’s a list of some of the resources I used to compile this information: