A modern APRS-IS server written in Go.
We are still under development. Welcome to contribute!
Gopher image by Ian Xia, licensed under Creative Commons 4.0 Attribution licence.
- Client ports: TCP full-feed and IGate (client-defined filter) ports, with optional TLS (including client-certificate login) and SCTP (Linux).
- Packet submission: TCP, UDP submit (qAU), and HTTP POST (qAC).
- Uplink: TCP uplink with round-robin failover and exponential-backoff reconnect.
- Core peers: UDP and TCP server-to-server links (per-peer transport, mixable within a group) with aprsc-compatible loop prevention.
- Q construct: full qAC/qAS/qAR/qAr/qAo/qAO/qAU/qAX/qAI/qAZ handling with loop detection.
- Filters: the 14 standard APRS-IS filter types (
a b d e f g m o p q r s t u), including position-awarem/,f/and rangedt/, plus runtime#filterupdates. - IGate routing: messages to heard stations are delivered regardless of filter, and a correspondent's next position is forwarded as a courtesy.
- Parser: positions (uncompressed/compressed), Mic-E, objects, items, messages, weather, telemetry, status, queries, NMEA and third-party traffic.
- Connection health: TCP keepalive on client and uplink sockets so dead idle peers are detected and dropped.
- Web status page: a Nuxt SSG dashboard (ElementPlus + Tailwind), embedded into the binary and served from memory — single-binary deployment.
- Stats: lock-free atomic counters, per-second rates and 30-day time series.
The reusable APRS algorithms (parser, filter, qConstruct, passcode, distance, base91,
client) live in the companion module aprsutils;
server-only logic (listeners, links, stats, web) lives here.
The web UI is generated as static files and embedded via //go:embed all:web/dist, so the
frontend must be built before the Go binary. A Makefile enforces this order:
# Build everything (installs web deps, generates the UI, builds the binary)
make build
# Or step by step:
cd web && pnpm install && pnpm generate # produces web/dist
cd .. && go build . # embeds web/dist and compilesRequirements: Go 1.26+, Node.js + pnpm (for the web UI).
Other Makefile targets: make run, make test, make test-race, make vet, make clean.
./aprsgoOn first run a default config.yaml is written next to the binary. Edit it and restart
(or send SIGHUP to reload configuration). The web status page is served on the configured
status port (default 14501).
config.yaml (excerpt):
server:
id: "N0CALL" # your server callsign
passcode: "0" # passcode for the server id
status:
host: "[::]"
port: 14501 # web status + HTTP submit
listeners: # client/submit ports (tcp or udp)
- { name: "Full Feed", mode: "fullfeed", protocol: "tcp", host: "[::]", port: 10152, visible: "hidden" }
- { name: "Client-Defined Filters", mode: "igate", protocol: "tcp", host: "[::]", port: 14580 }
uplinks: # upstream servers (tcp)
- { name: "Core Rotate", mode: "full", protocol: "tcp", host: "rotate.aprs.net", port: 10152 }
peer: # core peers (optional; per-peer udp/tcp)
host: "[::]"
port: 0
peers: []TLS with client-certificate login and UDP/TCP core peers are configured in the
generated config.yaml (see the commented examples there).
| Method | Path | Description |
|---|---|---|
| GET | /api/ping |
Health check |
| GET | /api/status |
Server / uplink / listeners / clients |
| GET | /api/stats |
Time-series statistics |
| POST | / /api/submit |
APRS packet submit (octet-stream) |
| GET | / |
Web status dashboard |