On-router, off-router, fleet#
The agent is one binary that talks to a router over that router's HTTP API. Where it runs is a deployment decision, and there are three answers. On the router is the product: the agent, the web UI and the router in one image. Off the router is the development path, unsupported, and it exists because the agent has no need to be on the box it manages. Fleet is one agent holding credentials for several routers, gated on a licence feature. Almost every support question that begins "the address in the documentation does not work" is really a question about which of these you are running.
The two install paths, side by side#
| Wheelhouse OS appliance | Developer install | |
|---|---|---|
| How it arrives | The bootable image, or the .deb on a router | A checkout, built or copied onto a host |
| Web UI | https://<router>:8443 | https://127.0.0.1:8090 |
| Binary | /usr/bin/wheelhouse-agent | /opt/wheelhouse/wheelhouse-agent |
| UI assets | /usr/share/wheelhouse/ui | /opt/wheelhouse/ui |
| systemd unit | packaging/wheelhouse-agent.service, installed by the package | install/wheelhouse-agent.service, copied by hand |
| Secrets | /config/wheelhouse/ | /etc/wheelhouse/ |
| Agent state | /config/wheelhouse/state.json | /config/wheelhouse/state.json |
| Supported | yes | no — development and lab use only |
Anything in this documentation naming port 8090 or /etc/wheelhouse is the developer
path. On an appliance, read 8443 and /config/wheelhouse
(docs/deploy.md).
A. On the router — the product#
The .deb installs the agent, the UI, a systemd unit binding 0.0.0.0:8443 with a
self-signed certificate, a first-boot unit that mints the agent's own router API key
and pins the router's HTTPS API to loopback, and a console-banner timer that prints
the web UI address above every login. The unit's ExecStart names every secret as a
file, never on the command line, because ExecStart is world-readable through
/proc — and the agent refuses to read a secret file that is group- or world-readable.
--api-url https://127.0.0.1
--api-key-file /config/wheelhouse/api-key
--admin-token-file /config/wheelhouse/admin-token
--license-key-file /config/wheelhouse/license-key
--addr 0.0.0.0:8443
--tls-self-signed
--ui-dir /usr/share/wheelhouse/ui
--data-dir /config/wheelhouseThe unit is also where the process is confined: NoNewPrivileges,
ProtectSystem=strict with /config as the only writable path, PrivateTmp, the
kernel-tunable and module protections, a MemoryMax of 200 MB and a CPUQuota of
300%. The memory ceiling is load-bearing rather than decorative — the agent buffers a
request body before the rate limiter sees it, and one anonymous POST was measured
taking it to 2.2 GB, so the kernel killing it and systemd restarting it beats the box
going to swap.
Everything works in this mode. It is the only mode the documentation describes unless it says otherwise.
B. Off the router — development and lab only#
install/install.sh puts the binary and the UI under /opt/wheelhouse, keeps secrets
in /etc/wheelhouse, and binds 127.0.0.1:8090. The agent points at a router
somewhere else with --api-url and that router's API key. It is genuinely useful —
zero-risk development against a lab router — and it is not the product.
./install/install.sh --api-url https://192.0.2.1 --api-key "$(cat /path/to/key)"
journalctl -u wheelhouse-agent | grep "shown once" # the generated admin passwordTwo things behave differently, and both say so rather than pretending:
- App volume directories cannot be created.
POST /api/apps/prepareanswerson_router: falseand hands back the exactmkdir -pcommand to run on the router instead (agent/apps.go,handleAppPrepare). - App health probes report nothing rather than something false. The agent has no
route to the router's container bridge, so a failed probe would say nothing about the
app. It reports
healthy: nullwith not probed — this agent runs off-router (docs/apps.md).
install.sh keeps the previous binary beside the new one, health-checks after a
restart and restores the old one if the check fails. That is a lab convenience, not
how the product upgrades: on an appliance an agent upgrade is a .deb replacement and
a full upgrade is an image change.
There is also --demo, which starts the agent with no router credentials at all.
Every router read then fails until --api-url and --api-key are supplied. It exists
so the process can be started for UI work; it is not a demonstration mode with fake
data.
C. Fleet — one agent, several routers#
--fleet-config <file> names a JSON file of routers. Each entry holds an id, a
label, a url and that router's API key
(agent/fleet.go):
{"routers": [
{"id": "lon-edge", "label": "London edge", "url": "https://192.0.2.1", "key": "..."},
{"id": "ams-edge", "label": "Amsterdam edge", "url": "https://198.51.100.1", "key": "..."}
]}Each entry is a router API key, which is root-equivalent on that router, so the file
is a credential store and gets the same treatment as every other secret the agent
reads: it must be mode 0600 or the agent refuses it. An entry with an empty id is
refused because fleet routes are addressed by id, and a duplicate id is refused
because it would silently replace the first client while both still appeared in the
status list.
What fleet mode offers:
| Route | What it does |
|---|---|
GET /api/fleet | Every router's status, checked concurrently: online, version, or the error. A bad key answers HTTP 200 with an error field on this platform, so that case is treated as offline rather than as an online router with an unknown version. |
GET /api/fleet/{id}/config | That router's configuration, redacted below admin |
GET /api/fleet/{id}/version | That router's version |
POST /api/fleet/{id}/configure | Apply operations to that router — audited, naming the actor, the router id and the outcome |
Fleet is a licence feature, not a second key: the routes are wrapped in
requireFeature("fleet", …) and answer 402 with the fleet feature is not part of this
licence's plan without it. The fleet file loads regardless of the licence; the routes
are what is gated.
Choosing#
- Buying and running a router: A, and nothing here applies to you.
- Developing against a lab router, or driving a router you cannot install on: B, knowing it is unsupported.
- Watching several routers from one place: A on each, plus C on one of them or on a separate host.
See also#
- What the agent asks the router — the API relationship itself.
- Apps are configuration — the two off-router differences.
- What the licence gates — the
fleetfeature. - The developer install — the lab path, step by step.
- Agent flags — every flag named above.
- The agent's files — what lives in each directory.
Checked against#
docs/deploy.md ·
agent/main.go ·
agent/fleet.go ·
agent/apps.go ·
packaging/wheelhouse-agent.service ·
install/wheelhouse-agent.service ·
install/install.sh ·
docs/apps.md ·
PLAN.md §5