Node-RED Secure Installation

By Adrian | December 10, 2019

Node-RED has traditionally been used for tapping into hardware devices and API endpoints to construct workflows in a drag and drop interface. It is quite extensible given you can add your own code and data manipulations. I’ve seen Node-RED used to connect into power metering hardware which cleans up the data feed, customises the output to multiple destinations (in this case Splunk and an output file). A quick YouTube search shows there are many possible home automations with Node-RED. There is great potential in this open source software. Now while I don’t actually have any IOT type devices or sensors I can make use of like this at this time, it still interests me and I may have a few uses for it for some data collection API calls I routinely make. Behind the scenes it runs NodeJS which may explain why I’ve ignored it for such a long time.

Here is my install guide for installing and securing Node-RED.

Pre-Requisites

Start with fully patched Ubuntu 18.04LTS base OS install. Not going to cover that part here.

Install the build-essentials package

sudo apt-get install -y build-essential

Install Node Package Manager (npm)

sudo apt-get install npm -y

Install Node-RED

Install Node-RED with the following command

sudo npm install -g --unsafe-perm node-red

Create a service so that Node_RED will start on reboot

Create /lib/systemd/system/nodered.service with the following text. Update the User, Group, WorkingDirectory as appropriate.

# systemd service file to start Node-RED

[Unit]
Description=Node-RED graphical event wiring tool
Wants=network.target
Documentation=http://nodered.org/docs/hardware/raspberrypi.html

[Service]
Type=simple
# Run as normal pi user - change to the user name you wish to run Node-RED as
User=<YOUR USER>
Group=<GROUP>
WorkingDirectory=/home/<USER>

Nice=5
Environment="NODE_OPTIONS=--max_old_space_size=256"
# uncomment and edit next line if you need an http proxy
#Environment="HTTP_PROXY=my.httpproxy.server.address"
# uncomment the next line for a more verbose log output
#Environment="NODE_RED_OPTIONS=-v"
#ExecStart=/usr/bin/env node $NODE_OPTIONS red.js $NODE_RED_OPTIONS
ExecStart=/usr/bin/env node-red $NODE_OPTIONS $NODE_RED_OPTIONS
# Use SIGINT to stop
KillSignal=SIGINT
# Auto restart on crash
Restart=on-failure
# Tag things in the log
SyslogIdentifier=Node-RED
#StandardOutput=syslog

[Install]
WantedBy=multi-user.target

Enable and start the service so it will start on reboot

sudo systemctl enable nodered
sudo systemctl start nodered

At this time, you now have a working install, you can navigate to http://w.x.y.z:1880 to access the system. Don’t go putting this online until its secure, Shodan.io shows people have just done that…. don’t be that person. Anyone with access to this IP may have access to create and modify flows if you don’t secure it.

Adding authentication to Node-RED

So that we can put Node-RED behind authentication we need to generate a password hash and update the settings.js file. This settings file is located at ~/.node-red/settings.js.

Installing the node-red-admin package was frustrating to say the least as I was getting permission error after permission error. I’ve only included the build steps that worked for me at the time and retried this guide to ensure that it is good.

Install the node-red-admin package.

sudo npm install -g node-red-admin

Generate a secure hash by using the following command:

node-red-admin hash-pw

# Output
<password hash>

Update ~/.node-red/settings.js. Uncomment out the block of code for adminAuth:. I have added a 1h sessionExpiryTime as well. It should look something like this afterwards:

    adminAuth: {
        sessionExpiryTime: 3600,
        type: "credentials",
        users: [{
            username: "admin",
            password: "<password hash>",
            permissions: "*"
        }]
    },

Restart the nodered service to make the change active

sudo service nodered restart

When you try to access nodered now you will be presented with a login page node-red-login

This is much better… but only half way there, as the website is still only http.

Adding Pre-Requisites for TLS

