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.exe and graywolf-modem.exe under C:\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

docker-compose.yml
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-dev on 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

TargetDescription
make allFull release build (Rust + Svelte + Go)
make releaseBuild Rust modem with native CPU optimizations
make webBuild the Svelte web UI
make graywolfBuild Go binary (triggers modem + web builds)
make testRun Rust tests (cargo test)
make go-testRun Go tests with race detector
make go-fuzzRun fuzz tests (AX.25, APRS parsers)
make cleanClean 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

FilePurpose
/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

FlagDefaultDescription
-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.