ADS-B - Ultrafeeder¶
What you'll end up with¶
An RTL-SDR USB dongle passed through to CT 200, running the Ultrafeeder Docker stack. Live flight tracking at https://adsb.home.example.com:<admin-port> (tar1090 map). Data feeding to FlightAware, FlightRadar24, and OpenSky simultaneously. Prometheus metrics for Grafana dashboard 18398.
Prerequisites¶
- Komodo running
- Traefik running
- An RTL-SDR USB dongle plugged into the Proxmox host (e.g. RTL-SDR Blog V4, FlightAware Pro Stick)
- Feeder accounts registered: FlightAware, FlightRadar24, OpenSky Network
- Your receiver's coordinates (latitude, longitude, altitude in meters)
1. Get your SDR serial number and calibration¶
Plug in the dongle on the Proxmox host, then:
Note the serial number shown. If you have multiple SDRs, set a unique serial with rtl_eeprom -s <serial> to avoid order changes after reboot.
PPM calibration: leave at 0 initially. After a few days of data you can fine-tune it - but for ADS-B at 1090 MHz the default is usually fine.
2. Create the LXC¶
| Setting | Value |
|---|---|
| CT ID | 200 |
| Hostname | ultrafeeder |
| Cores | 2 |
| RAM | 2048 MB |
| Disk | 8 GB |
| IP | 192.168.50.200/24 |
3. Run the CT script¶
This applies the USB passthrough to CT 200. Unlike the Zigbee dongle (which uses dev0), the RTL-SDR uses a different passthrough method because Docker needs access to the entire USB bus to enumerate the device:
lxc.cgroup2.devices.allow: c 189:* rwm
lxc.mount.entry: /dev/bus/usb dev/bus/usb none bind,optional,create=dir
The Docker compose then adds device_cgroup_rules: 'c 189:* rwm' to the Ultrafeeder container. Both the LXC-level and container-level rules are required.
4. Fill in the stack .env¶
| Variable | Value |
|---|---|
FEEDER_TZ |
Your timezone (e.g. Europe/Madrid) |
FEEDER_LAT |
Receiver latitude (decimal, e.g. 40.4168) |
FEEDER_LONG |
Receiver longitude (decimal, e.g. -3.7038) |
FEEDER_ALT_M |
Receiver altitude in meters above sea level |
FEEDER_NAME |
Display name for your feeder |
ADSB_SDR_SERIAL |
SDR serial number from step 1 |
ADSB_SDR_PPM |
PPM offset (use 0 initially) |
ULTRAFEEDER_UUID |
Generate at UUID generator |
PIAWARE_FEEDER_ID |
Your FlightAware claim code |
FR24_SHARING_KEY |
Your FlightRadar24 sharing key |
OPENSKY_USERNAME |
Your OpenSky username |
OPENSKY_SERIAL |
Your OpenSky feeder serial |
Getting feed keys:
- FlightAware: After registering, go to your account → My ADS-B → claim a new feeder → copy the claim code into
PIAWARE_FEEDER_ID - FlightRadar24: fr24feed signup → sharing key is emailed to you
- OpenSky: Register a sensor at opensky-network.org/my-sensor - serial is assigned after registration
5. Deploy via Komodo¶
Add CT 200 as a server in Komodo (wss://192.168.50.200:8120), then deploy the ultrafeeder stack.
Use the :telegraf image tag
The compose must use ghcr.io/sdr-enthusiasts/docker-adsb-ultrafeeder:telegraf, not :latest. The :latest tag dropped Telegraf support - port 9273 (readsb Prometheus metrics) won't bind without it, which breaks Grafana dashboard 18398.
After deploy, open https://adsb.home.example.com:<admin-port> - the tar1090 map should appear. Aircraft will start showing up within 30�60 seconds if the SDR is receiving signals.
6. Verify feeding¶
Check each feed status:
- FlightAware:
https://piaware.home.example.com:<admin-port>- shows connection status and message rate - FlightRadar24:
https://fr24.home.example.com:<admin-port>- shows feed status - OpenSky: opensky-network.org/receiver-profile - may take up to 24h to appear
7. Add to Prometheus (optional)¶
Ultrafeeder exposes metrics on two ports. These are already in prometheus.yml under the ultrafeeder job:
| Port | Metrics |
|---|---|
9273 |
readsb stats: aircraft count, message rate, signal quality |
9274 |
feed stats per aggregator |
After deploying the node-exporter-ultrafeeder stack, reload Prometheus config:
Then in Grafana, import dashboard 18398 and set the $host variable to ultrafeeder.
Day-2 operations¶
Updating Ultrafeeder¶
In Komodo UI: Stacks → ultrafeeder → Deploy. Pulls the latest image and restarts.
Pin the :telegraf tag
Don't let it pull :latest - always use ghcr.io/sdr-enthusiasts/docker-adsb-ultrafeeder:telegraf. :latest dropped Telegraf support, which breaks port 9273 and the Grafana dashboard.
Adding a new feed aggregator¶
Add an entry to ULTRAFEEDER_CONFIG in the .env file:
Redeploy the stack via Komodo to apply.
Checking message rate / signal quality¶
tar1090 map → click the stats icon in the bottom left. Good message rates depend heavily on antenna placement - outdoor or attic placement with a 1090 MHz antenna significantly outperforms indoor.
USB device changed bus path¶
If you re-plug the dongle or change USB ports, the bus path changes but the serial number doesn't. The LXC config mounts the whole /dev/bus/usb directory, so no LXC config change is needed. Just redeploy the stack in Komodo so Docker re-enumerates the device.
Troubleshooting¶
tar1090 map loads but shows no aircraft
- Check the SDR is detected inside CT 200:
pct exec 200 -- docker exec ultrafeeder rtl_test -t - Confirm the serial number in
.envmatches the actual device:pct exec 200 -- docker exec ultrafeeder rtl_eeprom - Check the LXC passthrough is active:
pct exec 200 -- ls /dev/bus/usb/
Port 9273 not responding (Prometheus scrape failing)
The image tag must be :telegraf. Check: pct exec 200 -- docker inspect ultrafeeder | grep Image.
Feeds not connecting
Check container logs for each feed service:
Common causes: wrong sharing key, firewall blocking outbound connections, or feed site temporarily down.