Installation
Get graywolf running on your system
Determine your architecture
Many users run graywolf on Raspberry Pi hardware. Graywolf works on every Raspberry Pi, all the way back to the original Model B, including the Pi Zero models, but you need to install the right build of graywolf for your architecture.
Log in to your Raspberry Pi, and run:
dpkg --print-architecture
Download the right package
Go to the GitHub Releases
page and find the latest version. Use the output of the
dpkg --print-architecture command to tell you which file
you need. For example, if the output shows "armhf", then you would
use the "graywolf_0.14.10_armhf.deb" file (as of this writing 0.14.10 is the latest
version).
From your web browser, right click on the proper file and select "Copy Link Address". The exact name may vary depending on which browser you use. While logged in to your Raspberry Pi, type:
$ cd /tmp
$ wget
and then type a space, and paste the link you just copied from your browser. You should have something that looks like this:
$ wget https://github.com/chrissnell/graywolf/releases/download/v0.14.10/graywolf_0.14.10_armhf.deb
The URL you see may differ as newer versions of graywolf are released. When you press return,
wget will download the installation file to your Raspberry Pi.
If you get an error message about wget not found or wget not installed, you can easily install it:
sudo apt install wget
Then rerun the wget command with the url again.
Install the Package
With the right package downloaded, installation is easy:
sudo apt install ./graywolf_*.deb
The ./ before the package name is important. It tells apt
to install the local file instead of looking for graywolf in the package index.
The package installs both binaries (/usr/bin/graywolf
and /usr/bin/graywolf-modem), creates a
graywolf system user with audio and
dialout group membership, installs a hardened systemd
unit, and enables the service.
Start the Service
sudo systemctl start graywolf
The service is already enabled at boot. Check that it’s running:
sudo systemctl status graywolf
Install the Package
Download the .rpm package for your architecture
from the
GitHub Releases
page, then install it:
sudo dnf install ./graywolf_*.rpm
The package installs both binaries, creates the
graywolf system user, and installs the systemd unit.
Start the Service
sudo systemctl enable --now graywolf
Install from AUR
# With an AUR helper (e.g., yay or paru)
yay -S graywolf-aprs
Or build manually:
git clone https://aur.archlinux.org/graywolf-aprs.git
cd graywolf-aprs
makepkg -si
The PKGBUILD builds both the Rust modem and Go binary from source,
installs them to /usr/bin, and installs the systemd unit.
Start the Service
sudo systemctl enable --now graywolf-aprs
Run the Installer
Download the Windows installer
(graywolf_<version>_Windows_x86_64.exe) from the
GitHub Releases
page and run it. Administrator rights are required so the installer
can write to C:\Program Files and register an
Add/Remove Programs entry. 64-bit Windows only.
The installer places:
graywolf.exeandgraywolf-modem.exeunderC:\Program Files\Graywolf\- The SQLite databases under
C:\ProgramData\Graywolf\(preserved across upgrades) - A Start Menu shortcut that launches graywolf with the correct flags
Start Graywolf
Launch Graywolf from the Start Menu. A console
window opens and the web UI binds to
127.0.0.1:8080.
graywolf.exe is a console application, not a
Windows service. Closing the console window stops graywolf.
See Running as a Service below to run it in the
background at boot.
Running as a Service (optional)
To run graywolf in the background and start it at boot, wrap it with NSSM:
choco install nssm
nssm install Graywolf "C:\Program Files\Graywolf\graywolf.exe" `
-config "C:\ProgramData\Graywolf\graywolf.db" `
-history-db "C:\ProgramData\Graywolf\graywolf-history.db" `
-modem "C:\Program Files\Graywolf\graywolf-modem.exe" `
-http 127.0.0.1:8080
nssm set Graywolf Start SERVICE_AUTO_START
nssm start Graywolf
Full instructions, including sc.exe as an
alternative, live in
packaging/nsis/RUNNING-AS-A-SERVICE.md.
Setting the Admin Password
The easiest way is through the web interface. With the service
running, browse to http://localhost:8080. On first
run — when no users exist yet — the login screen shows
a Create Admin Account form. Enter a username and
password there and you’re done; no command line needed.
If you prefer the command line, open a command prompt (or
PowerShell) and run the command below. The auth
subcommand must come first, before the -config
flag:
"C:\Program Files\Graywolf\graywolf.exe" auth set-password --user admin ^
-config "C:\ProgramData\Graywolf\graywolf.db"
You’ll be prompted to enter the password. The path is the same config database the service runs with (see the NSSM command above).
Container Image
ghcr.io/chrissnell/graywolf:latest
Docker Run
docker run -d \
--name graywolf \
--restart unless-stopped \
--device /dev/snd \
-p 8080:8080/tcp \
-v graywolf-data:/data \
ghcr.io/chrissnell/graywolf:latest \
-config /data/graywolf.db -http 0.0.0.0:8080
Audio device passthrough (--device /dev/snd) is
required for the software modem to access your sound card.
For serial PTT or GPS, pass the serial device as well
(e.g., --device /dev/ttyUSB0).
Docker Compose
services:
graywolf:
image: ghcr.io/chrissnell/graywolf:latest
container_name: graywolf
restart: unless-stopped
devices:
- /dev/snd:/dev/snd
ports:
- "8080:8080/tcp"
volumes:
- graywolf-data:/data
command: ["-config", "/data/graywolf.db", "-http", "0.0.0.0:8080"]
volumes:
graywolf-data:
docker compose up -d
Exposing Additional Ports
If you plan to use KISS TCP or AGWPE, expose those ports as well:
ports:
- "8080:8080/tcp" # Web UI
- "6700:6700/tcp" # KISS TCP
- "8000:8000/tcp" # AGWPE
Requirements
- Rust toolchain (stable, via rustup)
- Go 1.22+
- Node.js 22+ and npm (for the web UI)
- GNU Make
- ALSA development headers (
libasound2-devon Debian/Ubuntu)
Build
git clone https://github.com/chrissnell/graywolf.git
cd graywolf
# Build everything (Rust modem + Svelte UI + Go binary)
make graywolf
The binaries are written to bin/graywolf and
bin/graywolf-modem.
Cross-Compiling for ARM
To build for Raspberry Pi (aarch64), use cross:
cargo install cross
cross build --release --target aarch64-unknown-linux-gnu \
-p graywolf-modem
Install System-Wide
The repository includes a systemd unit, postinstall script, and
preremove script under packaging/. To install manually
from a source build:
# Install binaries
sudo install -m 755 bin/graywolf /usr/bin/graywolf
sudo install -m 755 bin/graywolf-modem /usr/bin/graywolf-modem
# Install the systemd unit
sudo install -m 644 packaging/systemd/graywolf.service \
/etc/systemd/system/graywolf.service
# Run the postinstall script (creates user, enables service)
sudo packaging/scripts/postinstall.sh
Then start the service:
sudo systemctl start graywolf
Makefile Targets
| Target | Description |
|---|---|
make all | Full release build (Rust + Svelte + Go) |
make release | Build Rust modem with native CPU optimizations |
make web | Build the Svelte web UI |
make graywolf | Build Go binary (triggers modem + web builds) |
make test | Run Rust tests (cargo test) |
make go-test | Run Go tests with race detector |
make go-fuzz | Run fuzz tests (AX.25, APRS parsers) |
make clean | Clean all build artifacts |
Connect to the Web UI
Once the service is running, open a browser and navigate to:
http://<your-ip>:8080
If you’re on the same machine, use
http://localhost:8080. The web UI is where you’ll
configure audio devices, radio channels, beacons, digipeater rules,
and everything else.
If you are on a Linux machine and you aren't sure what IP address to use, type:
hostname -I
into a shell prompt on the Linux machine running graywolf and pick the first IP address from the list.
Set a Password
Before exposing the web UI on your network, set an admin password:
sudo graywolf auth set-password --user admin
If you installed from a package and the service is running, you
need to specify the database path explicitly:
sudo graywolf auth set-password --user admin -config /var/lib/graywolf/graywolf.db
What the Packages Install
| File | Purpose |
|---|---|
/usr/bin/graywolf |
Go application server |
/usr/bin/graywolf-modem |
Rust DSP modem |
graywolf.service |
Hardened systemd unit (filesystem, kernel, and network lockdown) |
/var/lib/graywolf/graywolf.db |
SQLite configuration database (created on first start) |
The postinstall script creates a graywolf system user
with membership in the audio group (sound card access)
and dialout group (serial port access for PTT and GPS).
Command-Line Reference
| Flag | Default | Description |
|---|---|---|
-config PATH |
./graywolf.db |
Path to the SQLite configuration database |
-modem PATH |
auto-discover | Path to the graywolf-modem binary |
-http ADDR:PORT |
127.0.0.1:8080 |
HTTP listen address for the web UI and API |
-shutdown-timeout |
10s |
Maximum graceful shutdown duration |
-flac FILE |
— | Override audio input with a FLAC file (for testing) |
-debug |
false |
Enable debug-level logging |
Subcommands
version |
Print the version string (v0.14.10-abc1234) |
auth set-password --user NAME |
Set or change the web UI password for a user |
Verify It’s Working
Check the service logs to confirm graywolf started successfully:
journalctl -u graywolf -f
You should see the modem start, audio devices initialize, and the HTTP server bind. If you see errors about missing audio devices, that’s expected — you haven’t configured any yet. Head to Audio Devices to set up your first radio channel.