Skip to content

How federation works

What does it mean that APRScaching instances form one network, and what keeps that network honest? This page answers both for the sysop who is deciding whether to federate, and for anyone curious how a cache hidden on one instance shows up on another. It explains; the steps are in Join the network.

One network, no central server

Every instance is complete on its own: its own map, accounts, receivers and database. Federation links independent instances into one network without putting anyone in charge of it. There is no central server to sign up with, no company account and no single place that can switch the network off. Two sysops who know each other link their instances directly.

What the network gives the people on it:

  • Players see caches from across the network. A cache hidden on an instance your sysop trusts appears on your map, marked mirrored from its home instance. Finds logged there travel with it, so a cache's log reads the same everywhere.
  • Finds are confirmed across instances. When your own instance did not hear a finder on the air, it can ask the instances it trusts whether their receivers did. Enough independent "yes" answers lift the find to Radio-verified (Tier A), even though the finder was heard far from your receivers.
  • Trust stays local. Each sysop decides which peers to trust. A record from a peer you have not vetted stays hidden; a peer you block disappears.
  • Deletes reach everyone. When a player erases their account or a sysop removes a cache, a signed deletion travels the same paths and removes the copies on every instance that mirrored them.
  • Each instance keeps working alone. A peer that goes offline costs you nothing but its updates. An instance on a phone in the field or on a box with no internet carries on, and catches up when a path returns.

The moving parts

Signed records. Everything that travels is a record signed by the instance it comes from: a cache, a find, a callsign key, a bulletin, a deletion. A receiving instance checks the signature before it keeps anything, so the path a record took does not matter. The internet, 44Net, HAMNET and packet radio all carry the same bytes, and none of them can change a record without breaking its signature.

Keys and fingerprints. Each instance has its own signing key (FED_PRIVATE_KEY). A key fingerprint is a short checksum of it, four groups of four hex digits. Two sysops read their fingerprints to each other over a channel they already trust, such as a phone call or a QSO. That check, not the URL, is what tells you the key belongs to the instance you meant.

Peers and trust levels. A peer is another instance yours exchanges records with. Each peer has a trust level that you set: trusted (shown on the map, and a voice in find confirmation), unvetted (kept, but hidden until a player asks to see it), or blocked (ignored on every path). A new peer starts unvetted, however it arrived, unless you pinned its fingerprint in advance.

Mirrors. Your instance keeps a copy of what its peers publish, in tables of its own that are for display only. A mirrored cache is read on your instance and logged on its home instance. A record only moves forward: an older copy, replayed, changes nothing, however many paths bring it.

Tombstones. A tombstone is a signed deletion record. It travels ahead of the records in every exchange, so a deleted cache or an erased account is never mirrored back. Instances keep tombstones for good.

Corroboration quorum. Corroboration is one instance asking its trusted peers whether their own receivers heard a finder near a cache. A find needs two independent identities to agree (FED_CORROBORATION_QUORUM), counted by operator, so one sysop with several instances is one voice (How a find gets confirmed across instances).

How records travel

A record travels from the instance that signed it to the instances that fetch it or are handed it, and on through hubs. An instance publishes its own records and passes on what it mirrored from the instances it trusts, each record exactly as its home instance signed it. The spokes of one club hub therefore see each other's caches and finds, and so does every instance that follows the hub.

flowchart LR
  A["Instance A<br/>internet"]
  B["Instance B<br/>internet"]
  C["Instance C<br/>44Net"]
  D["Instance D<br/>HAMNET"]
  E["Instance E<br/>HAMNET"]
  H["Club hub"]
  P["Pocket or NAT box"]
  Q["Second spoke"]
  R["Instance R<br/>packet radio only"]
  F["Instance F<br/>no IP path"]
  A <-->|pull both ways| B
  A <-->|pull over 44Net| C
  D <-->|pull over HAMNET| E
  B -->|pulls, gets the spokes' records too| H
  P -->|pushes its records| H
  P -->|pulls the hub's and the other spokes' records| H
  Q -->|pushes and pulls| H
  A -->|pulls over an AX.25 circuit| R
  B -.->|FBB mail, experimental| F

An arrow starts at the instance that opens the connection.

  • Pull is the usual path: your instance fetches each peer's new records on a schedule, and a peer that has news asks you to fetch at once. A 44Net instance the internet reaches pulls like any internet instance; a HAMNET instance reaches only other HAMNET hosts.
  • Push is for an instance nobody can reach, such as a phone on mobile data or a box behind a carrier's NAT: it sends its records to a hub it can reach, a few seconds after each write, and collects the questions the hub holds for it.
  • Packet circuit is a pull over AX.25 or NET/ROM, dialled by your ingest box, for a peer you reach by radio rather than IP. It is off by default.
  • Store-and-forward over FBB packet mail is for a peer with no IP path at all. It is experimental and off by default.

