Installation

Get graywolf running on your system

Install the Package

Download the .deb package for your architecture (amd64 or arm64) from the GitHub Releases page, then install it:

sudo apt install ./graywolf_*.deb

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

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.

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