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 1
If 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 mosquitto
1. 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 systemd
service 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-compose
Next 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=0
Replace 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.service
and 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.pem
where 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_USER
where 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
mosquitto
which user the following access controls apply to, e.g.SOME_USER
- The second line tells
moquitto
to letSOME_USER
write to topicsome/topic
- The third line tells
mosquitto
to letSOME_USER
read from topicsome/other/topic
- The fourth line uses the
#
wildcard to tellmosquitto
to letSOME_USER
read 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.pem
replacing 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 tellsmosquitto
that we'll want different authorization and encryption settings on different ports.listener 1883
— This tellsmosquitto
that we want to listen on port 1883allow_anonymous true
— This tellsmosquitto
that 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 tellsmosquitto
that we also want to listen on port 8883.allow_anonymous false
— This tellsmosquitto
that we are going to require usernames and passwords on port 8883.password_file /etc/mosquitto/passwd
— This tellsmosquitto
where to find the username/password file we created earlier.acl_file /etc/mosquitto/acls
— This tellsmosquitto
where 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 tellsmosquitto
where to find the TLS certificate we got from Let's Encryptkeyfile /.../DUCKDNS_DOMAIN/privkey.pem
— This tellsmosquitto
where 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
mosquitto
on 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