Repository navigation
Guide Headless server
onair-server is OnAir without a window. The SDR is plugged into the computer that runs it (a Raspberry Pi in the attic, a Linux box, a Windows PC with no screen); you control it from a web browser on any other device, or from the desktop app or a script through the network. There is no cloud and no relay: the browser connects straight to the server. Nothing leaves your network unless you forward a port yourself.
Status: built and tested with the synthetic test signal and fake clients only. Not tried with a real radio, a real Raspberry Pi, a real browser on a phone or on a real Windows service.
onair-server # this computer only: http://127.0.0.1:8765/
onair-server --lan # other computers too: makes a token, saves it, prints it
Open http://<address of the server>:8765/?token=<token> in the browser. The page keeps the token for the tab and removes it from the address bar. From the server itself (127.0.0.1) no token is needed.
The page shows the spectrum and a waterfall (click to tune), the radio, mode, frequency, gain and sample rate, a Listen button (demodulated audio in the browser) and the receiver's telemetry. Every mode that the command line onair-cli --standard <id> knows is in the mode list.
| Loopback | No token. A request must name a loopback Host (protects against DNS rebinding). |
--lan / lan=1
|
Needs a token of 16 characters or more from every other computer: Authorization: Bearer <token> or ?token=. A bad token is answered after 300 ms; there is no other login. Without a token the server refuses to listen on the network. |
| Pages | Cross-origin requests are refused (no CORS headers are ever sent), POST needs Content-Type: application/json, and the page has a strict Content-Security-Policy (no outside script, font or image). |
| rtl_tcp share |
--share-rtltcp has no password (the rtl_tcp protocol has none): use it on a trusted network only. Off by default. |
The token travels in clear text on plain HTTP. On a network you do not trust, turn TLS on:
openssl req -x509 -newkey rsa:3072 -nodes -days 825 -keyout server.key -out server.crt -subj "/CN=onair"
onair-server --lan --tls-cert server.crt --tls-key server.key
or the same as tls_cert= / tls_key= in the settings file. The page is then https://...; a self-signed certificate gives the browser's warning once (add an exception, or use a certificate from your own CA or Let's Encrypt). TLS 1.2 and up.
TLS needs a build with OpenSSL: cmake -DDECT2_WITH_TLS=ON. It is off in the default build so the packages need no extra library; without it the server says so and refuses a certificate. A reverse proxy (Caddy, nginx) in front of the server works as well; then keep the server on 127.0.0.1 and let the proxy do the TLS and the access control.
The page's "Data use" menu sets how much the server sends. Over Wi-Fi on a phone, "Low" is about 2 spectrum lines a second of 256 bytes and 8 kHz audio (roughly 16 KB/s with audio, 1 KB/s without).
- Spectrum: a WebSocket subscription
{"spectrum":true,"bins":256,"fps":2,"fmt":"u8"}.fmt:"u8"sends one byte per bin in a binary message (0x01, u32 sequence, four little-endian floats: centre Hz, rate Hz, floor dB, top dB, then the bytes) instead of JSON text, about a tenth of the size. Default is JSON at 5 lines a second like before. - The server also watches itself: if sending a spectrum line takes more than half the line interval, the interval doubles (up to 16 times, never slower than 2 s) and comes back when the link keeps up. A slow client therefore never builds a queue.
- Audio:
{"audio":true,"arate":16000}(8000, 12000, 16000, 24000 or 48000 Hz; mono, 16 bit; binary messages starting with0x02). A listener that does not fetch loses the oldest audio, never more than one second is kept. At most 4 listeners.
Plain key=value lines, # for comments. Default place: ~/.config/onair/server.conf (%APPDATA%\OnAir\server.conf on Windows), or --config FILE, or the ONAIR_SERVER_CONFIG environment variable. The file is created on the first run (mode 0600 because it holds the token). What the browser changes (mode, frequency, gain, rate, radio, demodulator, start/stop) is written back, so the server comes up the same way after a restart; your comments and unknown keys are kept.
| Key | Meaning |
|---|---|
port |
8765 |
lan |
1: listen on all interfaces (needs a token; one is made when missing) |
token |
the access token |
tls_cert, tls_key
|
PEM files, see TLS |
device |
the radio: its name (or part of it), its number in the device list, or test for the built-in test signal. Default: the first radio found |
net_radio |
a radio on the network, as the app keeps it (rtltcp,192.168.1.20,1234); may be repeated |
file, file_rate
|
play a recording (SigMF, cs8, ...) as another "radio" |
mode |
a mode id: fm, dab, t2, atsc, adsb, dvbs, ... (all of /api/v1/modes) |
freq_mhz, rate_msps (0 = automatic), gain_db
|
tuning |
audio_demod |
auto, nfm, am, usb, lsb for Listen (automatic picks by frequency; FM broadcast uses its own stereo audio) |
autostart |
1: start the receiver when the server starts, and again 10 s after the radio comes back if it was unplugged. Start and Stop in the page set it |
share_rtltcp, share_port
|
also act as an rtl_tcp server (see above) |
Linux (systemd). packaging/linux/onair-server.service has the steps in its header: a system user in plugdev, the binary in /usr/local/bin, the settings and the token in /var/lib/onair. journalctl -u onair-server shows the log.
Raspberry Pi. The same; use a 64-bit OS and a Pi 4 or better for the heavier modes (DVB-T2 needs far more CPU than FM or ADS-B). --share-rtltcp makes it a network radio for other computers as well.
Windows. onair-server.exe is a normal console program. To run it without a login, use Task Scheduler ("run whether the user is logged on or not", trigger "at startup") or a service wrapper such as NSSM pointing at onair-server.exe --config C:\ProgramData\OnAir\server.conf. Allow the port in the firewall for the networks you trust. A built-in Windows service is not done.
-
Control: any program that speaks the remote-control API (
/api/v1/status,/devices,/modes,/start,/stop,/mode,/frequency,/samplerate,/gain,/ws; see the README) can drive the server with the token. The server addsGET /api/v1/x/server,POST /api/v1/x/demodandPOST /api/v1/x/autostart. -
Samples: start the server with
--share-rtltcpand add it in OnAir (or SDR++, SDR#) as an rtl_tcp network radio: you get the samples at the server's own rate as 8-bit IQ, and the desktop app does the decoding. The server then must run in a mode where the radio is open (receiver started).
The desktop app has no "remote server" screen of its own yet.
- One receiver, one radio at a time (the server runs the main receiver only: no second mode, no multi-radio).
- The browser page covers tuning, spectrum, audio and the common telemetry. The big per-mode tables and screens (service lists, maps, decoded text) are in the desktop app; the telemetry JSON carries the main figures of each mode.
- Voice modes that need a user-installed codec (mbelib, AMBE) are not played by the server; encrypted traffic is never decoded.
- Sound card audio of the server machine is silent on purpose: the sound goes to the browser.
See also: Tutorials and guides, FAQ, Troubleshooting.
Getting started
Using OnAir
Tools and guides (0.2.7)
- Band survey
- Message database
- Watchlists
- TV recorder
- Time machine
- Pass scheduler
- Plugin SDK
- Headless server
- All guides
Radios
Modes by group
- TV
- Broadcast radio
- Aviation
- Maritime
- Satellite & navigation
- Two-way radio
- Cellular & rail
- Pagers
- IoT & sensors
- Weather & science
- Amateur: digital
- Amateur: voice & packet
- HF utility
- General & tools
Tutorials
- DVB-T2 TV with a HackRF
- FM radio with RDS
- Aircraft with ADS-B and the map
- Ships with AIS
- DAB+ digital radio
- Weather satellite images
- HF digital: FT8 and WSPR
- Digital voice: DMR, D-STAR, P25
- Pagers: POCSAG and FLEX
- Time stations and the clock
- Record IQ, then the Signal workbench
- The signal sample library
- Control a rig with Hamlib
- Two receivers and the multi-decoder
Reference
Help
Legal and privacy
More