As has been my custom, I am using Amazon Route53 for my DNS, so I intend on registering a domain and requesting a certificate with Let’s Encrypt. These are the necessary pieces you need to setup a certificate.

First add the dependencies.


# Install certbot components
sudo apt-get install software-properties-common
sudo add-apt-repository universe
sudo add-apt-repository ppa:certbot/certbot -y

# Add in the route53 extension to certbot, python3-pip
sudo apt install python3-pip -y
sudo pip3 install certbot-dns-route53

# Get awscli package
sudo apt-get install awscli -y

# Configure awscli with an Access key and Secret for a user that has access to Route53
sudo aws configure

Generate a certificate

To generate the certificate run the following command.

sudo certbot certonly --dns-route53 -d 'nodered.example.com' --server https://acme-v02.api.letsencrypt.org/directory -m youremail@example.com --non-interactive --agree-tos

# Output
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Found credentials in shared credentials file: ~/.aws/credentials
Plugins selected: Authenticator dns-route53, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for nodered.example.com
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/nodered.example.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/nodered.example.com/privkey.pem
   Your cert will expire on 2020-02-29. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

Copy the certificate files to the .node-red folder

This will cause a breaking change every 3 months when the certificate renews, so you will need a cron job for this.

cd ~/.node-red
mkdir ssl
sudo cp /etc/letsencrypt/live/nodered.example.com/privkey.pem /home/$USER/.node-red/ssl/privkey.pem
sudo cp /etc/letsencrypt/live/nodered.example.com/fullchain.pem /home/$USER/.node-red/ssl/fullchain.pem
sudo chmod 644 ~/.node-red/ssl/privkey.pem

Add the certificate to settings.js

With the certificates obtained edit ~/.node-red/settings.js and make the following changes:

Uncomment the following line

# From
//var fs = require("fs)

# To
var fs = require("fs)

Enable HTTPS by un-commenting and updating the https block

# From
    //https: {
    //    key: fs.readFileSync('privatekey.pem'),
    //    cert: fs.readFileSync('certificate.pem')
    //},

    // The following property can be used to cause insecure HTTP connections to
    // be redirected to HTTPS.
    //requireHttps: true,

# To
    https: {
        key: fs.readFileSync('.node-red/ssl/privkey.pem'),
        cert: fs.readFileSync('.node-red/ssl/fullchain.pem')
    },



    // The following property can be used to cause insecure HTTP connections to
    // be redirected to HTTPS.
    requireHttps: true,

Restart the nodered service to make the change active

sudo service nodered restart

Now you won’t be able to access http://ip:1880 or http://hostname:1880. Accessing https://hostname:1880 should present the login screen.

Upgrade node

During the installation Node 8 was installed, I was having a few issues getting the node-red-admin package to install without throwing errors, so I upgraded NodeJS post installation. I’m pretty sure that the node-red-admin did install but did so with terminating errors, so I didn’t trust it.

Current version of Node

user@node-red:~$ node -v

# Output
v8.10.0

Installing Node package n

user@node-red:~$ sudo npm install -g n

# Output
/usr/local/bin/n -> /usr/local/lib/node_modules/n/bin/n
/usr/local/lib
└── n@6.1.3

Upgrading Node with n

user@node-red:~$ sudo n stable

# Output
  installing : node-v12.13.1
       mkdir : /usr/local/n/versions/node/12.13.1
       fetch : https://nodejs.org/dist/v12.13.1/node-v12.13.1-linux-x64.tar.gz
   installed : v12.13.1 (with npm 6.12.1)

Note: the node command changed location and the old location may be remembered in your current shell.
         old : /usr/bin/node
         new : /usr/local/bin/node
To reset the command location hash either start a new shell, or execute PATH="$PATH"

So there you have it, Node-RED has been installed and secured. I’m no expert in creating flows, so I’m interested to see what I can make it do. The documentation can be found here https://nodered.org/docs/.

I hope you found this useful, don’t forget to follow me on Twitter. Thank you.