I run a MQTT broker (mosquitto) on my home network, to support my local Home Assistant instance. As part of another project I needed to make that MQTT broker accessible from the public Internet, but of course I didn't want to make my whole network wide open. I couldn't find any good tutorials, so I pieced together parts of different tutorials and put them together for you here.
When you're done you will be able to access your MQTT broker from anywhere on the Internet, using a username and password to authenticate (so that not just anybody can access it), and confident that the connection is encrypted using TLS.
Let's get started!
0. PrerequisitesI assume you already have mosquitto running on a machine on your local network. Note that the Home Assistant Mosquitto Broker Add-On will not work. For this tutorial, you'll need to be running mosquitto on a machine where you have full control over its config. Additionally, for all of this to work, we'll need mosquitto version 1.5 or later. You can see what version you're running with the following command:
mosquitto --help | head -n 1If your Linux distribution doesn't provide mosquitto version 1.5 or later, you can add the mosquitto-dev PPA to your system and upgrade to the latest version using:
sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
sudo apt-get update
sudo apt-get install --only-upgrade mosquitto1. DuckDNS for Dynamic DNSThe first step is to get a dynamic DNS hostname so that any client on the Internet can find your MQTT broker. We'll use the amazing DuckDNS.org service for that.
Go to https://www.duckdns.org, log in using whatever provider you prefer, and then add a new domain. We'll need that domain name later, as well as your token (listed a little higher up the DuckDNS page). Don't worry about setting your IP address now—we'll do that later automatically.
2. Syncing DuckDNS and Getting a Certificate from Let's EncryptThe next step is to make sure that the domain name you created with DuckDNS points to your home network, and to get a TLS certificate from Let's Encrypt so that your MQTT communications will be encrypted. I've written a simple systemdservice that will use a couple of docker images (courtesy of https://github.com/maksimstojkovic) to do this for you.
First get the systemd service and install it, as well as make sure we have docker-compose (which the systemd service uses). We'll do all of the following on the machine that's running mosquitto:
git clone https://github.com/jgillula/duckdns-and-letsencrypt.git
cd duckdns-and-letsencrypt
./configure
make
sudo make install
sudo apt install docker-ce docker-composeNext we need to create a new group that will be able to view the TLS certificates, and add whatever user the mosquitto broker runs as to that group (probably mosquitto, but if you have a custom configuration this may be another user):
sudo addgroup --system duckdnsandletsencrypt
sudo usermod -aG duckdnsandletsencrypt mosquitto
echo "GID=$( getent group duckdnsandletsencrypt | cut -d: -f3 )"Remember the output of that last line (GID=SOME_NUMBER), we'll need it in the next step.
Now let's edit the configuration file /usr/local/etc/duckdns-and-letsencrypt/.env so that it has your info from earlier. The file should look like
DUCKDNS_TOKEN=BLAH-ABC1234-ETC
DUCKDNS_DOMAIN=something.duckdns.org
UID=0
GID=0Replace the DUCKSDNS_TOKEN value with your token from Step 1, the DUCKDNS_DOMAIN value with your domain name (including the .duckdns.org at the end), and the GID with the GID of the duckdnsandletsencrypt group we just created.
Finally, start the service with
sudo systemctl start duckdns-and-letsencrypt.serviceand it will automatically sync your IP address with DuckDNS and get a TLS certificate for that domain from Let's Encrypt.
The first time you start the service it may take a while, since it has to pull down the docker images. Once it's running, your certificates should be available at /usr/local/etc/duckdns-and-letsencrypt/certs/live/something.duckdns.org/ where something.duckdns.org is your domain name.
Finally, since Let's Encrypt makes the directories where the certificates are stored unreadable by group by default, we need to do one more thing to make the certificates be readable by users in the duckdnsandletsencrypt group. Wait until after the first certs are generated and then do:
sudo chmod g+rx /usr/local/etc/duckdns-and-letsencrypt/certs/{live,archive}
sudo chmod g+r /usr/local/etc/duckdns-and-letsencrypt/certs/archive/DUCKDNS_DOMAIN/privkey.pemwhere DUCKDNS_DOMAIN is your domain name (with the .duckdns.org at the end).
Next we need to configure mosquitto to require a username and password. Let's create a file at /etc/mosquitto/passwd which will store the username and password in a format mosquitto can read. Still on the machine running mosquitto, do:
sudo mosquitto_passwd -c /etc/mosquitto/passwd SOME_USERwhere SOME_USER is the username you want to allow to login to your MQTT broker from the Internet. (Note: SOME_USER does not have to be the same as a username that already exists on the machine. It can be any username you like.)
The command will prompt you to create a password (and enter it twice)—you'll need to supply that username and password in whatever MQTT client you use to login to your MQTT broker from the Internet.
4. Configuring Mosquitto with Access Controls (Optional)Note: If you don't want any access controls, you can skip this section.
Next let's set up some access controls so this user can only read or write certain topics. To do that, use sudo and whatever editor you like to create a file at /etc/mosquitto/acls. Then enter the access control lines defining the controls you want. Mine looks something like:
user SOME_USER
topic write some/topic
topic read some/other/topic
topic readwrite yet/another/topic/#- The first line tells
mosquittowhich user the following access controls apply to, e.g.SOME_USER - The second line tells
moquittoto letSOME_USERwrite to topicsome/topic - The third line tells
mosquittoto letSOME_USERread from topicsome/other/topic - The fourth line uses the
#wildcard to tellmosquittoto letSOME_USERread and write from any topic that starts withyet/another/topic/
Adjust this file to suit your needs, and then save it. (For more advanced information about ACLs in mosquitto, check out Steve's Internet Guide.)
5. Configuring Mosquitto to Use EverythingFinally let's configure mosquitto to actually use these files, as well as the TLS certificates we generated in Step 2. Use sudo and whatever editor you like to create a file at /etc/mosquitto/conf.d/public_internet_access.conf and paste the following inside it:
per_listener_settings true
listener 1883
allow_anonymous true
listener 8883
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acls
certfile /usr/local/etc/duckdns-and-letsencrypt/certs/live/DUCKDNS_DOMAIN/fullchain.pem
keyfile /usr/local/etc/duckdns-and-letsencrypt/certs/live/DUCKDNS_DOMAIN/privkey.pemreplacing DUCKDNS_DOMAIN with your DuckDNS domain (including the .duckdns.org at the end).
Let's examine each of these lines to see what they do:
per_listener_settings true— This tellsmosquittothat we'll want different authorization and encryption settings on different ports.listener 1883— This tellsmosquittothat we want to listen on port 1883allow_anonymous true— This tellsmosquittothat we want to allow anonymous logins on port 1883.
Since we don't have any other configuration for port 1883, this basically means anyone can log into port 1883, read or write any topic, and it won't use encryption. These are basically the default settings for mosquitto. In the next lines, we'll add a port that uses encryption, requires authorization, and enforces access controls.
listener 8883— This tellsmosquittothat we also want to listen on port 8883.allow_anonymous false— This tellsmosquittothat we are going to require usernames and passwords on port 8883.password_file /etc/mosquitto/passwd— This tellsmosquittowhere to find the username/password file we created earlier.acl_file /etc/mosquitto/acls— This tellsmosquittowhere to find the access control file we created earlier. Note: If you didn't create an ACL file earlier, you can skip this line.certfile /.../DUCKDNS_DOMAIN/fullchain.pem— This tellsmosquittowhere to find the TLS certificate we got from Let's Encryptkeyfile /.../DUCKDNS_DOMAIN/privkey.pem— This tellsmosquittowhere to find the private key it should use for the TLS encryption
As a result, we have mosquitto also listening on port 8883, using encryption, requiring usernames and passwords, and (optionally) enforcing access controls on users who connect on that port.
But we're not done yet!
6. Port Forwarding On Your RouterIn order to actually access your mosquitto broker from the Internet, we also need to open a port on your router and forward it on to the broker. How you do this will depend on your specific router, but if you're using DD-WRT like me, it's just a matter of:
- Logging into your router,
- Going to NAT/QoS > Port Forwarding,
- Adding a new port forward from whatever port you choose to the IP address of the machine running
mosquittoon port 8883, - Making sure to check the "Enable" checkbox,
- Saving and applying your settings.
When choosing what port to expose I recommend choosing a random high port number that isn't reserved for something else, i.e. in the range 49152–65535. That way bots looking specifically for MQTT servers won't be able to find it unless they scan every single port on your router.
And that's it! Now you can login to your mosquitto broker from the Internet using the username and password you chose earlier!



Comments