Configuration
xng/docs/configuration

Configuration

Everything past a one-off command lives in a station TOML file. One file describes every SDR, every mode, and every output — and xng station runs the whole site from it in a single process.

Station files

A station file is read by xng station station.toml. It has one mandatory top-level key, a [outputs] block shared by every decoder, and one[[session]] block per decode job. A full annotated example ships in the repo at contrib/station.example.toml, with a hardened systemd unit alongside it.

tomlstation.toml
station-id = "XX-KSEA-1"

[outputs]
feed-airframes = true
jsonl = "/var/log/xng/messages.jsonl"
metrics = "0.0.0.0:9090"          # Prometheus
http = "0.0.0.0:8080"             # live web dashboard + tar1090 data API
# mqtt = "mqtt://user:pass@broker:1883"
# sbs = "0.0.0.0:30003"
# beast = "0.0.0.0:30005"
# nmea-tcp = "0.0.0.0:10110"

# Two ACARS channels on one RTL-SDR
[[session]]
sdr = "driver=rtlsdr,serial=00000001"
gain = 48
mode = "acars"
sample-rate = 2400000
center = "131.000M"
channels = ["130.025", "131.125", "131.550", "131.725"]

# VDL2 on an Airspy — tuning derives from the mode plan when omitted
[[session]]
sdr = "driver=airspy"
mode = "vdl2"

# ADS-B; receiver position unlocks surface-position decode
[[session]]
sdr = "driver=rtlsdr,serial=00000002"
mode = "adsb"
sample-rate = 2000000
center = "1090M"
channels = ["1090"]
receiver-pos = "47.62,-122.35"

Don’t feel like writing tuning by hand? Run xng scan (see the Quickstart) and it prints a ready-to-paste session block. Per-mode channels and sample rates auto-derive from each mode’s built-in plan when you leave them out.

Top level

station-id

Your Airframes station identifier. Required.

string · mandatory

[outputs]

One block, applied to every session. See Inputs & outputs for what each destination does.

feed-airframes

Feed decoded messages to feed.airframes.io. Classic ACARS-only behavior unless an [outputs.airframes] block opts more modes in.

bool
jsonl

Append one normalized JSON message per line to this file.

path
metrics

Serve Prometheus metrics (frames, CRC, levels, per-label counts, FEC corrections).

host:port
http

Serve the live web dashboard and the tar1090 / VRS data API.

host:port
mqtt · sbs · beast · nmea-tcp

MQTT broker URL; SBS/BaseStation TCP; Beast binary TCP; and NMEA AIVDM TCP server, respectively.

url / host:port

Per-mode Airframes feeding

New in 0.21.0: an optional [outputs.airframes] block gives each mode its own station ID, can auto-suffix derived IDs, and lets you decode a mode locally without feeding it.

toml
[outputs.airframes]
enabled = true
station-id = "XX-KSEA"     # base id
auto-suffix = true         # → XX-KSEA-ACARS / -VDL2 / -HFDL / -AIS

[outputs.airframes.hfdl]
enabled = false            # decode HFDL locally, but do not feed it

[[session]]

Repeat one block per decode job. A session reads from an SDR or a recorded file.

sdr

SoapySDR-style device string, e.g. driver=rtlsdr,serial=00000001. Use file = "capture.cf32" instead to replay a recording.

mode

Which decoder to run — acars, vdl2, hfdl, ais, adsb, and so on. See Modes.

gain

Front-end gain in dB. Omit for hardware AGC.

sample-rate · center · channels

Capture rate (Hz), center frequency, and the channel list. Accept M/k suffixes. Auto-derived from the mode plan when omitted.

receiver-pos

lat,lon — enables ADS-B surface positions and AIS/APRS own-ship correlation.

feed · airframes-station-id

Disable feeding for just this session, or override its station ID.

Config is validated strictly (deny_unknown_fields) — a typo’d key is an error, not a silent no-op. Also note: a sample rate must be an integer multiple of the mode’s channel rate, which is the most common cause of a session that loads but never decodes.

Run it as a service

The repo includes contrib/xng-station.service. Drop in your config and enable it:

bash
sudo cp contrib/xng-station.service /etc/systemd/system/
sudo cp station.toml /etc/xng/station.toml
sudo systemctl enable --now xng-station
xng status        # live view of every session