[![chat][gitter-badge]][gitter]
Magistrala IoT Agent is a communication, execution and software management agent for the Magistrala IoT platform. It runs on edge devices and bridges local services (Node-RED, terminal) with the Magistrala cloud over MQTT. A built-in web UI is included for local management.
git clone https://github.com/absmach/agent
cd agentBuild the binary:
make allThe binary is written to build/magistrala-agent.
The recommended way to run agent is with the provided Docker Compose stack, which also starts Node-RED, FluxMQ, and Mosquitto.
If you have a running Magistrala instance, create the required clients and channels:
export MG_PAT=<personal-access-token>
export MG_DOMAIN_ID=<domain-id>
make run_provisionThis creates the necessary Magistrala clients and channels, then writes the resulting IDs and configuration into docker/.env.
Alternatively, create a Client and Channel manually via the Magistrala UI or API, then edit docker/.env directly with the values:
MG_AGENT_MQTT_URL=ssl://messaging.example.com:8883
MG_AGENT_CLIENT_ID=<client-id>
MG_AGENT_CLIENT_SECRET=<client-secret>
MG_AGENT_DOMAIN_ID=<domain-id>
MG_AGENT_CHANNEL=<channel-id>make all && make dockers_devmake runStarts: Agent (:9999), Node-RED (:1880), Agent UI (:3000).
make stop
make clean_volumesA web-based management UI is included and served at http://localhost:3000. It provides:
- Configuration — view and save the agent config (
server,channels,mqtt,nodered,log) - Node-RED — ping, get state, fetch flows, deploy flows (replaces all running flows), and add a single flow tab (non-destructive) from a local JSON file
- Services — view registered heartbeat services
- Execute Command — run shell commands on the edge device and see terminal-style output
The UI is built with Elm and served via nginx as a Docker container.
To build the UI image:
make dockers_devStart FluxMQ (or use an existing Magistrala FluxMQ instance).
Start agent with environment variables:
MG_AGENT_MQTT_URL=mqtts://messaging.example.com:8883 \
MG_AGENT_MQTT_USERNAME=<client-id> \
MG_AGENT_MQTT_PASSWORD=<client-secret> \
MG_AGENT_CHANNEL=<channel-id> \
MG_AGENT_DOMAIN_ID=<domain-id> \
build/magistrala-agentAgent configuration is kept in config.toml if not otherwise specified with env var.
Example configuration:
[server]
port = "9999"
broker_url = "amqp://guest:guest@localhost:5682/"
[channels]
id = "<channel-id>"
[mqtt]
url = "mqtts://messaging.example.com:8883"
username = "<client-id>"
password = "<client-secret>"
qos = 0
retain = false
mtls = false
[nodered]
url = "http://localhost:1880/"
[log]
level = "info"Environment variables:
| Variable | Description | Default |
|---|---|---|
MG_AGENT_CONFIG_FILE |
Location of configuration file | config.toml |
MG_AGENT_LOG_LEVEL |
Log level | info |
MG_AGENT_HTTP_PORT |
Agent HTTP port | 9999 |
MG_AGENT_BROKER_URL |
FluxMQ (AMQP) broker URL | amqp://guest:guest@localhost:5682/ |
MG_AGENT_MQTT_URL |
MQTT broker URL | localhost:1883 |
MG_AGENT_MQTT_USERNAME |
MQTT username (Magistrala client ID) | |
MG_AGENT_MQTT_PASSWORD |
MQTT password (Magistrala client secret) | |
MG_AGENT_MQTT_SKIP_TLS |
Skip TLS verification for MQTT | true |
MG_AGENT_MQTT_MTLS |
Use mTLS for MQTT | false |
MG_AGENT_MQTT_CA |
CA certificate path for mTLS | ca.crt |
MG_AGENT_MQTT_QOS |
MQTT QoS level | 0 |
MG_AGENT_MQTT_RETAIN |
MQTT retain flag | false |
MG_AGENT_CHANNEL |
Channel ID (req/data/res subtopics) | |
MG_AGENT_DOMAIN_ID |
Magistrala domain ID | |
MG_AGENT_NODERED_URL |
Node-RED API URL | http://localhost:1880/ |
MG_AGENT_HEARTBEAT_INTERVAL |
Expected heartbeat interval | 30s |
MG_AGENT_TERMINAL_SESSION_TIMEOUT |
Terminal session timeout | 30s |
Agent subscribes to m/<domain-id>/c/<channel-id>/req.
All messages use SenML JSON array format:
[{"bn": "<uuid>:", "n": "<subsystem>", "vs": "<command>[,<args>]"}]The n field selects the subsystem. Supported subsystems:
n |
Description |
|---|---|
control |
Node-RED commands |
exec |
Execute a shell command |
config |
View or save agent config |
term |
Terminal session control |
nodered |
Node-RED flow management |
Commands are passed as a comma-separated string: command,arg1,arg2. Commands with no arguments work as-is:
# No-arg command
mosquitto_pub \
-h <mqtt-host> -p 8883 --capath /etc/ssl/certs \
-u <client-id> -P <client-secret> --id "cmd-$(date +%s)" \
-t "m/<domain-id>/c/<channel-id>/req" \
-m '[{"bn":"req-1:", "n":"exec", "vs":"pwd"}]'
# With arguments
mosquitto_pub \
-h <mqtt-host> -p 8883 --capath /etc/ssl/certs \
-u <client-id> -P <client-secret> --id "cmd-$(date +%s)" \
-t "m/<domain-id>/c/<channel-id>/req" \
-m '[{"bn":"req-1:", "n":"exec", "vs":"ls,-la"}]'Commands are executed via sh -c so shell builtins and pipelines are supported. Each invocation is stateless; use && to chain commands: ls,-la,/tmp,&&,cat,/etc/os-release.
mosquitto_pub \
-h <mqtt-host> -p 8883 --capath /etc/ssl/certs \
-u <client-id> -P <client-secret> --id "cmd-$(date +%s)" \
-t "m/<domain-id>/c/<channel-id>/req" \
-m '[{"bn":"req-1:", "n":"config", "vs":"view"}]'Responses are published to m/<domain-id>/c/<channel-id>/res.
Agent can manage Node-RED flows running on the same device. Flows can be deployed either via the Node-RED UI directly, via the agent's HTTP API (local), or remotely from the Magistrala cloud over MQTT.
First, base64-encode the flow JSON:
FLOWS=$(cat examples/nodered/speed-flow.json | base64 -w 0)Then send it to the agent. The agent decodes the flows, patches the MQTT client ID, and forwards them to Node-RED on its behalf:
curl -s -X POST http://localhost:9999/nodered \
-H 'Content-Type: application/json' \
-d "{\"command\":\"nodered-deploy\",\"flows\":\"$FLOWS\"}"Other commands (no flows field needed):
# Fetch current flows
curl -s -X POST http://localhost:9999/nodered \
-H 'Content-Type: application/json' \
-d '{"command":"nodered-flows"}'
# Ping Node-RED
curl -s -X POST http://localhost:9999/nodered \
-H 'Content-Type: application/json' \
-d '{"command":"nodered-ping"}'
# Get flow state
curl -s -X POST http://localhost:9999/nodered \
-H 'Content-Type: application/json' \
-d '{"command":"nodered-state"}'FLOWS=$(cat examples/nodered/speed-flow.json | base64 -w 0)
mosquitto_pub \
-h <mqtt-host> -p 8883 --capath /etc/ssl/certs \
-u <client-id> -P <client-secret> --id "deploy-$(date +%s)" \
-t "m/<domain-id>/c/<channel-id>/req" \
-m "[{\"bn\":\"req-1:\",\"n\":\"nodered\",\"vs\":\"nodered-deploy,$FLOWS\"}]"In both cases flows is the flow JSON base64-encoded. The agent automatically patches the MQTT clientid inside the deployed flows to <client-id>-nr to prevent Node-RED from conflicting with the agent's own MQTT session.
See docs/nodered.md for the full setup guide, Docker Compose stack, and provisioning instructions.
Services running on the same host can publish to heartbeat.<service-name>.<service-type> to register with the agent.
go run ./examples/publish/main.go -s amqp://guest:guest@localhost:5682/ heartbeat.myservice.sensor ""Check registered services:
curl -s http://localhost:9999/servicesAgent can push a config file for the Export service from cloud to gateway via MQTT:
mosquitto_pub \
-h <mqtt-host> -p 8883 --capath /etc/ssl/certs \
-u <client-id> -P <client-secret> --id "cfg-$(date +%s)" \
-t "m/<domain-id>/c/<channel-id>/req" \
-m "[{\"bn\":\"req-1:\", \"n\":\"config\", \"vs\":\"<config_file_path>,<file_content_base64>\"}]"Generate the base64 payload:
b, _ := toml.Marshal(export.Config)
payload := base64.StdEncoding.EncodeToString(b)