Skip to content

Node-RED Environment Variables Setup

Overview

Node-RED is now configured to load environment variables for MQTT and other settings from a nodered.env file. Environment variables can come from two sources:

  1. Systemd Environment File (/home/pi/.node-red/environment)
  2. Loaded automatically by the systemd service
  3. Used for production deployments
  4. Lower precedence for overrides

  5. Dotenv File (/home/pi/.node-red/nodered.env)

  6. Loaded explicitly by settings.js via dotenv package
  7. Used for development/testing and overrides
  8. Higher precedence - overrides systemd variables

Environment Variables

MQTT Configuration

These variables are used to configure the MQTT client connection for Node-RED flows:

# MQTT Broker Connection
MQTT_BROKER=mqtts.tagai.xyz
MQTT_PORT=8883
MQTT_DEVICE_ID=rpi-staging-1883c404a130

# MQTT mTLS Certificates (paths)
MQTT_CERT_PATH=/home/pi/.node-red/mqtt/client.crt
MQTT_KEY_PATH=/home/pi/.node-red/mqtt/client.key
MQTT_CA_PATH=/home/pi/.node-red/mqtt/ca.crt

Node-RED Configuration

# Node-RED Server
NODE_RED_PORT=1880
NODE_RED_ENABLE_PROJECTS=true
NODE_RED_CREDENTIAL_SECRET=tagaitechteam
NODE_RED_USER_DIR=/home/pi/.node-red

# Device Identity
DEVICE_ID=rpi-staging-1883c404a130
TZ=Europe/Vilnius

Optional: Email Configuration

# Email Server (for email nodes in flows)
EMAIL_SERVER=smtp.gmail.com
EMAIL_PORT=587
EMAIL_SECURE=false
EMAIL_USER=your-email@example.com
EMAIL_PASSWORD=your-app-password

How It Works

1. Loading Order

When Node-RED starts:

1. systemd loads EnvironmentFile=/home/pi/.node-red/environment
   ↓
2. Node-RED process starts with these variables
   ↓
3. settings.js executes and loads /home/pi/.node-red/nodered.env via dotenv
   ↓
4. Dotenv variables override any systemd variables with the same name
   ↓
5. settings.js reads process.env.MQTT_* variables and passes to functionGlobalContext
   ↓
6. Flows access via: context.global.get('mqtt').broker, etc.

2. Accessing in Flows

In Node-RED flows, access the MQTT configuration via function nodes:

// Get MQTT configuration from global context
const mqtt = context.global.get('mqtt');

// Access individual settings
const broker = mqtt.broker;        // e.g., "mqtts.tagai.xyz"
const port = mqtt.port;            // e.g., 8883
const deviceId = mqtt.deviceId;    // e.g., "rpi-staging-1883c404a130"
const certPath = mqtt.certPath;    // e.g., "/home/pi/.node-red/mqtt/client.crt"
const keyPath = mqtt.keyPath;      // e.g., "/home/pi/.node-red/mqtt/client.key"
const caPath = mqtt.caPath;        // e.g., "/home/pi/.node-red/mqtt/ca.crt"

3. systemd Integration

The Node-RED systemd service is configured to load the environment file:

[Service]
EnvironmentFile=-/home/pi/.node-red/environment

The - prefix means the file is optional - service starts even if file is missing.

Deployment with Ansible

The Ansible playbook automatically:

  1. Installs dotenv package

    npm install -g dotenv
    

  2. Creates systemd environment file from template nodered-env.j2

  3. Deployed to: /home/pi/.node-red/environment
  4. Variables: MQTT_, NODE_RED_, DEVICE_ID, TZ

  5. Creates nodered.env file from template nodered-dotenv.j2

  6. Deployed to: /home/pi/.node-red/nodered.env
  7. Same variables as environment file

  8. Verifies settings.js uses the dotenv loading code

Running Ansible Provisioning

# Provision single device
ansible-playbook playbooks/provision-nodered-complete.yml \
  -i inventory/production/hosts.yml \
  -l rpi-staging-1883c404a130

