Node-RED SSL using Letsencrypt & Certbot

I've written this up in case it helps other who may wish to secure their node-RED online presence, by using SSL certificates.
The installation uses Letsencrypt to issue the certificates and also Certbot to fully automate and handle renewals - so it's a fit & forget solution.

Pre-requisites
I've started with a RPi3b+ and a fresh 'Buster' operating system, with node-RED installed via the official script.
Because node-RED is going to provide my online presence, no other webserver (such as apache) has been installed. If you do intend to also run another webserver as well as node-RED, then the Certbot installation is slightly different and not covered here, but see this tutorial for the necessary changes.
It's important at this stage that you have secured your node-RED editor by following this guide, then ensure that port forwarding is setup in your router for ports 1880 & 80 (port 80 is required by certbot).
You must also have a domain name, and which points to your server.
Ensure that you can access your node-RED editor via your domain name (http://mysite.com:1880) before going any further, otherwise Certbot will fail.

Create a folder to hold your new certs; mkdir /home/pi/.node-red/certs

Install Certbot
Most of the following commands require root privilidge, so let's make life easier!
sudo su

Install Certbot
apt-get install certbot

Obtain a set of certificates
certbot certonly --standalone
This will take a few minutes and should ask you a number of questions, such as email address, domain name, etc (nothing complicated!!) during that process.

Lets now create a script to automatically move a copy of the certs to your node-red/certs folder, prepare them for use by node-RED, and restart node-RED so that the new certificate is applied.
This script will only run if the certificate is successfully renewed.
Create a script called renewal_success in /etc/letsencrypt/renewal-hooks/deploy/

#!/bin/bash

domain=mydomain.com
node_dir=/home/pi/.node-red/certs
node_user=pi

cp /etc/letsencrypt/live/$domain/*.pem "$node_dir"/
chown $node_user "$node_dir"/*.pem

...and make executable;
chmod u+x /etc/letsencrypt/renewal-hooks/deploy/renewal_success

Now run the script;
/etc/letsencrypt/renewal-hooks/deploy/./renewal_success
and you should find that you will now have 4 certs in your node-red/certs folder, and node-RED restarted.

The Pi installation package automatically creates a systemd timer that runs twice daily (at randomised times) to check if it is necessary to renew the certificates, and although Letsencrypt certificates have a life of 90 days, they will be renewed 30 days before expiry.
To change the timing of the renewal checks, or disable them completely, see this post.

So that concludes installing & setting up certbot, so now exit su privilege;
exit

Add certificate links to the node-red settings file;

    https: {
    key: fs.readFileSync('/home/pi/.node-red/certs/privkey.pem'),
    cert: fs.readFileSync('/home/pi/.node-red/certs/fullchain.pem')
           },

To ensure that node-RED loads the new certificates when they have been renewed, enable httpsRefreshInterval in the settings file.

and enable this option to force http visitors to use https;
requireHttps: true,

...then reboot node-red to restart your SSL enabled server;
node-red-restart

Many thanks to @recursivecodes for writing the Oracle cloud tutorial on which this is based.

14 Likes

Hi Paul,
Thanks for sharing this! Just what I was looking for... Can the crontab be replaced by e.g. the cron-plus node, to integrate it even more into Node-RED?

Yes it could. You only need to run the command certbot renew (as root) to trigger the renew process.
But note that node-RED will not read the new certificates until the NR server is restarted, and if you look at the cron entry, there's a post-hook in there that does exactly that, and furthermore only restarts node-RED if a certificate renewal has been made, otherwise it doesn't restart.

You can simulate an actual renewal to test by using sudo certbot renew --dry-run whilst tailing the log file; sudo tail -f /var/log/letsencrypt/letsencrypt.log

1 Like

Ah ok. Sorry had overlooked that you had to restart Node-RED. That is a pitty. I now see here indeed that NodeJs needs this pull-request to allow the credentials to be hot swapped, for new connections being created. Wasn't aware of that...

1 Like

It's a quick restart just once every 2 months in the middle of the night! I can live with that :wink:

2 Likes

I've just updated the first post above to use the fullchain.pem certificate instead of cert.pem on the advice of the Letsencrypt guys.

2 Likes

Urm, that's odd, I don't do that. Hmm, what am I doing that is different I wonder? Surely I'm not restarting NR that often for other reasons?

Well I won't be able to find out until January.

Julian, do you have a paid account?

No. The last change was in October.

It is possible that this year has seen me updating that system more than usual and so restarting it more often. It is even possible that I set up a CRON job and completely forgot about it :rofl:

I'll get round to checking at some point.

Just updated the first post above.

After checking the Letsencrypt log, I found that the renewal application was being made at times outside the range of the custom cron setting, and upon further checking it appears that the Pi installation package also sets up systemd to run the process twice daily at random times.
See this post.

So no need for the cron job - it has been removed, and the post-hook function has been now been moved to the shell script instead.

It appears that the configuration of Certbot varies dependent upon the OS.

@BartButenaers - for info

1 Like

Hi Paul,

I am trying to do the same steps on my PI. For some reason I have jessie which does not include certbot. I found this post and installed certbot-auto. It does not have -d parameter, so I can only run as certonly --standalone. During this I get this:

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for ringlo.ddns.net
Cleaning up challenges
Problem binding to port 80: Could not bind to IPv4 or IPv6.

So this is the point when letsencrypt is trying to check that it is indeed my server, right? But how will it perform the challenge if nothing is running on port 80. Or do I need to set up apache for this?

I got a bit confused.

Yes, correct.
It appears from your link, that you've chosen the version of certbot intended to be run alongside an apache server. If you are also running Apache, then as I said in my first post -

From what I've read, if you don't have any other webserver, then use the Certbot version which spins up a python server to do the verification.
If however you do have another server, then the verification needs to be run through that other webserver (apache).

OK, I understand now. So I need to find out how can I install the standalone certbot in jessie. As apt says "unable to locate package certbot".

I haven't looked what is avaialble in Jessie, but have you tried updating your sources sudo apt-get update first.

I did sudo apt-get update but it did not help. What I did instead if fired up apache2 on port 80 (it is normally nor running), got the certificate created, copied it to the "cert" folder, changed the settings.js and restarted NR. Chrome is still saying that it is "not secure". When I view the certificate, it says Issued to: ringlo.ddns.net so that is definitely my certificate. When I look at the certification path I see Let's Encrypt Authority X3, and DST Root CA X3.
So what is Chrome's problem with this certificate? It this about that the challange was on port 80 and now we are on port 1880?

And do I understand correctly, that with the process I used above the certificate renewal will not work unless the apache server is running?

Have you changed ownership of the certs, so node-RED can access them OK?
It's included it the script in the first post.

yes, I did. In fact I ran the script after the certificate got generated and it copied the files to the folder under node-red. And since it says "issued to: ringlo.ddns.net" I know it is using these certificates. Previously I had a self signed certificate which has no root CA.
Do I just need to restart my computer for Chome to forget something?

As you probably have not added the certificates to Apache, can you stop apache and then look at just your node-RED server, as http://ringlo.ddns.net/ seems to be pointing to 'Saia PCD Web Server'.
Also anything in the node-RED log?

Yes, and I would like to keep port 80 as it is, but you can reach Node red on https://ringlo.ddns.net:1880/

@Paul-Reed: this is all my bad, I am so sorry. I opened my NR as https://192.168.1.80:1880 instead of using the domain. Of course Chrome has issues as the IP does not match the domain of the certificate. Such a rookie mistake. I am so sorry.

2 Likes