Skip to content

Deploy and configure Node-RED

How to remotely deploy Node-RED in production?


This how-to explains how qbee can deploy Node-RED applications to a fleet of distributed remote devices for production purposes. It allows headless setup and control of Node-RED on large numbers of devices. This provides an extremely powerful tool and we will only give some basic insights into what and how you can use this. This will enable you to gain very secure and granular control over your distributed SCADA, HVAC or operational technology (OT) deployments. will enable to distribute flows even to devices that are behind firewalls, NATs, mobile networks or other real industrial deployments. This allows to securely deploy flows from the lab to the real world into production. And yes, Node-RED is stable enough to run in production (and qbee is governing it while doing so). Here is an example use case of one of our customers. It is also possible to distribute the flows through the APIs and online services such as GitHub.

Tutorial how to install and configure Node-RED: and Node applications work extremely well together in production. In this tutorial we will focus on the following tasks:

  • install Node-RED properly on Debian systems (such as RPI)
  • get control over the settings
  • allow system wide credential access
  • enable automatic updates of flows on remote target devices
  • allow templating of Node-RED flow properties

This is all done on a Raspberry Pi (RPI) as this is widely available. But it will work on any other embedded Linux platforn as well.

Sign up for your 30 day free trial!

Additional tutorials for Node-RED

The following section explains how to get a clean and updated installation of Node-RED on your Raspberry Pi (RPI). It is strongly recommended to use the script below instead of relying on pre-delivered packages.

Creating a clean installation manually

Installing Node-RED on the Raspberry Pi manually

