Before this:Connecting an SDRServices with systemd
Install GopherTrunk on a Pi
Key takeaways
Everything converges: GopherTrunk ships as a single ARM binary — match it to
uname -m (arm64 for aarch64), drop it in /usr/local/bin, and it runs
with nothing else to install. First run goes foreground over SSH with a
minimal config, so you can watch the daemon find the SDR and lock a control
channel; the interface is the web console on your LAN. Once decoding works,
promote it to the systemd service from Unit 3 — and the moment
enable --now returns, you own a headless scanner that survives reboots.
Unit 6 begins the build the module promised. The board is flashed, hardened, networked; the dongle streams clean. This lesson adds the decoder and gets to the first decoded call — deliberately in the foreground first, service second, so every layer is proven before it’s automated.
Which binary, and where does it go?
The Go-language payoff: GopherTrunk is one static binary — no runtime, no dependency tree. Two facts pick your download from the Linux install guide: it must be Linux, and it must match your ARM flavour (ARM and the SoC):
$ uname -m
aarch64 # → the arm64 Linux build
Grab the matching asset from the GopherTrunk releases page and unpack it on the Pi (substitute the current version number):
$ curl -LO https://github.com/MattCheramie/GopherTrunk/releases/download/<version>/gophertrunk-<version>-linux-arm64.tar.gz
$ tar xzf gophertrunk-<version>-linux-arm64.tar.gz
$ sudo install -m 0755 gophertrunk /usr/local/bin/
$ gophertrunk version
gophertrunk version printing a version string proves architecture and binary in
one stroke — exec format error here means the wrong architecture was
downloaded.
What does a first config look like?
Start minimal: one system, its control channel, your dongle. Create
/etc/gophertrunk/config.yaml with the shape (values from your local system —
found via the Scanning module’s
database-and-discovery methods):
sdr:
driver: rtlsdr
systems:
- name: county-p25
protocol: p25
control_channels: [853.9625e6]
recordings:
dir: /var/lib/gophertrunk/recordings
Config vocabulary — protocols, talkgroups, recording options — is the install guide’s territory; the embedded-lesson point is narrower: start with the smallest config that can possibly decode, so the first run has the fewest moving parts.
Why run in the foreground first?
Resist the urge to go straight to the service. In your SSH session (inside tmux, as always):
$ gophertrunk daemon -config /etc/gophertrunk/config.yaml
The log streams to your terminal — and narrates the whole chain you’ve built:
the SDR opening (Unit 4’s driver work), tuning, control-channel hunting, then
the lock, and decoded grants scrolling by as calls happen. Now open the web
console from any browser in the house — http://scanner.local:8080 (or the
pinned IP from Networking your board)
— and watch call activity live. When a recording lands, listen to it in the
console: that is the first decoded call on your own SBC hardware.
Foreground-first pays off precisely when something’s wrong: no control-channel
lock (antenna, frequency list, signal — the
RF-side checklist), SDR won’t open (back to
Connecting an SDR — is rtl_test still
clean?), or CPU pinned (next lesson’s tuning). Each failure is visible at the
moment it happens, in a log you’re already watching.
How does it become an appliance?
Promote the proven foreground command into the Unit 3 pattern — this is exactly
the unit file Services with systemd
wrote, ExecStart now pointing at a decoder you’ve watched work:
$ sudo adduser --system --group gophertrunk
$ sudo mkdir -p /var/lib/gophertrunk/recordings
$ sudo chown -R gophertrunk:gophertrunk /var/lib/gophertrunk /etc/gophertrunk
$ sudo systemctl enable --now gophertrunk
$ journalctl -u gophertrunk -f # same narration, now in the journal
Then the graduation exam — the power-cycle test from
Watchdogs & recovery: sudo
reboot, wait two minutes, open the console. Lock reacquired, calls flowing,
nobody logged in? Then you have an appliance, not a program. Add the daemon’s
vitals to your monitoring script
(service active + a recording landed recently) and Unit 5’s machinery is
guarding the new workload.
Rule of thumb: foreground until it decodes, service once it’s proven, reboot test before you call it done. Never automate a thing you haven’t watched work.
Quick check: why run the daemon in the foreground before enabling the systemd service?
Recap
- GopherTrunk is a single static ARM binary: match
uname -m(arm64 foraarch64), install to/usr/local/bin, verify withgophertrunk version. - Start from the smallest config that can decode — one system, one control channel, your dongle.
- Foreground first over SSH: watch the SDR open and the control channel lock; the web console on the LAN is the interface — the Pi stays headless.
- Promote to the systemd service (dedicated user,
enable --now) only once decoding is proven, then pass the reboot test. - Wire the new workload into Unit 5’s monitoring — the appliance now guards itself.
Next up: Tuning for small CPUs.
Frequently asked questions
Does GopherTrunk run on a Raspberry Pi?
Yes — GopherTrunk is a single Go binary and ships ARM Linux builds that run on Raspberry Pi OS and similar distributions. It runs headless, with its web console served over the network, which fits the Pi perfectly. A modern Pi decodes a trunked system comfortably; the following lessons cover fitting the workload to smaller boards.
Which GopherTrunk download do I need for a Pi?
The Linux ARM build matching your OS word size: on a 64-bit OS (uname -m reports aarch64) take the arm64 build; on a 32-bit OS (armv7l) take the 32-bit ARM build. Because it’s a single static binary there is nothing else to install — copy it into /usr/local/bin, make it executable, and it runs.
Do I need a monitor on the Pi to use GopherTrunk?
No. GopherTrunk is designed to run headless — you install and control it over SSH, and its interface is a web console you open from any browser on your network. The Pi itself never needs a display, keyboard, or desktop environment.