Feed gateway

One feed out. Nothing in.

A partner, an agency or a client sometimes needs to watch one mission: the live picture, the positions, nothing else. The feed gateway is a separate tool for exactly that. A gateway inside the fleet takes one feed off the multicast tree and publishes it outward to a feed server; a viewer opens a link in a browser, with a token that is theirs, for exactly the feeds it names, until it expires or is revoked. The fleet listens on no port, the server never reaches the field, and the viewer never touches the network that carries the mission. It sits beside the network as its own package — a gateway app, a server package, a token issuer — and asks one thing of the network: a node that may receive and never send.

Shippedfeeds.nexusatlas.net, or your own server
Two modes Shipped

A subscriber that publishes, or a member that only listens.

Both modes run the same gateway app with the same configuration; the difference is what the host is to the fleet. Mode 1 is the quick share. Mode 2 is what is offered when something is shared with outsiders for a season.

Mode 1 — an existing subscriber publishes out

A node that already subscribes to the group — typically a ground-station laptop with an internet uplink — runs the gateway app beside the daemon. The app reads the group off the atlas interface and publishes it. Nothing changes in the fleet: no new record, no new link. Its limit is that this laptop is a full member, often an operator or a config author, so the public side now touches a machine that can author and send.

INSIDE THE FLEET · THE MULTICAST TREE Camera node writes the group Relay one copy on the trunk Ground station subscriber · gateway app also an operator: a full member MODE 1 · AN EXISTING SUBSCRIBER PUBLISHES OUT OUTBOUND ONLY Feed server feeds.nexusatlas.net · or yours Browser Browser one token each one uplink stream per feed, however many viewers · the fleet opens no port · the server never reaches the gateway
INSIDEa subscriber that already receives the group runs the gateway app
OUTone outbound stream per feed to the feed server; the fleet opens no port
VIEWERSa browser each, a token each, for the feeds it names

Mode 2 — a dedicated read-only member with two paths

A separate host at the site — a small box or a VM — joins the fleet with its own record, flagged sink: it may subscribe and receive, and it may not send data into the fleet, relay, or author anything. It keeps links to at least two fleet nodes, two radios or a radio and a cable, so the tree reaches it by two paths; when its tree parent dies the tree re-roots through the other link, and the viewer sees one re-root, not a dead feed. Its second network leg is the internet, the host forwards nothing between the two legs, and only the gateway app bridges, at the application layer, outward. With [multicast] redundant_parents = 2 the gateway asks for a redundant last hop: a second neighbour that already carries the stream — the source, or a node on another subscriber's path — forks one extra copy to the gateway, the dedup window drops whichever copy comes second, and the only extra copy anywhere is on that one link. Losing the tree parent then costs no gap at all. If the public side is ever compromised, the attacker holds a node that can read one group and nothing else; revoking it is one fleet revoke and touches no operational node.

INSIDE THE FLEET Camera node writes the group Relay A tree parent Relay B second path · 2nd parent Gateway host sink = true · two links reads the group · sends nothing a packet it originates is dropped, counted MODE 2 · A DEDICATED READ-ONLY MEMBER OUTBOUND ONLY Feed server public hostname · real certificate Browser Browser one token each redundant_parents = 2: a second neighbour that already carries the stream forks one extra copy; the duplicate is dropped, a dead parent costs no gap
THE HOSTits own record, sink = true: receives, never sends, relays or signs
TWO PATHSlinks to two fleet nodes; a dead parent re-roots the tree, or with redundant_parents = 2 costs no gap
IF COMPROMISEDthe attacker reads one group; one revoke, no operational node touched
Direction Shipped

Push out, never let in.

