Skip to main content
The ADOS Drone Agent runs on the companion computer of a drone or ground station. A fresh install is local: it talks to Mission Control directly over the LAN and never reaches out to a backend. Self-hosting changes one thing. You point the agent at your own Convex deployment and MQTT broker, so a Mission Control on any network can find and command the drone through your relay. This page assumes your Convex backend and broker are already up. See Mission Control and Convex and Self-hosting: MQTT broker.

Install the agent

The installer detects the board, applies board-specific overrides and brings up the services. No follow-up commands are needed for a working local agent. Every installer flag, including --pair, is listed on Drone Agent installation.
Pairing by code only reaches your backend once the agent knows where that backend lives. Set the server mode first (next section), or pair over the LAN from the Add-a-Node card in Mission Control, which needs no backend at all.

Switch the agent to self-hosted mode

The agent reads /etc/ados/config.yaml. Set server.mode to self_hosted, fill in server.self_hosted, and set pairing.convex_url to the same site origin.
pairing.convex_url wins. In self_hosted mode the relay falls back to server.self_hosted.url when pairing.convex_url is empty. Set both so every component agrees on one origin. Only cloud and self_hosted turn the relay on. local, a missing value or a misspelt mode all keep the agent local and silent.

Server keys

Pairing keys

The :3210 and :3211 origins

A self-hosted Convex deployment serves two origins on the same host: The agent talks to the site origin on :3211.
Point the agent at :3211, not :3210. A :3210 URL sends the register and heartbeat calls to the wrong origin, where they return 404. The setup and pairing writers rewrite a pasted :3210 URL to :3211, but a hand edit of config.yaml is used as written.

How the agent reaches the broker

The agent always dials the broker over TLS. There is no plaintext path.
  • With the default server.mqtt_transport: websockets, it connects to wss://<mqtt_broker>:<mqtt_port>/mqtt. A mqtt_port of 8883 is rewritten to 443, so put a TLS-terminating proxy or tunnel on 443 that forwards /mqtt to Mosquitto’s WebSocket listener on 9001.
  • With server.mqtt_transport: tcp, it speaks MQTT over TLS on mqtt_port. Add a TLS listener to Mosquitto (for example 8883 with certfile and keyfile) and set mqtt_port to it.
Every relay connection authenticates as ados-<deviceId> with the pairing key as the password, which is the same key the agent sends as X-ADOS-Key. There are no separate MQTT username, password or plaintext settings. The broker carries the MAVLink and MSP byte planes, WebRTC signaling, vision detections and plugin streams. Fleet status goes to Convex separately, as an HTTPS POST to /agent/status every 5 seconds. The topic list is on Cloud infrastructure.

Apply the change

After editing /etc/ados/config.yaml, restart the supervisor so the new server mode takes effect:
Confirm the agent picked up the mode and is reaching your backend:
If the agent does not appear, check journalctl -u ados-cloud -o json (or ados logs query if you enabled the logging store). A register or heartbeat call that lands on the wrong origin logs the URL it tried.

Server modes

Local mode is not a misconfiguration. On a single LAN bench or field setup you do not need self-hosting. Self-hosting is for cross-network access, where the agent and the GCS need a relay in between.
For the video path, see Self-hosting: video relay. Every port in the stack is on Self-hosting: ports and troubleshooting.

Next steps

MQTT broker

Stand up Mosquitto with per-device auth and the TLS front the agent dials.

Video relay

Play the drone’s stream in a browser through your own relay.
Last modified on October 11, 2026