# Provision multiple devices
ansible-playbook playbooks/provision-nodered-complete.yml \
  -i inventory/production/hosts.yml \
  -l staging

# Force environment update (without full provisioning)
ansible-playbook playbooks/update-nodered-settings.yml \
  -i inventory/production/hosts.yml \
  -l rpi-staging-1883c404a130

Manual Testing

1. Check Environment Variables Are Loaded

# SSH to the Raspberry Pi
ssh pi@rpi-staging-1883c404a130.tagai.uk

# Check systemd environment file
cat ~/.node-red/environment

# Check nodered.env file
cat ~/.node-red/nodered.env

# Check what systemd loaded
systemctl show --environment nodered | grep MQTT

2. Check Node-RED Service Started Correctly

# Check service status
systemctl status nodered

# View service logs
journalctl -u nodered -f

# Look for nodered.env loading log message
journalctl -u nodered | grep "Loaded Node-RED env"

3. Verify in Node-RED

Via Node-RED function node:

// Test accessing global MQTT config
const mqtt = context.global.get('mqtt');
node.warn(JSON.stringify(mqtt, null, 2));

The debug output should show:

{
  "broker": "mqtts.tagai.xyz",
  "port": 8883,
  "deviceId": "rpi-staging-1883c404a130",
  "certPath": "/home/pi/.node-red/mqtt/client.crt",
  "keyPath": "/home/pi/.node-red/mqtt/client.key",
  "caPath": "/home/pi/.node-red/mqtt/ca.crt"
}

Troubleshooting

Environment Variables Not Loaded

Problem: MQTT settings not reflecting in Node-RED flows

Check: 1. Is nodered.env file present?

ls -la ~/.node-red/nodered.env

  1. Does it have correct permissions?

    # Should be readable by pi user
    ls -la ~/.node-red/nodered.env
    

  2. Did Node-RED load it? Check logs:

    journalctl -u nodered | grep -i "env\|mqtt"
    

Solution: - Restart Node-RED: sudo systemctl restart nodered - Verify nodered.env file syntax (should be KEY=VALUE format) - Check Ansible deployed it correctly

Dotenv Module Not Found

Error: Cannot find module 'dotenv'

Solution:

# Install globally
sudo npm install -g dotenv

# Or reinstall Node-RED with Ansible
ansible-playbook playbooks/provision-nodered-complete.yml \
  -i inventory/production/hosts.yml \
  -l <device>

Environment File Not Readable

Error: Permission denied when reading .env

Solution:

# Fix permissions
sudo chown pi:pi ~/.node-red/nodered.env
chmod 644 ~/.node-red/nodered.env

Ansible Templates

nodered-env.j2 (systemd environment file)

Location: ansible/roles/node_red/templates/nodered-env.j2

Used to generate: /home/pi/.node-red/environment

Includes: - MQTT broker and port settings - MQTT client certificate paths - Node-RED configuration - Optional email settings - Device identity and timezone

nodered-dotenv.j2 (dotenv nodered.env file)

Location: ansible/roles/node_red/templates/nodered-dotenv.j2

Used to generate: /home/pi/.node-red/nodered.env

Same variables as systemd environment file but in dotenv format.

Variable Reference

From group_vars/all/nodered.yml

These variables are used in Ansible templates:

node_red_port: 1880
node_red_project_encryption_key: "tagaitechteam"
mqtt_broker: "mqtts.tagai.xyz"
mqtt_broker_port: 8883
node_red_email_enabled: false
# ... other variables

Device-Specific Variables

From inventory host_vars: - inventory_hostname → Device name (e.g., rpi-staging-1883c404a130) - ansible_user → SSH user (e.g., pi)

Next Steps

  1. Optional: Add custom variables to Ansible templates for your specific needs
  2. Test locally on a staging device before production rollout
  3. Update inventory if using different MQTT broker addresses per environment
  4. Review flows to use context.global.get('mqtt') instead of hardcoded values

References