The gateway makes outbound connections only: SRT with a passphrase for video (WHIP where the gateway's ffmpeg is 8 or newer), an outbound WSS for telemetry, HTTPS for the stop poll and the health report. No port is opened at the field, so there is no NAT to traverse and no exposed surface. Viewers connect to a public hostname with a real certificate, never to field equipment. The server never reaches the gateway: a stop is a message the gateway collects over its own outbound connection.

PUBLISH · SRT / WSS WHEP / LL-HLS / WSS Gateway no listening port Feed server auth hook on every connection Viewer a token per feed Token issuer the server's own · more by key the gateway polls for a stop · nothing reaches it uninvited no path toward the fleet a compromised server reaches nothing inside the fleet · a compromised sink reads one group and nothing else
GATEWAY → SERVERoutbound only: SRT and WSS; no port at the field
SERVER → VIEWERWHEP, LL-HLS or WSS behind a real certificate, a token on every connection
VIEWER → FLEETno path exists
Economy

One uplink stream per feed

Whatever the number of viewers, the gateway sends each feed once — the same economy the distribution tree gives inside the fleet, applied to the internet side. Fan-out, bandwidth and scaling are the server's; the field pays for one stream. One place holds the audit: every authorisation, kick, link issued, revocation and gateway connection is one line in the server's audit.jsonl. Publishing one feed costs the media server about 1 % of a core, each WebRTC viewer about 0.2 % more. Measured the tree ↗

Channels Shipped

The channel is chosen by the content.

Every channel is one that browsers and every language already speak. Video over a bare WebSocket is not offered: it needs custom player code on every viewer and gains nothing over WebRTC.

What is sharedChannelAdds, beyond the fleetWhy this one
Live video for people in a browserWebRTC · WHEP for playbackabout 0.3 s: glass to glass p50 285 ms, p95 300 ms, two mesh hops included MeasuredPlays in every browser and phone with nothing to install; "open this link" is the whole onboarding
Video for many viewers, or networks that allow only HTTPSLL-HLS2–6 sPasses any proxy, scales on a CDN, costs nothing per viewer at the field
Telemetry, positions, events — for partners building their own screensWSS carrying JSONabout 100 msOne socket, any language. A small document — position, heading, altitude, battery, link state — built by the gateway from the MAVLink it reads, not a passthrough
Raw MAVLinkWSS, read-only framesas aboveTelemetry only, and off unless a feed turns it on; anything a viewer sends is dropped and counted at the server and never reaches the mesh
A partner's own ground-control softwareRTSPabout 0.5 sWhat those tools expect; never offered to the public
Token

Short-lived, signed, only the feeds it names

A token is a compact JWS signed with Ed25519: the issuer, the viewer's id and name, the feeds it opens with the channels allowed on each (video, telemetry, positions, mavlink, recording, rtsp), issue time, expiry and a token id. The link is /view#t=<token>, or /watch/<feed>#t=<token> for one of its feeds: the token rides the URL fragment, which a browser never sends, so it reaches no server log. The server's auth hook verifies it on every connection. A link opens exactly the feeds it names, and nothing else — one feed or several, ticked by the operator in the console's share dialog, with the channels granted per feed. Tokens are bearer secrets, so links travel over HTTPS and expire short. An expired link is cut within about a second of its expiry. Measured

Issuer

The server's own issuer, and any other it trusts by key

Every feed server ships its issuer: a console behind a local password or your SSO proxy's user header — tick the feeds, name the viewer, set the expiry, copy the link — and feedgate-server issue to mint a link offline. The server trusts one or more issuer keys, its own and any other whose public key is listed, and polls each one's signed, sequence-numbered revocation list. The hosted instance runs the same issuer.

Kill switch

Per viewer, per feed, or everyone

Revoke one link, one viewer on a feed, or the whole feed; revoking a link cuts every feed it names. At the server's own issuer the cut is immediate; from another trusted issuer it lands within that issuer's poll interval, under two seconds with a two-second poll. Stop a feed and every viewer is cut, the publisher is refused and the gateway stops publishing. Measured

On the picture

Watermark and latency, always

The player draws the viewer's name, the feed and the time across the picture, always on. It is an overlay in the player, not burnt into the video: a technically able viewer can strip it from their own screen, and nobody else's. The player states the latency, so nobody tries to direct an aircraft from a shared feed. Recording on the server is optional per feed, off unless the feed turns it on, under the same tokens, with a stated retention.

Code

A code on the link, sent another way

A link can also require a code — a six-digit PIN the server generates, or a password the operator types. It is off by default. The code is shown once beside the link and is meant to travel over a different channel than the link itself. The server keeps only an Argon2id hash of it, never the code; after five wrong tries the viewer waits with a growing back-off, and after twenty failed codes the link locks until the operator resets it. The right code opens a session of 12 hours by default, never past the link's own expiry. Until then the media server, the telemetry socket and the token check all refuse the link.

Map

Where the mesh nodes are, only when both say so

With the operator's say-so on both the gateway and the link, the viewer also sees a map of the mesh nodes beside the picture: each node's name and last position with the age of its fix, and the vehicle's last two minutes of track. It takes share_positions = true on the feed's gateway and the positions channel on the link; both default off, so fleet positions are never shared by accident.

Several feeds

One screen, as many feeds as the link names

The viewer lists the link's feeds and composes them on one screen: side by side, picture-in-picture, a 2×2 grid, or the video beside the map.

Hosted

feeds.nexusatlas.net

A feed server with a public hostname and a public certificate, the package's own issuer and console. A CDN in front of HLS only when a feed needs hundreds of viewers.

Yours

Self-contained on your hardware

The server package runs inside a customer's own network — typically a large intranet — on hardware they own, with no dependency on our hosted services: one compose file brings up the media server, the auth hook, a local token issuer and the player page, and it needs nothing from nexusatlas.net. The hostname is yours, the certificate comes from your own CA, and the auth hook trusts the issuer key you choose.

Server

Mature media software, not ours

The media server is MediaMTX, a mature single-binary media server that takes SRT in — WHIP too — and serves WHEP, LL-HLS and RTSP out, with an authentication hook per request. The package writes no media code: it adds the auth hook, the issuer, the player page and the telemetry fan-out around it. On one small server WebRTC carries tens to low hundreds of viewers per feed at 2–4 Mbit/s; past that, HLS and a CDN.

sink

A member that may receive and never send

A node record may carry sink = true (fleet add-node --sink, fleet set-caps --sink true). Its peers accept its handshake, probes, adverts and multicast subscriptions — the control plane it needs to be reached — and drop every data packet that originates from it, unicast or multicast, at the first hop and at every later hop, counting caps.sink_dropped, exactly as classes are clamped per hop; they never choose it as a transit hop. The sink holds back what its own TUN offers as well, so it answers no ping through the tunnel: the host is managed over its own leg. The flag is in the signed record, so it holds fleet-wide and survives the gateway's restart, and the record compiles to no relay, no classes and no authorship whatever else it lists; a sink that tries to send is a journal line on its peers, not a risk. fleet check warns when a sink record also names classes, relaying, authorship or a fleet dashboard. Measured capability flags ↗

Two parents

A redundant last hop, for sinks only

The distribution tree uses one parent per source and group. A sink may ask for two with [multicast] redundant_parents = 2: a second neighbour that already carries the stream forks one extra copy, the stream arrives through both and the dedup window drops the duplicate. The extra copy rides only that neighbour's link to the sink, no node is pulled onto the tree for it, and the option is honoured only for a record flagged sink — every peer ignores it for anyone else. Cutting the gateway's tree link under live video: one parent freezes the picture for 1.4–2.4 s; two parents lose no packet and the largest frame gap is 67 ms at 25 fps. Measured the tree ↗

Boundaries

What the gateway is, and is not.

Stated in the same font size as everything above.

Readable inside

Multicast is read by every relay on its tree

Inside the fleet a group is protected hop by hop by the link encryption and read by every relay that forwards it; that is true with or without a gateway. A feed meant for outsiders should carry nothing the fleet would not show them.

Mode 1

A laptop is an operator

In mode 1 the public side touches a full member. That is fine for a demo and a quick share; for a season, use mode 2.

Not control

Nothing travels toward the fleet

No channel carries a command inward, raw MAVLink included. A partner who needs to fly the aircraft is a member of the fleet, not a viewer of a feed.

Tokens

Bearer secrets

Whoever holds a link holds the feeds it names until it expires or is revoked, unless the link also requires a code sent by another channel. Short expiries, revocation and the optional code are the controls; the watermark names the viewer on screen, as an overlay the viewer could strip from their own copy.

Latency

A view, not a cockpit

A shared feed is the fleet's latency plus the channel's. The player says so.

Second parent

Only a neighbour that already carries the stream

The redundant last hop uses a neighbour that is on the tree anyway — a subscriber, or a node on another subscriber's path. Atlas never pulls a node onto the tree for the gateway; with no such neighbour the gateway has one parent and a dead parent is a re-root.

Request an evaluation

Need to show one mission to someone outside it?

Tell us who watches, from where and for how long. The answer is a gateway placement, a channel per feed and a token policy — hosted, or inside your own network.