All apps · 0 apps
Flotilla Agent
Plugin from Livin Mathew
Overview
Readme
View on GitHubflotilla-agent
Server-side companions for Flotilla Push — the optional, paid push notification feature of Flotilla, an iOS Unraid/Proxmox homelab client app. This repo is everything that runs on your server; the counterpart Cloudflare Worker that everything here talks to is flotilla-relay. The wire format both repos (and the iOS app) agree on is documented in PROTOCOL.md.
Three components, one job each:
- The Unraid plugin (
plugin/) — hooks into Unraid's own notification system (notifyagent) and a heartbeat cron job, and adds a settings page under Unraid's Settings tab for pairing and configuration. flotilla-beacon(cmd/flotilla-beacon) — the equivalent for Proxmox VE: a small daemon that receives Proxmox's native webhook locally and forwards it, since Proxmox has no plugin system to hook into directly.flotilla-seal(cmd/flotilla-seal) — the shared encryption CLI (internal/sealbox, ChaCha20-Poly1305) both senders shell out to, so the sealing logic is implemented exactly once.
MIT-licensed, no runtime dependency on anything besides Go's standard library
and golang.org/x/crypto (used only by the Go binaries — the Unraid plugin is
plain PHP/bash and needs no runtime dependency at all beyond what Unraid
already ships: bash, curl, jq).
What it does, and does not, see
- Event content is sealed (ChaCha20-Poly1305) locally, before it ever
reaches the relay. Both senders in this repo —
send-event.sh(the Unraid plugin) andflotilla-beacon(Proxmox) — encrypt with a key (K) that exists only in this server's config file and the paired iPhone's Keychain. Neither this repo's code, the relay, nor Apple's push infrastructure can read a sealed event's real subject/description; the relay only ever forwards ciphertext. - Your server's credentials never leave your LAN. Nothing in this repo
ever sends your Unraid API key, Proxmox API token, hostname, or any
server-local secret to the relay. The only things that go out are: the
pairing ID, the bearer auth secret (
S, used only to authenticate — never logged or displayed), sealed event ciphertext, and (forflotilla-beacon) a periodic heartbeat. - The one exception: the beacon-less Proxmox webhook path. If you point
Proxmox's native webhook straight at the relay's
POST /v1/pveinstead of installingflotilla-beacon, there is no local encryption step — the relay (and therefore Apple, downstream) sees that event's title, message, and severity in plaintext.flotilla-beaconexists specifically to close this gap; see PROTOCOL.md for exactly which path each sender takes. - No telemetry. Nothing in this repo phones home anywhere except the relay URL you've configured, and only for the pairing/heartbeat/event traffic described above.
Install
Unraid plugin
From Unraid's Plugins → Install Plugin, paste the .plg URL:
https://raw.githubusercontent.com/Livin21/flotilla-agent/main/plugin/flotilla-agent.plg
This installs the settings page under Settings → Flotilla Agent, where you pair with the Flotilla iOS app (scan a QR code) and configure which notification categories/severities get forwarded. "Reset pairing" there revokes the old pairing at the relay (see below) and generates a new one.
Proxmox VE (flotilla-beacon)
The iOS app renders the exact install command during pairing (also documented in PROTOCOL.md) — the script itself is fetched straight from this repo's GitHub raw URL, not from the relay:
curl -fsSL https://raw.githubusercontent.com/Livin21/flotilla-agent/main/beacon/beacon-install.sh | FLOTILLA_SECRET=<s> FLOTILLA_KEY=<k> bash -s -- <relay> <pairingID>
This installs flotilla-beacon as a systemd service listening on
127.0.0.1:8799 by default (override with FLOTILLA_LISTEN=host:port),
writes /etc/flotilla-beacon.conf (mode 600), and then creates the two
pieces of Proxmox notification config the beacon needs:
- a webhook target named
flotilla, pointed at the beacon's listen address, carryingAuthorization: Bearer <S>and the body template{"severity":{{ json severity }},"title":{{ json title }},"message":{{ json message }}}; - a matcher of the same name routing severities
warninganderrorto that target.
Both are required — PVE delivers nothing with only one of them — and both are
additive: PVE's stock default-matcher (everything → mail-to-root) is left
alone. Re-running the install command is safe (it rewrites config, binary and
unit, restarts the service, and recreates the target/matcher) — useful after a
re-pair, which rotates S and would otherwise leave the old target 401ing.
If the node isn't a Proxmox host, or pvesh fails, the install still finishes
and prints the exact values to enter by hand instead. Pass FLOTILLA_SKIP_PVE=1
to always configure it yourself. The full table of values is in
PROTOCOL.md, along with the pvesh commands.
Once configured, confirm the whole chain with
pvesh create /cluster/notifications/targets/flotilla/test. If nothing
arrives, journalctl -u flotilla-beacon will say whether the webhook was
rejected for a missing or wrong Authorization header.
The binary is downloaded from this repo's GitHub releases, which requires a
published release and this repo to be public — already a launch requirement
(the Unraid CA and Proxmox community-scripts both mandate open source). The
systemd unit is embedded in the installer rather than fetched, so the install
has exactly one network dependency. For testing against an unpublished
build — e.g. before this repo has ever cut a release — set
FLOTILLA_BEACON_BIN=/path/to/a/locally-built flotilla-beacon (a binary you
built yourself, e.g. via GOOS=linux go build -o flotilla-beacon ./cmd/flotilla-beacon): the script installs that file directly instead of
downloading one. Everything else about the install (config file, unit, systemd
enable/restart, PVE notification target) is unchanged.
flotilla-seal (standalone)
go build -o flotilla-seal ./cmd/flotilla-seal
./flotilla-seal keygen # 32 random bytes, base64url
echo '{"hello":"world"}' | ./flotilla-seal seal --key <b64url-key>
Reset / revoke
Resetting the pairing (Unraid's "Reset pairing" button, or re-running
beacon-install.sh for Proxmox after re-pairing) sends DELETE /v1/pairing to the relay with the old pairing's secret before generating
new pairing values, so the relay-side state (device tokens, heartbeat/alarm
state) for the old pairing is actually wiped rather than silently
orphaned. This is best-effort: a relay that's unreachable at that moment
never blocks the local reset (plugin/src/scripts/revoke.sh always exits 0,
bounded to a 5s timeout).
Self-hosting
Every sender's relay URL is a config value, not a hardcoded constant: the
Unraid plugin's settings page (RELAY), flotilla-beacon's conf file
(relay=), and the iOS app's own settings all point at a URL you control. To
point this repo's agents at your own relay you only need to change that URL —
nothing else in this repo is tied to a specific deployment. (Whether a
self-hosted relay can itself deliver push for the official App Store build of
Flotilla is a constraint of flotilla-relay, not of anything here — see that
repo's README.)
Development
go build ./...
go test ./... # cmd/flotilla-seal, cmd/flotilla-beacon, internal/sealbox
php test/*.php # settings.php unit tests (CSRF, cfg escaping, entity fixup, ...)
bash test/agent_test.sh # send-event.sh/heartbeat.sh/revoke.sh against a local capture relay
bash plugin/build.sh <version> # rebuilds plugin/flotilla-agent-<version>.txz from plugin/src
test/agent_test.sh needs jq, python3, and go on PATH; it spins up
test/capture_server.py as a fake relay and drives the real shell scripts
against it end-to-end (including timeout/black-hole behavior against an
unreachable relay).
License
MIT — see LICENSE.
Categories
Download Statistics
Downloads by Month
Related apps
Explore more like this
Explore allLinks
Details
https://raw.githubusercontent.com/Livin21/flotilla-agent/main/plugin/flotilla-agent.plg