MQTT - TLS encryption example

Nice. Thanks for the writeup Paul, most helpful.

Tried this before though without much enthusiasm and never got it working. Possibly to do with the chain cert. Never really wanted to expose my MQTT so I never tied it down.

One thing though, if your certs are from Let's Encrypt, you should be able to verify the certificate in the NR MQTT configuration. This is something that, in general, is a good thing to do because unverified certs are not terribly secure. Probably not really a security problem in your case but it is a good practice to get into. I wont go into the full reasoning behind this though I can explain to people if they want to PM me.

Indeed, even self-signed certs can be verified as long as you create a root certificate that you keep safe and generate a full chain from.

A nice addition to the Node-RED knowledgebase, thanks.

Yes, I was surprised too, but it doesn't verify for some reason. Could it be because only the CA certificate is added?

Actually, having thought about it, the TLS settings in the mqtt node appear to be for authenticating the CLIENT since it includes the private key.

I'm thinking that maybe you should turn that off and try to use the correct port.

Have you actually verified that the connection is on the secure channel?

Also, you might want to check out the following page which shows you that you possibly have your certs in the wrong order. The cert should be the chain.pem, it is called fullchain.pem on my installation. Then the cafile entry should contain the verified CA root from the OS which is, according to the mosquitto site: /etc/ssl/certs/DST_Root_CA_X3.pem.

OK, I can see that I'm going to have to bite the bullet and actually try this myself :sigh: good job the Mrs is out at her sewing class!! :rofl:

So, some experimentation and reading later. Here are some updates and simplifications.

