Skip to content

Deploy to a host or Docker

The HOST platform runs a component on a bare host or in a plain Docker container, with no Greengrass Nucleus. It uses a dual-MQTT transport: the component connects to a local MQTT broker and, optionally, to AWS IoT Core at the same time. This is the path you use for local development, smoke tests, and standalone Docker deployments.

You select it at startup with --platform HOST. On HOST the SDK applies these profile defaults (any of which an explicit flag or config value overrides):

Setting Default on HOST
--transport MQTT (the dual-MQTT provider)
-c/--config source FILE
Metric target library default (local log)
Metric log path ./logs/{ComponentFullName}.metric.log
Identity the -t/--thing value, else the AWS_IOT_THING_NAME env var, else NOT_GREENGRASS

The dual-MQTT transport needs a broker for its local connection. The repo ships a shared EMQX broker that exposes plaintext MQTT on 1883 and mutual-TLS MQTT on 8883.

Terminal window
docker compose -f test-infra/compose.yaml up -d # EMQX: 1883 plaintext, 8883 mTLS
# ...or a throwaway broker:
docker run -d -p 1883:1883 emqx/emqx:latest

HOST/MQTT is configured by a messaging config JSON file, passed as the positional argument to --transport MQTT <messaging_config.json>. It has two brokers under messaging:

  • local (required) — the local broker. Fields: host, port, clientId, optional type, optional credentials.
  • northbound (optional) — a generic northbound MQTT broker. Fields: host or endpoint, port, clientId, optional credentials.

TLS is configured inside credentials: caPath (the CA to verify the broker) plus certPath and keyPath (the client cert/key for mutual TLS). For a plaintext local broker on 1883 you omit credentials entirely.

Where the file comes from differs per SDK. The Rust/TS scaffolds ship a ready-to-edit sample at test-configs/standalone-messaging.json (the minimal local-only form; type is ignored by Rust/TS). The Java/Python scaffolds do not include this file — you create ./standalone-messaging.json yourself, as the generated README instructs (“Provide an MQTT messaging-config JSON”). A full sample that sets type and includes a northbound block lives in the library repo at libs/java/standalone-messaging-sample.json / libs/python/standalone-messaging-sample.json — copy it and edit. Each running process must use a unique clientId.

Create ./standalone-messaging.json yourself (the Java scaffold does not ship it — copy libs/java/standalone-messaging-sample.json from the library repo). Full sample with an optional northbound connection:

{
"messaging": {
"local": {
"type": "mqtt",
"host": "localhost",
"port": 1883,
"clientId": "my-component-local"
},
"northbound": {
"endpoint": "xxxx-ats.iot.us-east-1.amazonaws.com",
"port": 8883,
"clientId": "my-component",
"credentials": {
"certPath": "creds/device.cert.pem",
"keyPath": "creds/device.private.key",
"caPath": "creds/root-CA.crt"
}
}
}
}

Build the component, then launch it with --platform HOST --transport MQTT <messaging_config.json>, the component config via -c FILE <config.json>, and the IoT Thing name via -t. The CLI contract is identical across SDKs; only the build tool and the launcher binary differ.

Terminal window
mvn clean package
java -jar target/<jar>-1.0.0.jar \
--platform HOST --transport MQTT ./standalone-messaging.json \
-c FILE test-configs/<Component>.json -t my-thing-name

Add --enable-native-access=ALL-UNNAMED to the java command only when the component uses the streaming subsystem (which loads the native edgestreamlog binding via the FFM API).

A running component publishes its state keepalive on the Unified Namespace every 5 seconds by default. Subscribe to the state wildcard with any MQTT client (for example MQTTX or mosquitto_sub) pointed at your local broker:

Terminal window
mosquitto_sub -h localhost -p 1883 -t 'ecv1/+/+/state' -t 'ecv1/+/+/+/state' -v

You should see periodic state envelopes on ecv1/<device>/<component>/state with body {"status":"RUNNING","uptimeSecs":n} — the device and component are also carried in each message’s identity element. From there, use the Messaging guide to publish/subscribe on your own topics, and the Configuration guide to drive behavior from the -c FILE config.

The northbound block makes the component connect to a second MQTT broker in addition to the local broker. AWS IoT Core is one valid northbound broker, but k8s and standalone deployments can point this at any MQTT broker.

  • host or endpoint — the northbound broker host, such as an AWS IoT Core ATS endpoint.
  • credentials.caPath — enables TLS and verifies the broker certificate.
  • credentials.certPath / credentials.keyPath — optional client certificate and private key for mutual TLS.

Provision a Thing, certificate, and policy in AWS IoT, then point certPath/keyPath/caPath at the downloaded files (paths are resolved relative to the working directory). Omit the whole northbound block to run purely against the local broker.

There is no dedicated bare-host Dockerfile in the templates. The scaffolding CLI generates a Dockerfile only when Kubernetes is a selected target (it is gated behind --platforms KUBERNETES), and that image’s entrypoint runs with no platform arguments so it can auto-detect the platform at runtime. See Deploy to Kubernetes for that image and its build flow.

To run a component in a container on a plain Docker host (no Kubernetes), the practical options are:

  • Run the built artifact directly on the host (the build and run commands above), which is the documented HOST path.
  • Reuse the Kubernetes Dockerfile as a base image but override the entrypoint to pass --platform HOST --transport MQTT <messaging_config.json> -c FILE <config.json> -t <thing>, and mount your messaging config and component config into the container.

When the platform is left as auto (the default) outside Kubernetes and without Greengrass signals, the resolver falls back to HOST. A bare-host container therefore still needs its broker and config supplied — either as the --transport MQTT <path> payload or through the active config source.