LAB
Lab stack — deploy, wire, and verify
This page is the operator record for running Zyvor OTA together with
Fleet, Nodra, Device Agent, and relay-edge on one Linux host. It is not
Minewing board qualification. Simulator OTA never flashes disks or calls
reboot(2). Generic QEMU RAUC lab HIL is documented separately in
HIL.md Track A.
Topology (updated 14–15 September 2026)¶
Host 80.79.5.173 (NLDW4-4-16-36, Ubuntu 24.04, user sus). Existing
services already occupied :8080 (Kryton), :18080 (Yard), :8081
(kairon-node), so lab ports were chosen to avoid collisions.
┌─────────────────────────────────────────┐
│ Zyvor Fleet :18090 (HTTPS, non-demo) │
│ ZYVOR_FLEET_DEMO=0 · OTA contract │
└──────────────┬──────────────────────────┘
assignment/events │ enroll + inventory
(device bearer) │
│ │
▼ ▼
zyvor-otad-demo fleet-agent
unix socket --device-agent-url :9188
simulator backend │
▼
zyvor-device-agent :9188
(lab-surrogate · not Minewing HIL)
nodra MQTT ──────────────────► nodrad :1883
│
▼
nodra-server :18447 (HTTPS)
relay-edge :18086 (HTTPS · EDGE_REQUIRE_AUTH=1)
| Product | Unit | Listen | Lab posture (signed where noted) |
|---|---|---|---|
| Zyvor Fleet | zyvor-fleet.service |
https://80.79.5.173:18090/ |
Non-demo ExecStart; TLS; ops + abbreviated WAN signed (Fleet ops-checklist.md) |
| Fleet site agent | zyvor-fleet-agent.service |
outbound to Fleet | Merged Device Agent inventory into site metadata |
| Nodra control plane | nodra-server.service |
https://80.79.5.173:18447/ |
Direct TLS (NODRA_TLS_*); ops + abbreviated WAN/disk signed |
| Nodra edge | nodrad.service |
MQTT 127.0.0.1:1883, HTTP 127.0.0.1:9091 |
Enrollment + MQTT ingress |
| Device Agent | zyvor-device-agent.service |
127.0.0.1:9188 |
Lab-surrogate only — minewing_claimable=false; not silicon HIL |
| OTA demo | zyvor-otad-demo.service |
/run/zyvor-ota-demo/agent.sock |
Signed Fleet assignment → committed (simulator) |
| OTA artifacts | zyvor-ota-demo-artifacts.service |
127.0.0.1:58897 |
Loopback bundle HTTP |
| relay-edge | relay-edge.service |
https://80.79.5.173:18086/ui/ |
auth_required=true; ops checklist signed |
Login (lab credentials — rotate before any shared use):
- Fleet:
admin@zyvor.local/ password from/etc/zyvor-fleet/fleet.env - Nodra:
admin/ password from/etc/nodra/nodra.env - relay-edge:
Authorization: Bearer <EDGE_API_TOKEN>(token not in git)
Deploy each product¶
From each repository, as sus with SSH keys and passwordless sudo:
# Fleet (avoid :8080 if something else already owns it)
./scripts/deploy-remote.sh 80.79.5.173 sus --key --port 18090
# Then ensure non-demo: ZYVOR_FLEET_DEMO=0 and no --demo on ExecStart
# Nodra (enable NODRA_TLS_CERT / NODRA_TLS_KEY for HTTPS)
./scripts/deploy-remote.sh 80.79.5.173 sus --port 18447
# relay-edge with auth required
EDGE_API_TOKEN=… EDGE_REQUIRE_AUTH=1 RELAY_EDGE_DIRECT=1 EDGE_PORT=18086 \
./scripts/deploy-remote.sh 80.79.5.173 sus
# OTA simulator smoke-deploy
./scripts/deploy-remote.sh 80.79.5.173 sus --key
# Device Agent (loopback / lab-surrogate — not Minewing claim)
./scripts/deploy-remote.sh sus@80.79.5.173 --no-ui
OTA smoke-deploy is documented in deploy/README.md.
It is not a RAUC board image.
Wire the stack¶
OTA requires HTTPS Fleet (fleet_url rejects http://). On the lab host:
- Issue a local TLS cert for Fleet (
subjectAltNameincludes127.0.0.1). - Restart
fleetdwith--tls-cert/--tls-key(without--demo). - Trust that cert as
fleet_caon the OTA agent. Thezyvor-ota-demouser must be able to read/etc/zyvor-ota-demo/agent.json(groupzyvor-ota-demo, mode640). POST /api/v1/ota/devicesas a Fleet admin; write the returned token to/etc/zyvor-ota-demo/fleet.token(mode640, groupzyvor-ota-demo).- Set
fleet_url,fleet_token_file,fleet_cain the demoagent.jsonand restartzyvor-otad-demo. PUT /api/v1/ota/devices/{id}/assignmentwith a signed envelope whosedevice_idmatches the agent,compatible/backendmatch the config, andsequenceis higher than the journal high-water mark.- Watch
otactl job JOB_IDthrough commit. Simulatorauto_rebootstill only flips the JSON slot file. DELETEthe assignment after the job is terminal so the agent does not keep re-fetching it.
Fleet ACK of OTA events is contiguous. A synthetic sequence: 1 posted
before a real job whose events start at 10 leaves a hole; the agent then
retains its outbox. Either start the Fleet device with ackedSequence equal
to the agent's last acknowledged sequence, or ACK locally with
otactl ack SEQUENCE only after Fleet has durably stored that prefix.
Enable Device Agent [nodra] enabled = true only after MQTT is listening,
then confirm nodra_connected=true. Treat Device Agent on this host as
lab-surrogate evidence only (device-agent HIL.md).
Helper: scripts/lab-wire-remote.sh
(run on the lab machine as sus). Bring-up sketch, not a production installer.
End-to-end result recorded on this host¶
| Path | Result |
|---|---|
| OTA selftest (deploy script) | 5/5 pass — signed install → reboot → commit (simulator) |
| Fleet → OTA signed job | committed (simulator slots) |
| Fleet event ACK | pending_events=0 after sequence alignment |
Fleet site lab-nldw4 |
online, Device Agent serial merged |
| Device Agent → Nodra MQTT | connected (surrogate host) |
| relay-edge with auth | auth_required=true; unauthorized /v1/* → 401 |
| Generic QEMU RAUC lab HIL | Complete — HIL.md Track A / qemu-lab/CHECKLIST.md |
What this lab does not prove¶
- Minewing GW1 r1 silicon / BSP image claims (
minewing_rauc_claimable). - Fleet or Nodra HA (single-writer products).
- Production public TLS identity (lab uses self-signed certs).
- relay-edge → live Relay Accept until Relay is deployed beside it (
:8443).
Continue with QUALIFICATION.md for the Minewing matrix and PRODUCTION.md for the factory-image path.