A local web console for WarDragon drone detection kits. It is intended to run on the kit and answer: is this kit healthy, and what is it seeing right now?
- Health dashboard from ZMQ snapshots:
4225wardragon_monitor system/GPS/DragonSDR status4227droneid-go health4228DragonSig health
- Drone and signal summaries from DragonSync HTTP:
GET /statusGET /dronesGET /signals
- Curated read/write view for the two allowlisted DragonSync config files:
/home/dragon/WarDragon/DragonSync/config.ini/home/dragon/WarDragon/DragonSync/gps.ini
The console does not subscribe to high-rate drone/signal ZMQ ports and does not query systemd for service state.
If you have not cloned it yet, drop the checkout next to DragonSync inside the WarDragon directory and run the installer:
cd ~/WarDragon
git clone https://github.com/alphafox02/wardragon-console.git WarDragon-Console
cd WarDragon-Console
sudo packaging/install.shThe installer is opinionated and built for the WarDragon kit layout. It is honest about that: it assumes a user named dragon, with DragonSync at /home/dragon/WarDragon/DragonSync. Override with WARDRAGON_USER=<name> and WARDRAGON_DRAGONSYNC_DIR=/path if you have a different layout — or just run the installer on a TTY and it will prompt for the user. Non-default values work but are best-effort: DragonSync itself was built around dragon, so a different user means you also took on the path mapping for DragonSync. The installer exits cleanly if the chosen user does not exist.
install.sh is idempotent — re-run it any time you change packaging files or want to refresh the systemd unit.
What it does:
- apt-installs anything missing from
python3 python3-zmq rsync avahi-daemon avahi-utils python3-dbus python3-gi gir1.2-glib-2.0. No pip and no virtualenv on the kit. - Copies source to
/opt/wardragon-consoleand creates a/usr/local/bin/wardragon-consolewrapper. - Installs
wardragon-console.service(templated to the chosen user). Runs as that user, not root. - Installs
/etc/sudoers.d/wardragon-consolewith a single narrow rule letting the service account runsystemctl restart dragonsync.serviceand nothing else. - Publishes
wardragon.localon the LAN via Avahi (packaging/avahi/wardragon-console.service) and a small CNAME publisher unit (wardragon-avahi-alias.service) that adds the alias over the Avahi D-Bus API — no/etc/hostnamechange. - Pins
wardragon.localto127.0.0.1in/etc/hostson the kit only, so the kit's own browser always reaches loopback. Remote clients ignore this and keep using mDNS. - Sets
deny-interfaces=in/etc/avahi/avahi-daemon.confto the kit's current docker bridges and veth pairs, so Avahi only announces on real network interfaces. If you create new docker networks later, re-runinstall.sh. - Creates
<DragonSync>/certs(mode 0700, owned by the service user) for TAK certificate uploads. - Hardens the service unit (
ProtectSystem=strict,ProtectHome=read-only,PrivateTmp,RestrictAddressFamilies, etc.).NoNewPrivilegesis deliberately not set so the sudoers DragonSync restart still works.
packaging/setup-time-sync.sh is a separate, operator-run helper. It is not invoked by install.sh because it touches system-wide time configuration, and that is your call. Run it once per fresh kit image:
sudo packaging/setup-time-sync.shWhat it does (idempotent — safe to re-run):
- apt-installs
chrony,gpsd,gpsd-clientsif missing. - Sets
START_DAEMON="true",USBAUTO="true",GPSD_OPTIONS="-n"in/etc/default/gpsd. LeavesDEVICES=""so the gpsd udev rules auto-pick a plugged-in USB GPS. - Adds a managed
refclock SHM 0block to/etc/chrony/chrony.confso chrony reads gpsd's shared-memory time samples. Stratum 10 so internet NTP stays preferred when reachable, with offset/delay tuned for non-PPS serial GPS so chrony does not mark it as a falseticker. - Enables and (re)starts
chronyandgpsd.socket. - Backs up the originals to
*.wardragon.bakon first run.
When internet NTP is reachable, chrony keeps using it. When the kit goes offline, chrony falls back to GPS so the system clock keeps tracking UTC instead of free-running.
Useful environment overrides (set in packaging/wardragon-console.service for the packaged install):
WARDRAGON_DRAGONSYNC_DIR=/path/to/DragonSync
WARDRAGON_DRAGONSYNC_URL=http://127.0.0.1:8088
WARDRAGON_CONSOLE_HOST=127.0.0.1
WARDRAGON_CONSOLE_PORT=4280
WARDRAGON_CONSOLE_CONFIG_WRITE=1
WARDRAGON_CONSOLE_TETHER_ENABLED=1
WARDRAGON_CONSOLE_TETHER_CIDRS=192.168.42.0/24,192.168.43.0/24,172.20.10.0/28
WARDRAGON_CONSOLE_REMOTE_CONFIG_WRITE=1
WARDRAGON_CONSOLE_REMOTE_RESTART=0
WARDRAGON_CONSOLE_UPDATE_CHECK=1
WARDRAGON_CONSOLE_UPSTREAM_REPO=alphafox02/wardragon-console
WARDRAGON_DRAGONSYNC_UPSTREAM_REPO=alphafox02/DragonSyncThe Version tab has a Check for updates button. It compares the local install to the configured upstream GitHub repos and tells you whether you are behind. It does not pull or apply anything — actually upgrading is still a manual git pull && sudo packaging/install.sh. Set WARDRAGON_CONSOLE_UPDATE_CHECK=0 on air-gapped kits to disable the endpoint entirely.
Config writes are only allowed by default when the server is bound to loopback. If a future tether/tablet mode exposes the console on a non-loopback address, config writes stay disabled unless WARDRAGON_CONSOLE_REMOTE_CONFIG_WRITE=1 is set.
DragonSync restart is separate. Remote/tablet config editing does not imply remote restart; keep WARDRAGON_CONSOLE_REMOTE_RESTART=0 if tablet users should save changes but not restart the service. The default packaged service allows tablet config writes but keeps tablet restart disabled.
The config UI is intentionally curated. It does not expose Kismet or ADS-B options yet. Saves are atomic and short-circuit when nothing actually changed; real changes create a single timestamped backup beside the edited file. DragonSync still needs a restart or reboot before most changes take effect.
TAK certificate upload stores files under <DragonSync>/certs/ and writes absolute paths into config.ini. Absolute paths are intentional even though DragonSync runs with WorkingDirectory=<DragonSync> — they survive future service changes and remove ambiguity.
python3 -m venv .venv
. .venv/bin/activate
pip install -e .
wardragon-consoleOpen http://localhost:4280/. No system install needed for iteration — everything reads from the working tree, and tests run with PYTHONPATH=src python3 -m unittest discover -s tests.
The safe default is still 127.0.0.1:4280. When WARDRAGON_CONSOLE_TETHER_ENABLED=1, the console watches for USB-tether-like network interfaces and starts a second HTTP listener only while one is present. This should be enabled by default on kit images so a headless operator does not need to turn on tablet mode from the UI.
The tether listener binds to the interface IP itself, not 0.0.0.0. It only activates for known phone/tablet tether drivers/vendors and expected tether subnets. This avoids opening the console on the normal WarDragon USB Ethernet adapter, which is always present on many kits.
Default tether subnets:
- Android USB tether:
192.168.42.0/24 - Android hotspot/tether variants:
192.168.43.0/24 - Apple personal hotspot:
172.20.10.0/28
Override with WARDRAGON_CONSOLE_TETHER_CIDRS if a real device uses a different tether subnet.
Examples:
- Android USB tether usually appears as
rndis_host/cdc_etherwith an address like192.168.42.x. - iPhone/iPad USB tether usually appears as
iphethor Apple USB vendor05acwith an address like172.20.10.x.
The Overview and System tabs show the current tablet URL, for example http://172.20.10.2:4280/.
install.sh apt-installs avahi-daemon, avahi-utils, python3-dbus, python3-gi, and gir1.2-glib-2.0 if missing, then makes four small changes so the kit is reachable as wardragon.local:
- Installs packaging/avahi/wardragon-console.service — advertises the HTTP service on port 4280 over mDNS.
- Installs packaging/wardragon-avahi-alias, run as
wardragon-avahi-alias.service. It publishes awardragon.localCNAME alongside the kit's own<hostname>.localrecord via the Avahi D-Bus API. No/etc/hostnamechange. - Adds a small managed block to
/etc/hostspinningwardragon.localto127.0.0.1on the kit only. This makes the kit's own browser hit loopback instead of getting a docker-bridge or veth IP back from avahi. Remote clients ignore this entry. - Sets
deny-interfaces=in/etc/avahi/avahi-daemon.confto the kit's current docker bridges and veth pairs, so avahi only announces on real interfaces (eth/wifi/USB tether). Re-runinstall.shif you create new docker networks later.
After plugging the tablet into the kit via USB and turning on USB tethering, the order to try:
- iPhone/iPad: Safari resolves
.localnatively. Openhttp://wardragon.local:4280/. Done. - Android Chrome: Chrome does not resolve
.localURLs by default. Either:- Install a service-discovery app — Service Browser (Druk1, free) is the most common; Discovery - DNS-SD Browser and Bonjour Browser also work. Open it on the tether network, find "WarDragon Console on dragon", tap to launch the URL in a browser.
- Or use Firefox for Android, which honors
.localvia the system NSD.
- Either platform, mDNS fails (some tethers NAT or client-isolate):
- Read the tether-side IP from the kit's display if HDMI is plugged in.
- Or read it from your phone's network settings — the kit will have an address in
192.168.42.x(Android) or172.20.10.x(Apple), typically.1or.2. Tryhttp://<that-ip>:4280/. - The Overview and System tabs show the current tablet URL once you do get in, so it's easy to bookmark for next time.
Remote config writes are enabled in the packaged service because physical tether/local access is the intended configuration path. Remote restart remains disabled unless WARDRAGON_CONSOLE_REMOTE_RESTART=1. Password/token fields are masked on non-loopback tablet listeners. Saving the masked placeholder preserves the existing secret; typing a new value replaces it, and clearing the field clears it.
For a no-screen kit the answer in priority order is:
- USB tether listener is auto-enabled on trusted tether interfaces (default in the packaged unit).
wardragon.localis advertised via Avahi on every real interface (not docker/veth/bridge).- If the tablet can't resolve
.local— install a discovery app per the section above. - If discovery also fails (rare; some carriers or USB-tether stacks block multicast), plug in HDMI/keyboard once and either bookmark the URL or set a static tether subnet override via
WARDRAGON_CONSOLE_TETHER_CIDRS.
The kit cannot fully guarantee IP discovery on every tablet without a screen, a managed Wi-Fi AP, or a companion scanner. The combination above covers the common phones.
MIT — see LICENSE.