English · Português
One command installer for a complete ADS-B stack (RTL-SDR + readsb + tar1090) on Arch and derivatives.
ADS-B guides almost always assume Raspberry Pi OS or Debian: the official scripts use apt-get, Debian's lighttpd already ships the conf.d/conf-enabled layout, and the AUR packages of older decoders are not tested against current GCC. Every one of those costs real debugging on an Arch-based box. easy1090 automates the whole thing with the friction already sorted out.
What you end up with: the correct driver for the RTL-SDR Blog V4, readsb decoding ADS-B at 1090 MHz, and a live web map, all with permissions, udev rules and systemd services in place, surviving reboots.
The stack, seen from the machine itself: viewadsb with callsign and RSSI, and the SBS CSV stream straight out of port 30003 (TAM, Aerolíneas Argentinas and Lufthansa passing over the region that day):
The reward, on the map: the tooltip alone answers "what plane is that?", a South African Airways A330 climbing through 9,250 feet, with registration, route, altitude and speed:
- Arch Linux or a derivative (EndeavourOS, Omarchy, Manjaro, CachyOS)
- An AUR helper (
yay) - An RTL-SDR plugged in, ideally the RTL-SDR Blog V4
- A real terminal, because
sudoneeds a tty
git clone https://github.com/Esl1h/easy1090.git
cd easy1090
./easy1090 install./install.sh still works as a shortcut for ./easy1090 install.
There is a second implementation of the same installer in Rust, under rust/: same commands, same messages, same behavior, verified by comparing its output against the shell version. Every release publishes it as a static, self-contained binary, so the tree clone above is replaced by a download:
curl -fsSL -o easy1090 \
https://github.com/Esl1h/easy1090/releases/download/v0.2.0-rust.3-rc/easy1090-0.2.0-linux-amd64.bin
chmod +x easy1090
./easy1090 installRun it as your normal user, like the shell version: it asks for sudo when a step needs it, and refuses to start as root. Run it from the directory that should hold install.conf: the binary keeps that file in the current directory, the way the shell version keeps it next to the script. install.conf.example and the pinned tar1090 installer are compiled in, so the .bin needs nothing else.
There is an arm64 binary alongside it for Raspberry Pi and friends, and a SHA256SUMS to check. Each binary also comes in a .tar.gz with the README, the license and a vendor/ directory that carries the tar1090 license text; files next to the binary win over the compiled-in copies. Being statically linked, the binary runs on any Arch derivative regardless of its glibc age.
Two honest caveats: it is a release candidate, not the battle-tested default yet, and the install is download-and-run, deliberately not curl | sudo bash, because sudo needs a real tty for the password and the first run is interactive (language, antenna position, feeding).
Until the port graduates, the shell version in this tree is the reference implementation.
Before running anything as root on your machine, see what it would do:
./install.sh --dry-run--dry-run runs the full preflight (read-only) and prints the exact commands, not descriptions of them. It is the same text you could paste into a terminal yourself.
On first run it asks for your interface language (Portuguese or English), your antenna coordinates, and whether you want to share data with a public flight tracking network. All three are remembered in install.conf.
--full install everything, including SDR++ and SatDump
--lang <pt|en> interface language
--lat <degrees> antenna latitude (e.g. -23.58)
--lon <degrees> antenna longitude (e.g. -46.55)
--skip-tar1090 do not install the web map
--skip-sdrpp do not install SDR++
--skip-satdump do not install SatDump
--dry-run print the exact commands, without executing
--yes do not ask anything (except the sudo password)
--verbose debug level logging
yay -Syu --devel # AUR git packages yay installed: the driver, SDR++
./easy1090 install # converges config and services after an updateOr let easy1090 do both halves:
./easy1090 updateIt runs yay -Syu --devel and then handles readsb separately, because readsb needs handling separately.
--devel is not optional: every AUR package in this stack is a -git one, and a plain yay -Syu compares against the version declared in the AUR, which does not move when upstream commits. Without it nothing is ever updated.
And readsb is invisible even to --devel. It is built with makepkg outside yay, deliberately, so that a prepare() patch stays possible when a new GCC breaks the build. The cost is that yay never records it in its VCS database, so it is never checked. easy1090 update compares the installed commit with upstream HEAD itself and offers to rebuild.
Check what you are running with pacman -Q readsb-wiedehopf-git: the .gXXXXXXX suffix is the upstream commit it was built from.
./easy1090 status # what is running, what fell over, what is missing
./easy1090 restart # restart readsb, lighttpd and tar1090 in order
./easy1090 open # list what you can open
./easy1090 open viewadsb # live table in the terminal
./easy1090 open map # web map in the browser (prints the URL if headless)status and open never ask for sudo. open runs in the current terminal instead of spawning a window, because this stack usually lives on a headless box.
To undo it all:
./easy1090 uninstall --dry-run # see exactly what would be removed
./easy1090 uninstallIt calls tar1090's own uninstaller, removes the services, configs and packages easy1090 installed, and deliberately leaves shared packages (lighttpd, jq) and the system users alone. --keep-packages removes only services and configs.
And the web map at http://YOUR-SERVER-IP/tar1090/.
Configuration lives in install.conf, created from install.conf.example on first run. It is plain sourceable shell, in the /etc/default/* style, with no parser dependency.
Because the installer is idempotent, that file works as a declaration of the desired state of the machine: running it again converges to whatever is written there. There is no separate --update mode, and no first run versus later run distinction.
What that converges is configuration and services, not package versions. If a component is already installed, easy1090 leaves it alone: keeping your packages current is yay -Syu, deliberately. Pulling a new AUR version behind your back could start a 45 minute rebuild with no warning, which is not something an installer should decide for you.
Two settings worth reading before the first run:
JSON_LOCATION_ACCURACY controls how precisely your receiver position is exposed in the JSON and on the map. The default is exact; if the map is reachable outside your network, consider lowering it to approximate, or not publishing it at all.
Turn it on, and set up the statistics package, with:
./easy1090 feed # list the networks and their state
./easy1090 feed adsbexchange # enable, plus their stats package and UUID
./easy1090 feed airplaneslive # enable (readsb feeds it directly)
./easy1090 feed adsbexchange --disableBoth can be fed at once: they are independent connectors on the same readsb. airplanes.live needs no extra package for ADS-B; their installer exists for MLAT, which needs a separate client and, unlike ADS-B, does require your exact position.
FEEDER_ADSBEXCHANGE is off. Enabling it shares your data and your position with a third party, so it is opt-in by decision, never by oversight. The installer asks explicitly on first run.
FlightAware is deliberately not offered: feeding their network requires the piaware client, with its own registration and feeder ID, and a plain --net-connector feeds nothing.
This list is the real value of the project, and every item cost actual debugging:
pacman's --noconfirm answers "N" to the conflict prompt, silently aborting the install. So removing a conflicting package is always an explicit, confirmed step.
yay resets any edit to the cached PKGBUILD on every run, which is correct anti-tampering behavior but incompatible with manual patches. Builds that need a patch run from a copied directory, outside ~/.cache/yay/.
blacklist in modprobe.d only stops autoload at boot. On hotplug, udev asks for the module by alias and the kernel hands it over anyway. The install <module> /bin/false line is what actually closes that door, and it is missing from almost every tutorial.
The stock udev rule grants the dongle to the plugdev group, which is enough for an interactive user because systemd-logind adds a session ACL. The readsb service user has no session and no ACL, so it needs a rule for its own group. The problem hides precisely because it works when you test by hand.
Arch's lighttpd.conf is minimal and never includes conf-enabled, so everything the tar1090 installer writes there is dead config, with no error at all.
Arch does not load mod_redirect, so tar1090's url.redirect is ignored and the slash-less URL returns 404, which is exactly the URL the installer prints when it finishes.
The tar1090 installer only restarts lighttpd if it was already running; a freshly installed one stays dead and disabled.
sudo does not work without a real tty. Preflight detects it and fails early with a clear message, instead of letting you find out in the middle of a 45 minute build.
The script runs as a normal user and aborts if executed as root, because makepkg and yay refuse to run that way. Escalation is per step, via sudo. A single sudo -v up front validates the password once, and a background keepalive holds the timestamp during long builds so you are not asked again mid-compile.
The official tar1090 installer is vendored under vendor/ rather than fetched from the network on each run, and is checksum verified before executing. Updating means downloading the new version, reviewing the diff and changing the pin in install.conf. Refusing to run a modified root script is deliberate.
v1 supports Arch and derivatives. The package manager layer is isolated in lib/pkg-arch.sh, so supporting another distro means writing a pkg-debian.sh with the same pkg::* interface, without touching the modules. Debian and Raspberry Pi OS are not a priority because upstream's own scripts already cover them well.
It is not a daemon nor a configuration panel. It is an installer you run when you want to.
easy1090/
├── easy1090 single entrypoint, dispatches the subcommands
├── install.sh thin wrapper for "easy1090 install"
├── install.conf.example reference configuration
├── lib/
│ ├── common.sh logging, dry-run execution, sudo, config
│ ├── i18n.sh language selection and lookup
│ ├── i18n/{pt,en}.sh message catalogs
│ ├── pkg-arch.sh package manager layer
│ ├── cmd-install.sh install command
│ ├── cmd-update.sh update command
│ ├── cmd-feed.sh ADSBExchange feed and stats
│ ├── cmd-uninstall.sh uninstall command
│ ├── cmd-status.sh status command (read-only)
│ ├── cmd-service.sh start / stop / restart
│ ├── cmd-open.sh open command
│ ├── 00-preflight.sh read-only checks
│ ├── 10-driver.sh RTL-SDR Blog fork and DVB blacklist
│ ├── 20-readsb.sh decoder, udev, systemd
│ ├── 30-tar1090.sh web map and the Arch lighttpd fixes
│ ├── 40-optional.sh SDR++ and SatDump
│ └── 60-validate.sh end to end validation
├── rust/ the Rust port (see rust/README.md)
└── vendor/
├── tar1090-install.sh official installer, pinned by checksum (GPL v2+)
├── LICENSE.tar1090 upstream license text
└── README.md provenance and update procedure
The manual walkthrough, with the reasoning behind every choice, is documented in the SDR series on my blog (in Portuguese):
- Capturing ADS-B at 1090 MHz with the RTL-SDR v4
- From terminal to map: live ADS-B on the web with tar1090
- Practical guide: every way to watch ADS-B in real time
If you want to understand before running a root script, start there.
Bug reports from real installations are the most useful contribution, because this project exists to encode friction that only shows up on actual hardware. See CONTRIBUTING.md, the code of conduct and the security policy.
Current release: v0.2.0, tested end to end on a clean Omarchy (Arch) machine with an RTL-SDR Blog V4, and on an EndeavourOS server that had been built by hand.
The Rust port is at v0.2.0-rust.3-rc: full command parity with the shell version, verified output-for-output, but not yet exercised end to end on real hardware the way the shell release was.
Changes are tracked in CHANGELOG.md. The frictions found along the way, with their causes and the reasoning behind each workaround, are in KNOWN_ISSUES.md, which is worth reading before opening an issue.
Two things are not yet exercised: the removal path for a conflicting Mictronics readsb-git (it needs a machine that already has the old fork installed), and a full --full run including SatDump.
easy1090 is MIT.
vendor/tar1090-install.sh is third party code by Matthias Wirth (wiedehopf), redistributed under GPL v2 or later, its own license. It stays byte identical to upstream and is invoked as a separate program. See vendor/README.md for provenance, the checksum pin and how to update it.