For the Mosquitto configuration, you need to add/change /etc/mosquitto/conf.d/custom.conf (you can call the file anything. You also seem to have to add the default port as well if you want to retain that. Mosquitto uses default settings which include the standard port but they seem to be turned off once you add your own custom settings. Note the bits in angle brackets that you need to change:

# Default Listener: 1883
port 1883
# Bind the default listener to localhost only if you want to force external connections to be TLS only
#bind_address localhost

# Secure listener
listener 8883
## This is standard and should always be this
cafile /etc/ssl/certs/DST_Root_CA_X3.pem
## These are from your installation of LE
certfile /<path-to-LE-cert-files>/fullchain.cer
keyfile /<path-to-LE-cert-files>/<private-key-name>.key
## Forces use of modern version of TLS to avoid security issues
tls_version tlsv1.2

## Forces ALL CLIENTs to provide a valid certificate - change the node config to allow this from NR
#require_certificate true

You then need to restart the Mosquitto broker with sudo systemctl restart mosquitto. You can check whether it has started the correct ports with sudo netstat -lptu | grep mosquitto which should give you 4 entries:

tcp        0      0  *               LISTEN      17697/mosquitto
tcp        0      0  *               LISTEN      17697/mosquitto
tcp6       0      0 [::]:8883               [::]:*                  LISTEN      17697/mosquitto
tcp6       0      0 [::]:1883               [::]:*                  LISTEN      17697/mosquitto

Note that you do not have to make any firewall changes on the Pi, the OS does that for you and will open both ports. You can check that from another Linux/Mac device (or Windows using WSL) with telnet <IP-NAME> 1883 and telnet <IP-NAME> 8883.

To connect securely from Node-RED, you need to configure the MQTT connection to use the TLS connection not the standard one. You also need to use the IP name rather than the IP address because otherwise, the certificate won't be valid.


Note that you need to set the URL and the port but you don't need to set the "Enable secure connection" flag. That lets you authenticate the Node-RED client connection to the broker (if you set the require_certificate to true for example).

Many thanks to Paul for giving me both the clues and the motivation to get this done. :smiley:

To monitor what is going on with Mosquitto, you can use the command sudo tail /var/log/mosquitto/mosquitto.log -f. This will show you connections and disconnections. If you need more information, you can change the log level in your mosquitto broker configuration file and restart the broker.

# Logging. Defaults to "error, warning, notice, information"
# debug, error, warning, notice, information, subscribe, unsubscribe, websockets, none, all
#log_type all
#log_type error
#log_type warning
#log_type notice
#log_type information
#log_type subscribe

once you guys have the "perfect" solution sorted... it would make a great addition to the cookbook :slight_smile:

1 Like

It looks pretty much the same as my example above except you've called your configuration file custom.conf, whereas I called mine default.conf (could call it anything so long as it has a conf suffix).

I'm surprised you don't need to set the "Enable secure connection" flag, I thought that was the whole point.

Are you able to now verify the certificate?

1 Like

While similar, note the differences in the cert entries. The root cert verification is provided by Debian's trusted root cert list.

The other difference in the config is that I have forced TLS 1.2 to make sure you don't use an outdated, insecure TLS connection (e.g. TLS 1.0).

Yes. You could also split it so that different bits were in their own files if you like.

Nope, I think that the help info could do with some updating (hint to @dceejay :smiley:) to make that clearer. The "Enable secure connection" flag is for the client to authenticate to the broker rather than the other way around.

Actually, that is hard to say since I have no access to the internals of the mqtt nodes without a lot of faffing. So I can't prove that the client is validating the certificate chain right now. Maybe Dave knows?

Anyway, it works and now uses the certificates recommended by Mosquitto themselves.

:sigh: OK, I'll drop a note into the slack channel. I assume that I need to do a PR?

Yes please - (maybe start with the info update you just mentioned :slight_smile:

1 Like

PR submitted.

1 Like

Just updated the first post to include @TotallyInformation's comments;

# Local MQTT
listener 1883

# Secure MQTT
listener 8883
## This is standard and should always be this
cafile   /etc/ssl/certs/DST_Root_CA_X3.pem
## These are from your installation of LE
certfile /home/pi/.node-red/certs/fullchain.pem
keyfile  /home/pi/.node-red/certs/privkey.pem
## Forces use of modern version of TLS to avoid security issues
tls_version tlsv1.2
## Force all clients in this listener to provide a valid certificate, change the node config to allow this from NR
#require_certificate true

Just updated first post above to describe how to configure client node-RED MQTT nodes in order to present a valid certificate, and connect to the broker.


This is how I got MQTT SSL/TLS connections to a Mosquitto server using a domain certificate issued by Let's Encrypt working, including certificate validation in Node-RED:

Mosquitto configuration:

listener 8883
certfile /lets_encrypt_certs/domain.tld.crt
cafile /lets_encrypt_certs/domain.tld.chain.pem
keyfile /lets_encrypt_certs/domain.tld.key

The three files in /lets_encrypt_certs/ are created by a Let's Encrypt cert-bot.
Note: No require_certificate true - this is for authenticating the user in Mosquitto with a certificate.

Node-Red configuration:

  • Port: 8883
  • Enable secure (SSL/TLS) connection: Check.
  • CA Certificate: Provide a file that contains the chain for certificates issued by Let's Encrypt (see below).
  • Verify server certificate: Check (otherwise all this is pointless).
  • Server Name: The domain name for which the Let's Encrypt certificate was issued (this is crucial - otherwise any certificate issued by Let's Encrypt would be accepted).

Leave the rest unchanged/empty.

The certificate chain file for Let's Encrypt (save as text file and use for CA Certificate):



(These are the ISRG Root X1 (self-signed) certificate and the Let’s Encrypt Authority X3 (Signed by ISRG Root X1) certificate found at




1 Like

Urm, please don't publish your certificate files here thanks. They are specific to you, we don't need them.

Also, as has already been mentioned, the cafile should be the CA ROOT and not your chain. The chain works but isn't correct.

@TotallyInformation The certificates I posted are not my own certificates, but official certificates from Let's Encrypt (as I explain in the answer). Providing this chain as CA Certificate in Node-RED is a way to have Node-RED connect to Mosquitto while having the Verify server certificate option checked. Why do you think this is not correct?

We don't really need certificate files in the forum as anyone using LE will have them anyway. It is also easy enough to make a mistake and paste something that should be kept secret.

This has already been covered in the other posts. I've also written a cookbook entry containing all the correct information as was also mentioned. You can check out the PR if you like.

  1. Because it isn't the official information given in the Mosquitto documentation.
  2. Because you've specified the root certificate chain in a user area of your device which is potentially more open to manipulation than the correct root CA entries that are kept in an area of the OS that isn't as easy to write to. That makes it easier for an attacker to replace the chain with their own to do a successful man-in-the-middle attack.

Small things for many users but the kind of thing that can easily make certificate-based security worthless.

The mantra when working with Public Key Infrastructures is that they are hard to configure securely and really hard to keep secure.

Which part of my post are you referring to? This is the portion of the mosquitto.conf man page that I think is most relevant here:

When using certificate based encryption there are three options that affect authentication. The first is require_certificate, which may be set to true or false. If false, the SSL/TLS component of the client will verify the server but there is no requirement for the client to provide anything for the server: authentication is limited to the MQTT built in username/password.

I don't see any problem here. The very moment someone get's access to what you call user area, he can access all the information that would be protected by a secure MQTT connection anyway.

Using an URL beginning with mqtts:// instead of providing the CA Certificate chain explicitly only works if the Let's Encrypt certificate chain is available on the system running Node-RED. I agree that this should be the preferred way. But if the server certificate cannot be verified using the system's built in trusted certificates, I think it is still better to do it by providing the CA Certificate chain explicitly instead of disabling certificate verification or not using SSL/TLS.

I just made another discovery: When using an URL that begins with mqtts:// but not selecting Enable secure (SSL/TLS) connection, the certificate is not verified at all (neither the CA nor the hostname). To verify the certificate, this option and Verify server certificate have to be selected.

If these options are not selected, rejectUnauthorized is set to false in the options object passed to MQTT.js's.

See issue node-red#2379.

I've just updated the first post above to include locking the broker down to clients who are both TLS enabled and present the correct username/password.
I've updated the Mosquitto config file and the new section starts at Enforce Security.

As always, please comment with improvements/suggestions.

1 Like

Cool stuff Paul, thanks for that.

One thing that would probably be interesting for people not using a cloud-based client would be to be able to use self-signed certificates for the client - in case that client is on a laptop for example and therefore does not have a recognised domain and so cannot use a Let's Encrypt certificate.

In theory, you should be able to create your own CA file that contains the root trust for a self-signed certificate in addition to the standard Pi root trust.

Of course, it would require you to create a self-signed certificate "properly" which means creating your own root CA certificate as well as the client certificate based off it.

This thread seems to suggest a way to successfully combine the certs in a PEM file:

Since all of that is rather complex. I might suggest that people create a 3rd interface that allows user-id/password logins over mqtts for when client certificate authentication isn't feasible.

It shouldn't need to be said, but I will anyway :grinning: - NEVER add id/password based logins (or indeed any other kind of login) without having first restricted access to a TLS encrypted connection.

By keeping things on separate interfaces (each with its own TCP port), it is possible to restrict access using firewall rules as another level of security. You can also restrict access to specific parts of the topic structure in MQTT and restrict whether or not that interface can update topics or only read them.

Finally, by splitting the interface configurations into their own files, they would be easier to manage I think as well as potentially easier to turn on/off as needed.