The easiest and most recommended way to get a working Node-RED installation is to follow the recipe on this page. If you have an installation from before just delete your .node-red directory as user pi. Then run the command form the web page: bash <(curl -sL

Completely headless and automated install of Node-RED on Debian systems such as Raspberry Pi

Installing Node-RED fully headless and automated

In production it is preferable to be able to install a complete Node-RED system automatically without any user interaction. qbee can do this for you and there is a detailed install Node-RED headless tutorial available on how to do this. This installs Node-RED headless on any Raspberry Pi or Debian based system. It is also relying on the script mentioned in the manual install.

Some basic information about how Node-RED works and how the settings.js, flows.json and flows_cred.json impact each other

There are three main files in a typical Node-RED installation. Usually they are in the hidden .node-red directory under the user account that runs Node-RED. The settings.js contains all relevant settings. This file is created the first time Node-RED is run as long as there is no file from before. In the standard settings.js most settings are commented out. So it makes sense to configure this according to your use case. If a standard setting.js is used and a flow is created and deployed that contains credentials two new files are created: The flows.json and flows_cred.json. This is not 100% correct as the standard settings will create a flows_YOUR-HOSTNAME.json and a flows_YOUR-HOSTNAME_cred.json. This can also be controlled through settings. The _cred.json file contains an encrypted version of the credentials (for example your MQTT user name and password). And here it can get a bit confusing: In a standard settings.js file there is no password defined. Therefore Node-RED will create its own and save it in .config.json after the first time a flow with credentials is deployed. This can cause problems if this is not getting deleted properly.

Properly define your credentials

When a credentialSecret is defined in settings.js AND Node-RED was restarted then new credentials can be defined and will be encrypted with the key from settings with the next deploy.

Why are my Node-RED credentials empty?

When no password is defined in settings.js and a flow with credentials is deployed Node-RED creates a secret key in .config.json. This key allows to decrypt flows_cred.json. But if the settings.js and the flows files are moved it is not possible to decrypt the credentials anymore. If configured correctly with a password in settings.js the .config.json should show an empty user entry at the end of the file. If there is an entry here (and you want to follow the instructions further) please delete the key. Another source of error is the ownership rights of the settings file. It seems that credentials only get decrypted if the settings.js file has the same ownership for group and user as the user running Node-RED. This means that for user pi it needs to look like this

16 -rw-r----- 1 pi pi 13444 Sep 7 15:16 settings.js

To correct this just call (the pi.pi doing the "change owner" both for user and group in one command)

chown pi.pi /home/pi/.node-red/settings.js

Creating a settings.js file that can be distributed to all devices

The first thing you want to do is to adjust your settings file. On Linux the settings.js file is copied from the /usr/lib/node-modules/node-red/ folder to your .node-red folder in your home directory when you start node-red, and there is no previous settings.js file present. This file contains a lot of options. Here we will only look at the ones that are relevant for describing our base use case. There are very good tutorials on the internet how to tweak and adjust additional settings. The settings file itself can also be explored in its latest version on github.

Where to get the settings.js file from?

We recommend to base your settings.js file on the one that you get from your version of node-red (the path defined above), but it should be compatible across versions as well.

Credentials and Node-RED - important to know

There is one setting in Node-RED called credentialSecret: "a-secret-key". Once you set this property, do not change it - doing so will prevent node-red from being able to decrypt your existing credentials and they will be lost. We circumvent this problem by playing out a defined settings.js with your password and the according flows_creds.json to all devices.

Let's get started. Please install Node-RED on your local development machine and start Node-RED. This can be done on any platform. Just make sure that you do not have a previously set key in .config.json (see warning above).

This will copy a settings.js file into your .node-red folder. Open this and edit the following items: Remove the trailing "//" to activate this the following. This basically removes the dependency of the device hostname out of the flow name and makes life easier.

//flowFile: 'flows.json',

Setting the secret key

The following change encrypts the credentials used in your blocks. This is very useful and this binds the settings.js together with the flows_cred.json. Please make sure you have restarted Node-RED.

Do the same with the following and insert your secret key.

//credentialSecret: "a-secret-key",

Thus this line changes into

credentialSecret: "my-personal-secret-key",

Then save this file again and restart Node-RED. Now it is time to fire up Node-RED and create a basic flow.

Creating a basic Node-RED flow file with MQTT credentials

We will build a very simple example. This is a weather station that outputs the weather as a string and sends it to a debug output and to a MQTT output node. An inject node, a function node and a debug node is needed for each. This is how the flow will look:


The complete flow can be seen here and be copied into your Node-RED editor:

    "id": "117f088e.84eb97",
    "type": "tab",
    "label": "Flow 1",
    "disabled": false,
    "info": ""
    "id": "d75ee7b0.0775c8",
    "type": "inject",
    "z": "117f088e.84eb97",
    "name": "weather",
    "props": [
        "p": "payload"
        "p": "topic",
        "vt": "str"
    "repeat": "10",
    "crontab": "",
    "once": true,
    "onceDelay": 0.1,
    "topic": "weather",
    "payload": "very good",
    "payloadType": "str",
    "x": 171.5,
    "y": 175,
    "wires": [
    "id": "d1e24e2f.b5a2",
    "type": "function",
    "z": "117f088e.84eb97",
    "name": "weather station",
    "func": "var payload = msg.payload;\n\nmsg.payload=\"The weather is \"+msg.payload;\n\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "x": 373.5,
    "y": 175,
    "wires": [
    "id": "e7b731c2.2f7f2",
    "type": "debug",
    "z": "117f088e.84eb97",
    "name": "",
    "active": true,
    "tosidebar": true,
    "console": false,
    "tostatus": false,
    "complete": "false",
    "x": 586.5,
    "y": 174,
    "wires": []
    "id": "ae91ac8a.7bf89",
    "type": "mqtt out",
    "z": "117f088e.84eb97",
    "name": "",
    "topic": "",
    "qos": "",
    "retain": "",
    "broker": "bcb17249.9cb7c",
    "x": 580,
    "y": 260,
    "wires": []
    "id": "bcb17249.9cb7c",
    "type": "mqtt-broker",
    "z": "",
    "name": "qbee",
    "broker": "",
    "port": "8888",
    "clientid": "",
    "usetls": false,
    "compatmode": false,
    "keepalive": "60",
    "cleansession": true,
    "birthTopic": "",
    "birthQos": "0",
    "birthPayload": "",
    "closeTopic": "",
    "closeQos": "0",
    "closePayload": "",
    "willTopic": "",
    "willQos": "0",
    "willPayload": ""

The weather is hard-coded for now. The relevant injectors and functions look as follows:



Please run the flow locally, add your MQTT credentials and you should see the weather message both in the debug output and your MQTT stream.

This can now be automatically distributed to a large number of devices

This flow is a static flow and this could be played out to a large number of devices by including settings.js, flows_cred.json. How this is done will be explained below. Please note that this also can be done by the qbee APIs and online services such as GitHub. But we don't want to bore you and add another interesting step.

Adding the magic - qbee templating

qbee has a templating engine that can identify any value in any configuration file and make it accessible as a key-value pair. This is done by using Mustache annotation with double curly brackets around a variable. So the "good" weather turns into the variable {{weather}}. Please see more below.

Creating flows with templating to allow for automated adjustment of parameters

In real life Node-RED applications changes often need to be introduced between different installations. Typical examples of this are:

  • different modbus addresses
  • a different string to tag a device
  • adjust an update rate dynamically
  • point to a different MQTT server
  • change the MQTT topic

With qbee Node-RED templating you can do all this on a device or group level through the templating engine.

Let's revisit the flow and change it into qbee's templating format by using a so-called Mustache notation. This basically means that the exposed key-value variable will be made accessible by qbee. So instead of having the value "very good" we define the payload as {{weather}} introducing "weather" as key and defining the value through qbee templating. This can be done in the Node-RED editor or just in the json text file. If done in the editor please deploy to write the json.

Ignore editor warnings when defining numbers as string

If you have defined a payload as number and then you introduce a {{my-number}} string an error message is issued. This can be ignored. Just make sure that the value you insert later is a number.


Instead of using the flows.json we copy and rename the new flow into


This file is used by the qbee agent to create the real flows.json on the device after the automated key-value extraction.

Now you upload the settings.js and the flows.tmpl and the according flows_cred.json to the qbee file manager.


The qbee file manager does not work with hidden directories like .node-red yet. Please copy the files to a non-hidden location and upload from there.

Now everything is prepared to play out files and configuration to real target machines. We are assuming that we run Node-RED as user pi from the /home/pi user directory.

Distributing flows with different settings to different devices by using templating

In the devices tab of qbee we create a tree structure with one or more devices to experiment. In this case we can later select a whole group, a sub-group or a single device to execute the file distribution upon. For a reference about the qbee tree concept please follow the link.

It is also possible to play out the same flows to all devices in production and then configure them differently for a specific group such as "group_A". If a device is moved from one group to another or if new devices will be moved into a group they will automatically receive the correct Node-RED files and templating variables. For a proper Node-RED file distribution we need to play out the settings.js, the flows.tmpl (if no templating is used use flows.json) and the flows_cred.json.

Now we can start defining the configuration to achieve the templating. Go into the "Configure" menu of qbee and navigate to the group or device that is supposed to receive the configuration. Select the function "file distribution". In our case we select the group "group_A", as can be seen in the selector box.


In file distribution please enable this for this group level, and then we define the files we want to distribute. In our case all files reside in the /node-demo/ folder in the file manager.

So first we distribute




and then we do the same with the credential file:




The third file is slightly different. If you only have static content you would play out the flows.json. But since we demo templating we distribute the file with the templating variable in Mustache notation that we called flows.tmpl. In addition, we need to check the "templating" box that allows to define one or more key-value pairs:




What happens with the flows.tmpl file?

Any time there is a change in the value for the key "weather" qbee will expand the flows.tmpl into a new flows.json on the device. This will then trigger the "command to run" and restart Node-RED. From there the flow runs with the new variable.

Now we can define what the weather should be this time. We define it as "bad"

weather : bad

In order to make this all active we need to do one more thing. We need to issue a "command to run" that will be triggered each time something changes or the first time a device is moved into that group. Commands in this box can be chained using &&. There are two things to do here. First we need to change the ownership of the settings.js file to the local user "pi" and also to group pi (usually qbee does this automatically. The command chown pi.pi file changes both user and group for "file". This is needed in order to allow Node-RED to function properly. And then we need to restart Node-RED as user "pi":

chown pi.pi /home/pi/.node-red/settings.js && sudo -u pi node-red-restart

Please save and commit these changes and wait one run interval of the qbee agent. In the log files you will see that both the flows.tmpl file was transformed into the flows.json with the appropriate value and that the settings.js and flows_cred.json files were played out. It also displays that Node-RED was restarted automatically.

Any new commit will cause qbee to restart Node-RED

Any change in configuration causes qbee to restart the service thus making configuration valid automatically.

Only saved AND committed changes will become active

Don't forget to save AND commit (button in the right hand corner) in order to make this configuration active.


Investigating the result of the remote Node-RED deployment in the MQTT stream

Did it work? Well, let's see by going to the remote device and press on the debug pane. There is a manual for remote web access . Now there should be a weather state defined as bad. Just try to change it, save and commit and after the next agent run it will change according to whatever value you selected in the key-value form.

Ok, then let's check how it could look like for different weather settings in an MQTT client like CloudMQTT:



At this point in time it is possible to define groups of devices running node-red and provide them with a common flow. The templating variables will get set through the qbee UI. Any change is logged in the audit trail of qbee so it is possible to see which user has set something and what it actually was. has an audit function that tracks any change to the system. Below you see the audit entry for the changes:


So this tutorial has shown how to handle Node-RED and gave some insights into the pitfalls and problems associated with moving the flow, credential and setting files around between different installations and devices as often done in production environments. We also showed how qbee can help to setup Node Red headless as well as to distribute specific files to different devices. In addition, it is possible to work with templating which allows to re-use flows by exposing certain key-value variables into the qbee UI making them accessible from the tool (or through the API). Thus the templating allows to apply certain conditions to a group, a sub-group or a single device.

Some final thoughts and comments

As a final remark it can be said that groups of devices can be configured with the same flow and specific properties can be changed as needed. This could be different update settings (fast on ethernet, slower for devices on mobile network), machine configurations or anything else. By moving a device into the correct group it will receive the correct settings. Any change is registered in the audit log. This records also the values. If anything changes the node-red process is restarted automatically and this is recorded in the logs as warning. Through the qbee API these key-values can even be set by third party applications.

If we assume a Node-RED flow is used to control the HVAC system in a smart building context we could envision a fleet of industrial Raspberry Pi devices in different buildings controlling the HVAC or SCADA system. Now not all smart buildings and building managers will want to have the same setpoint for the climate control. Here grouping the devices and using flows.json templating with Mustache will resolve this very elegantly.

It is also possible to monitor the service and restart it automatically if it terminates through a watchdog like function.

Sign up for your free trial!