Skip to content
N4LLZ

APRS-IS: Servers, Filters, and Gateways

The internet side of APRS in full: the login handshake, q constructs and how they record provenance, the complete server-side filter language, and the rules an IGate must follow.

APRSAdvanced14 minUpdated

APRS-IS is the internet backbone that makes APRS global. It is a mesh of servers relaying a single worldwide stream of packets over plain TCP, in the TNC2 text format, one frame per line.

It is also where most APRS misbehaviour happens, because the internet side has no propagation limits to keep bad configuration local. A misconfigured RF digipeater annoys a county. A misconfigured IGate can annoy the planet.

Connecting

APRS-IS speaks a line-oriented text protocol. Connect a TCP socket, send a login line, and read lines forever.

user N0CALL pass 12345 vers myclient 1.0 filter r/36.16/-86.78/50

The fields:

  • user — your call sign, with SSID if you want one.
  • pass — your passcode. Not a password you choose. It is a number deterministically derived from your call sign by a published algorithm, which means it is not a security measure — it is a speed bump confirming you have a call sign at all. Everyone’s passcode for a given call is the same number.
  • vers — software name and version. Required; servers reject clients that do not identify themselves.
  • filter — optional, and covered below.

Send -1 as the passcode for receive-only access. The server will accept the connection and stream packets, but will refuse anything you try to inject. If you are building a display, a logger, or a receive-only IGate, use -1 — there is no reason to authenticate for read access, and doing so risks accidentally becoming a transmitter.

The server replies with a comment line beginning #, then a verification line:

# aprsc 2.1.19-g730c5c0
# logresp N0CALL verified, server T2NUENGLD

verified means the passcode matched. unverified means it did not, and your packets will be dropped rather than gated.

Ports

Servers such as rotate.aprs2.net listen on several ports, and the choice matters:

Port Purpose
14580 Filtered feed. The normal choice — you specify a filter and receive only matching traffic.
10152 Full feed, all traffic worldwide. Firehose.
8080 HTTP POST submit-only, for injecting packets without a persistent socket.
20152 Full feed, binary/raw variants on some servers.

Use 14580 with a filter. The full feed is thousands of packets per second and there is rarely a reason for a client to drink from it.

q constructs

Every packet that passes through APRS-IS gets a q construct appended to its digipeater path — a three-character token beginning with q that records how the packet entered the internet. This is the provenance mechanism, and it is what prevents loops between RF and the internet.

N0CALL-9>APRS,WIDE1-1,qAR,N0GATE-10:!3554.12N/08646.50W>
                            └┬─┘ └───┬───┘
                        construct   the station that gated it

The ones you will actually see:

Construct Meaning
qAC Received from a client that logged in with a verified passcode, directly on a server port.
qAR Gated from RF by the station that follows. The most common construct on the network.
qAo Gated from RF by a station that does not gate internet traffic back to RF.
qAS Received from a server-to-server link.
qAX Received from an unverified client. These packets are not relayed onward to RF.
qAU Received via UDP submit.
qAI Injected directly by the server itself.

The practical rule: qAR says a real radio heard this packet, and names the receiver. qAC says it arrived over the internet and never touched RF. A gateway deciding whether to transmit something must look at the q construct, because gating an internet-only packet back to RF injects traffic that was never on the air in the first place.

The filter language

Filters are the reason port 14580 is usable. You set one at login, or change it at any time by sending:

#filter r/36.16/-86.78/50 t/poimqstunw

Filters are additive — a packet matching any one of them passes. Prefix a filter with - to make it a rejection.

Range and area

r/lat/lon/dist        within dist km of a point (signed decimal degrees)
m/dist                within dist km of MY last reported position
f/call/dist           within dist km of another station's position
a/latN/lonW/latS/lonE inside a bounding box

r/ is the workhorse. r/36.16/-86.78/100 gives you everything within 100 km of a point — the natural filter for a local map or a regional IGate.

Note that r/ and f/ only match packets that have a position. A status report or a message has no coordinates and will not pass a range filter, which is a common surprise.

By station

p/aa/bb/cc      source call STARTS WITH any of these prefixes
b/call1/call2   budlist — exact call match, SSID significant
o/obj1/obj2     objects and items by name
d/digi1/digi2   packets that were digipeated by these stations
e/call1/call2   packets gated to APRS-IS by these entry stations
g/call1/call2   messages addressed to these stations
u/unproto1      packets with these destination identifiers (tocalls)

p/ is prefix-based, so p/K passes every US call starting with K — usually far too broad. b/ is exact, and the SSID is part of the match: b/N0CALL-9 will not match N0CALL-7.

Several of these support wildcards with *.

By content

t/poimqstunw    packet TYPE filter
s/pri/alt/over  symbol filter
q/con/ana       q construct filter

The type letters:

Letter Type
p Position
o Object
i Item
m Message
q Query
s Status
t Telemetry
u User-defined
n NWS weather and weather objects
w Weather
c CWOP
* Everything

So t/w gives you weather reports only — which, if you are building a weather display, is dramatically more efficient than filtering a full feed client-side.

s/pri/alt/over filters by symbol: s/_ passes weather station symbols from the primary table. Combined as t/w s/_, you get a clean weather-only stream.

Filter first, parse second

Every packet you filter server-side is bandwidth you do not carry, CPU you do not spend, and load you do not put on the network. A client that connects to the full feed and discards 99.9% of it works fine and is still doing the wrong thing. Push the predicate to the server.

Running an IGate

An IGate bridges RF and APRS-IS. Receive-only is trivially safe and genuinely useful. Bidirectional gating is where care is required.

Receive-only (RX IGate)

Hear a packet on 144.390, append qAR,YOURCALL, send it to APRS-IS. That is the whole job.

Requirements are modest: an RTL-SDR or any receiver, a 2 m antenna, and software such as Dire Wolf feeding an APRS-IS client. It adds coverage for everyone in your area and cannot cause RF harm, because it never transmits. If you want to contribute something to the network, this is the thing to build.

Before you do, check aprs.fi for existing IGates nearby — if your area is already well covered, your receiver adds little, whereas a genuine gap is valuable.

Bidirectional (TX IGate)

Transmitting internet traffic onto RF is where an IGate can do real damage, because the internet has no range limit and the RF channel does. The governing rules:

  1. Only gate messages to stations you have actually heard on RF recently. The conventional window is roughly 30 minutes. If you have not heard the station, transmitting to it puts a packet on the air that nobody local can use.
  2. Never gate a packet back to RF if it already has an RF origin in its path, or if your own call already appears. That is a loop.
  3. Never gate third-party traffic (}) back to RF.
  4. Do not gate position beacons from the internet to RF at all. Messages and their acknowledgements, yes. Everyone’s positions, no — that would flood the local channel with stations nobody can hear.
  5. Respect qAX. Unverified packets must never reach RF.

Most IGate software implements these correctly by default. The failure mode is almost always someone overriding a default they did not understand.

Local RF beaconing

An IGate should beacon its own position occasionally — every 20 to 30 minutes — with the IGate symbol (/&, or an overlay) so the local network knows it exists. It should not beacon more often than that, and it should use a short path or none at all, since by definition it is connected to the internet and does not need digipeating to be seen.


Next: APRS Weather Stations covers the weather packet formats that ride on all of this, and APRS Packet Anatomy covers the frame structure underneath it.