Choose how to connect matches each situation to a path, and Federation transports explains every transport step by step, with who starts it, what it sends, when and what to configure.

How instances find each other. Mostly, two sysops exchange addresses and fingerprints. An instance can also hear of others: its trusted peers list the instances they trust, and instances on one Wi-Fi network or hotspot announce themselves by mDNS. What it hears of is listed, switched off and unvetted, and nothing is pulled from it until the sysop follows it (Discovery).

A hub passes on the records of the instances it trusts (A hub passes its spokes' records on). The hub signs nothing of them and lends them none of its trust: your instance checks each record against its home instance's key and shows it with your own trust in that home. A home you never vetted stays hidden however many hubs it crossed, and one you block stays blocked. A record crosses at most four instances, and never travels back to its home instance.

How records travel through the mesh

Every instance keeps track of what it holds per home instance: "every cache of instance A up to number 812 is here". Each home numbers its records in the order it writes them, and the number is part of what it signs. When your instance meets a neighbour, over the internet, 44Net, HAMNET or a hub, it reads the neighbour's summary of what the neighbour holds of each home, and asks only for what lies past its own position: "A's caches after 812". Any neighbour can fill the gap, so your instance switches paths without reading again what it already holds.

flowchart LR
  A["Instance A<br/>signs caches 1 to 900"]
  H1["Hub 1<br/>holds A up to 812"]
  H2["Hub 2<br/>holds A up to 900"]
  M["Pocket station<br/>holds A up to 900"]
  C["Your instance<br/>holds A up to 812"]
  A -->|pull| H1
  A -->|pull| H2
  A -->|pull at home| M
  H1 -->|summary: A up to 812, nothing to ask| C
  H2 -->|A after 812: 813 to 900| C
  M -.->|at the field event, when no other path exists| C
  • Signed by the home, whoever carries it. A hub, a second hub or a phone passes each record on exactly as its home signed it. Your instance checks it against the home's key; the path adds no trust.
  • Deletions first. Each exchange brings every home's tombstones before any cache or find, and your instance keeps tombstones for good, so a stale copy that arrives later over another path is refused.
  • Gaps get filled. A neighbour you trust moves your position for a home; a neighbour nobody vetted still delivers records, but your instance does not take its word for what it holds, so a neighbour that skips a record cannot hide it. A record your instance could not take (its clock behind, its database busy), one that reached it over four other instances, and one a neighbour lacked, are asked for one by one while sync moves on. One that no neighbour delivers within a week is given up and listed for the sysop; a missing deletion (tombstone) is never given up, and is asked for daily until it arrives.
  • A phone carries records. A Pocket station that syncs at home and later meets an instance with no path home is an ordinary neighbour: it passes on what it holds, each record signed by its home (Carry records between instances).

How a find gets confirmed across instances

This is the exchange that makes a network of small instances stronger than any one of them. A player logs a find on their home instance. That instance's own receivers did not hear the player near the cache, perhaps because the cache is 200 km away. Other instances may have heard them. Federation asks them.

When it happens. At the moment the find is logged, and only when the find has not already reached Radio-verified on its own. The question goes to every trusted peer at once (at most 16), and each has 3 seconds to answer, so the player sees the result with the log.

What the question says. "Did your own receivers hear OE8APR-7 within this area, in this half-hour, at a receiving site other than these?" The area is snapped to a grid of about 500 m and the time to 10-minute buckets, so the question never reveals the exact spot or second. The "other than these" list holds the finder's own calls and stations: a station the finder controls never vouches for them. The asking instance signs the question with its key and adds a fresh random number (a nonce).

How a peer answers. The peer checks the question's signature and refuses a peer it blocked. It searches only positions that one of its own attested receiving sites heard directly on the air and delivered through its own ingest box. A copy from APRS-IS never counts, because anyone with a public passcode can inject one. It answers "yes, within about this distance, around this time" in 100 m and 10-minute buckets, or "no". It signs the answer and binds it to the question's nonce, so the answer cannot be replayed or reused for another question.

The quorum. The asking instance checks each answer's signature against the key it pinned for that peer. It counts the "yes" answers by identity: by the operator the registry names, else the callsign the peer was added under, else its key. When two identities agree (FED_CORROBORATION_QUORUM), and the finder's own track could have been at that place at that time, the find becomes Radio-verified (Tier A) and records which instance confirmed it.

sequenceDiagram
  participant F as Finder
  participant H as Home instance
  participant P1 as Trusted peer 1
  participant P2 as Trusted peer 2
  F->>H: log a find
  Note over H: own receivers did not hear the finder
  par ask every trusted peer
    H->>P1: signed question, nonce
    H->>P2: signed question, nonce
  end
  Note over P1,P2: search positions their own receivers heard on air
  P1-->>H: signed yes, distance bucket
  P2-->>H: signed yes, distance bucket
  Note over H: two identities agree, track plausible
  H-->>F: find is Radio-verified

Confirmed later. An answer that comes through a hub's relay (below) arrives once the spoke collects the question, about 15 seconds after the find while the spoke is online, and lifts the find then. When a trusted peer could not be reached (a timeout, a failed connection, a rate limit or a server error), the same question goes to the peers that missed it again 1, 6 and 24 hours after the find, and never after 72 hours. Answers already in hand still count, as long as their peer is still trusted. A find lifted this way shows confirmed later. A verified "no" from a trusted peer ends the retries.

Which instances can answer. A peer reachable at an address the asking instance can dial (its https URL, its 44Net name, or its HAMNET address when the asker is on HAMNET too) gets the question directly. A trusted peer nobody can dial, such as a phone or a box behind a carrier's NAT that pushes to a hub, gets it through the hub's relay: the asking instance leaves the signed question with the hub, the spoke collects it on its own outbound connection and answers from its own receivers, and the asking instance reads the signed answer back. The hub queues questions only for its own push spokes and only from instances it knows, and it cannot change an answer. When the asking instance is the hub itself, the question goes straight into its own queue. A home instance known only through the records a hub passes on is not asked: its key came from that hub, which would then both carry the answer and vouch for the key that signs it.

sequenceDiagram
  participant A as Home instance
  participant H as Hub
  participant S as Spoke, no inbound port
  A->>H: signed question for S
  H-->>A: ticket
  S->>H: collect my queries, every 15 s
  H-->>S: the question, unchanged
  Note over S: search positions its own receivers heard on air
  S->>H: signed answer
  A->>H: read the answer, signed, with the ticket
  H-->>A: S's signed answer
  Note over A: check it against S's key and the nonce

A spoke answers only while it is online and collecting its queries (FED_RELAY_SECRET on the spoke). A question it has not answered within an hour goes to the next later attempt. The quorum counts the spoke by its identity, as any other peer, whichever path its answer took. Packet radio carries no questions.

What a sysop configures. A signing key (FED_PRIVATE_KEY) to ask at all; the peers you trust; your own receiving sites under Instance admin → Trusted receiving stations or FIRST_PARTY_SITES, without which your instance never vouches for anyone; and optionally FED_CORROBORATION_QUORUM, FED_CORROBORATION_REQUIRE_KNOWN and FED_REVEAL_IGATE (Running federation safely). For a firewalled spoke to answer through its hub, both set FED_RELAY_SECRET (Rendezvous relay).

What travels, and what never does

Travels to peers Never leaves your instance
Caches hidden on your instance, with their title, type, D/T, position and description Caches the hider marked local-only
Finds, DNFs and notes on those caches, signed by the finder where they signed them Finds on local-only or imported caches
Callsign keys, and whether each call is verified Imported data: heritage places and caches imported from other platforms
Bulletins, tombstones and account moves The hint of every cache, and the description of an unlisted cache
Caches, finds, tombstones and account moves mirrored from the instances you trust, unchanged (FED_RESERVE) Accounts, email addresses, sessions, passkeys and profiles
Station positions, tracks, messages and packet logs

An unlisted cache travels without its description, and a mirror keeps it off its map as its home does. Corroboration answers say "heard within a distance, around a time", in coarse buckets; the receiving station's callsign is shared only when both sysops opt in (FED_REVEAL_IGATE).

What federation cannot do

  • Lift trust by itself. A record from an instance you never vetted stays hidden, whatever path brought it, a trusted hub included. A beacon or a mail batch from an unknown instance is quarantined, never applied.
  • Forge or alter a record. A relay, a hub, a tunnel or an RF path in between can delay or drop records, but not change them unnoticed.
  • Recall a record. A peer that mirrored a cache keeps its copy until a tombstone arrives. A peer that is offline sees the deletion when it next syncs.
  • Hide anything on the air. Over amateur RF, records are signed and readable, never encrypted (Automatic stations on the air).

Next