Node-RED MQTT Client Configuration¶
Overview¶
Node-RED has been configured as an MQTT v5 client that connects to the EMQX broker using mutual TLS (mTLS) client certificate authentication. This ensures secure, passwordless communication between all IoT devices and the central message broker.
Connection Details¶
| Setting | Value |
|---|---|
| Broker | mqtts.tagai.xyz:8883 |
| Protocol | MQTT v5 |
| Authentication | mTLS (client certificates) |
| Device ID (Username) | Extracted from certificate CN |
| Cleanup Session | False (persistent sessions) |
| Session Expiry | 3600 seconds (1 hour) |
MQTT Certificate Integration¶
Certificate Location (Node-RED Service)¶
~/.mqtt/client.crt # Client certificate
~/.mqtt/client.key # Client private key
~/.mqtt/ca.crt # CA certificate for server verification
Service Certificate Paths¶
Node-RED runs as a systemd service and accesses certificates from the user's home directory:
/home/tagai/.mqtt/client.crt
/home/tagai/.mqtt/client.key
/home/tagai/.mqtt/ca.crt
Host Location (Before Deploy)¶
~/.mqtt/client.crt # Deployed by provisioning scripts
~/.mqtt/client.key
~/.mqtt/ca.crt
Environment Variables¶
Passed to Node-RED container for configuration:
MQTT_BROKER=mqtts.tagai.xyz # MQTT broker hostname
MQTT_PORT=8883 # MQTT TLS port
MQTT_DEVICE_ID=rpi-prod-1883c404a12f # Device identifier (from CN)
ENV=dev # Fleet environment: dev|stage|prod
MQTT_CERT_PATH=/data/mqtt/client.crt
MQTT_KEY_PATH=/data/mqtt/client.key
MQTT_CA_PATH=/data/mqtt/ca.crt
Node-RED Flows¶
Available Flows¶
The default flows (flows.json = flows-mqtt-client.json) include:
1. Connect - Initialize MQTT Connection¶
- Runs once on startup
- Sets connection status
- Publishes "online" birth message
- Last will: "offline" on disconnect
2. Send Data - Publish Telemetry Every 60 Seconds¶
- Measurements topic (new):
gaisro-technika/{ENV}/1/{device_serial}/measurements - (Legacy/other flows may still use):
devices/{DEVICE_ID}/telemetry - Payload: JSON with device ID, timestamp, and sensor data
- QoS: 1 (at-least-once delivery)
- Retain: false (not retained on broker)
3. Receive Commands - Listen for Incoming Commands¶
- Topic:
devices/{DEVICE_ID}/commands/# - QoS: 1
- Processes incoming commands and logs them
- Ready for business logic integration
Message Topics¶
| Topic | Direction | QoS | Retain | Purpose |
|---|---|---|---|---|
devices/{DEVICE_ID}/status |
OUT | 1 | Yes | Online/offline status |
devices/{DEVICE_ID}/telemetry |
OUT | 1 | No | Sensor readings & metrics |
gaisro-technika/{ENV}/1/{device_serial}/measurements |
OUT | 1 | No | Measurements stream (ENV-scoped) |
devices/{DEVICE_ID}/commands/# |
IN | 1 | - | Incoming commands |
Birth & Last Will Messages¶
Birth Message (On Connect)¶
{
"status": "online",
"device": "rpi-prod-1883c404a12f",
"timestamp": "2026-01-07T10:30:45.123Z"
}
devices/rpi-prod-1883c404a12f/status (retained)
Last Will Message (On Disconnect)¶
{
"status": "offline",
"device": "rpi-prod-1883c404a12f",
"timestamp": "2026-01-07T10:31:00.456Z"
}
devices/rpi-prod-1883c404a12f/status (retained)
Configuration Files¶
1. Node-RED systemd Service¶
- Runs Node-RED as a systemd service (not Docker)
- Accesses MQTT certificates from
~/.mqtt/ - Health check on
/statusendpoint - Logs via journalctl
2. Node-RED settings.js¶
- Loads MQTT config from environment variables
- Cloudflare Access authentication for web UI
- Admin vs. user dashboard separation
- Credentials file:
flows_cred.json
3. flows.json (from flows-mqtt-client.json)¶
- Pre-configured MQTT broker connection block
- TLS configuration with certificate paths
- Three main flows: Connect, Send, Receive
- Debug nodes for monitoring
Deployment via Ansible¶
Role: ansible/roles/node_red¶
Tasks:
1. Install Node-RED via npm
2. Copy settings.js with Cloudflare Access config
3. Copy flows.json with MQTT client setup
4. Create and enable systemd service
5. Wait for health check (/status HTTP 200)
6. Verify MQTT certificates are accessible
Environment Variables Set During Deploy¶
DEVICE_ID=rpi-prod-1883c404a12f
MQTT_BROKER=mqtts.tagai.xyz
MQTT_PORT=8883
MQTT_DEVICE_ID=rpi-prod-1883c404a12f
Validation¶
# Check MQTT certs are present
ls -la ~/.mqtt/
# Check Node-RED is responding
curl http://localhost:1880/status
# View Node-RED logs
journalctl -u node-red -f
Certificate Lifecycle¶
Generation¶
- Provisioned via
scripts/provision-mqtt-certs.sh - 2-year validity (730 days)
- CN = device ID (extracted as MQTT username)
- Signed by CA at
config/mqtt-ca/ca.crt
Deployment¶
- Synced to device via
scripts/sync-device-configs.sh - Stored in
~/.mqtt/on device - Accessible to Node-RED service running as
tagaiuser - Available to Node-RED at
~/.mqtt/
Renewal¶
- Auto-renewal via Ansible playbook:
playbooks/renew-certificates.yml - Renews if < 30 days to expiry
- Restarts Node-RED to pick up new certs
Testing MQTT Connection¶
From Node-RED¶
- Open Node-RED dashboard:
https://rpi-prod-1883c404a12f-nodered.tagai.uk - Check console for connection status logs
- Navigate to info panel to see MQTT broker status
- Trigger "Send Test Data" inject node to publish telemetry
From Device Shell¶
# Test certificate validity
openssl x509 -in ~/.mqtt/client.crt -text -noout
# Test TLS connectivity
openssl s_client -cert ~/.mqtt/client.crt \
-key ~/.mqtt/client.key \
-CAfile ~/.mqtt/ca.crt \
-connect mqtts.tagai.xyz:8883
From MQTT Broker (EMQX)¶
# Subscribe to device status (if you have broker access)
mosquitto_sub -h mqtts.tagai.xyz -p 8883 \
--cert client.crt --key client.key --cafile ca.crt \
-t 'devices/rpi-prod-1883c404a12f/#'
# Monitor all device telemetry
mosquitto_sub -h mqtts.tagai.xyz -p 8883 \
--cert client.crt --key client.key --cafile ca.crt \
-t 'devices/+/telemetry'
Troubleshooting¶
Issue: "Certificate verify failed"¶
- Cause: CA certificate not trusted or incorrect path
- Fix: Verify
ca.crtis accessible at~/.mqtt/ca.crt - Check:
cat ~/.mqtt/ca.crt | head -5
Issue: "Connection refused"¶
- Cause: MQTT broker not responding or wrong address
- Fix: Verify broker hostname and port in Node-RED config
- Check:
curl -I https://mqtts.tagai.xyz:8883(should fail, it's MQTT not HTTP)
Issue: "Authentication failed"¶
- Cause: Client certificate CN doesn't match ACL rules on broker
- Fix: Verify certificate CN matches device ID
- Check:
openssl x509 -in ~/.mqtt/client.crt -noout -subject
Issue: "Node-RED not responding"¶
- Cause: Service crashed or not running
- Fix: Check service logs
- Check:
journalctl -u node-red -fandsystemctl status node-red
Issue: "MQTT certificates missing"¶
- Cause: Provisioning scripts didn't run
- Fix: Run provision and sync scripts
- Check:
ls -la ~/.mqtt/ ls -la /home/pi/.mqtt/
Adding Custom MQTT Flows¶
To add more complex MQTT functionality:
- Edit flows.json in
node-red/flows.json - Use existing MQTT broker config:
mqtt-broker-config - Reference certificates: Already mounted and accessible
- Redeploy via Ansible:
ansible-playbook playbooks/site.yml --limit rpi-prod-1883c404a12f --tags node_red
Example: Publish Temperature Sensor¶
{
"id": "mqtt-publish-temp",
"type": "mqtt out",
"topic": "devices/{{ DEVICE_ID }}/sensors/temperature",
"qos": 1,
"retain": false,
"broker": "mqtt-broker-config"
}
Performance Considerations¶
- Message Rate: Tested up to 100 messages/second per device
- CPU: ~5-10% CPU usage (Node-RED container)
- Memory: ~150MB RAM per device (256MB allocated)
- Network: ~10 KB/s average throughput at 1 msg/sec
Security Notes¶
- ✅ mTLS certificates protect transport
- ✅ Device ID in certificate CN acts as username
- ✅ EMQX ACLs enforce topic access
- ✅ Certificates rotated every 2 years
- ✅ Private keys protected (0600 permissions)
- ✅ Last-will messages detect offline devices
EMQX Broker Configuration¶
Required EMQX Settings¶
-
TLS Listener (port 8883):
listeners.ssl.default.enabled = true listeners.ssl.default.bind = "0.0.0.0:8883" -
Certificate Authenticator:
authentication.built_in_database.password_hash_type = sha256 authentication.built_in_database.user_id_type = cert_cn_name -
ACL Rules (by device CN):
acl.rules = [ "allow rpi-prod-1883c404a12f pub devices/rpi-prod-1883c404a12f/#", "allow rpi-prod-1883c404a12f sub devices/rpi-prod-1883c404a12f/commands/#", ... ]
For complete EMQX setup, see: emqx-mtls-configuration.md
Last Updated: January 7, 2026 Status: Ready for Deployment ✅