; Date: Thu Oct 13 2022
Getting started with Mosquitto is deceptively easy. We show you how to avoid the pitfalls.
The Docker Hub page for the Mosquitto server makes it look trivially easy to deploy the server. You just run the server, and immediately you can set up listeners and post some messages and it's all so easy. But, that's not what happens. There's a configuration file, data, and logs directories to mount into the container, and there is the matter of permissions to access the server anonymously. Once those are properly squared away, it is very easy to install Mosquitto and kick the tires.
Mosquitto is a message broker for the MQTT protocol.
https://mosquitto.org/ It is described as being light weight, and suitable for use on a range of devices from embeddable single board computers (e.g. Raspberry Pi) up to large servers. The Mosquitto project also includes a C library for MQTT, as well as the
MQTT is a protocol for distributing messages using the publish-subscribe (pubsub) model. In MQTT parlance, the broker is the service that distributes messages. MQTT is widely used and the protocol is so lean that it's easy to implement an MQTT client on tiny embedded microcontrollers. A typical usage is to attach sensors to microcontrollers like the ESP32, then deliver data over the Internet to an MQTT service. The protocol is documented at: https://mqtt.org/
Fortunately we are normally not required to implement MQTT ourselves, since there are many existing client libraries and broker services. An example is the Mosquitto project we're using in this tutorial.
We'll look at deploying Mosquitto using Docker, and run a few commands. Along the way we'll discuss a couple common deployment failures. We're not going to dive into using MQTT or Mosquitto for anything significant and instead stay with deployment and light configuration.
Mosquitto deployment on a Linux host
Before getting to Docker, let's quickly run over how to deploy Mosquitto on a Linux host.
On a Debian-based system like Raspbian (Raspberry Pi OS), Ubuntu, Debian, etc, these are useful commands:
# Install server and client packages sudo apt install mosquitto mosquitto-clients # Start the server sudo systemctl enable mosquitto # Check its status sudo systemctl status mosquitto # Restart the server sudo service mosquitto restart
This is easy to do and this is the traditional way of running servers on a Linux system. For other Linux distros, you'll use similar commands (e.g.
yum) and perhaps with different package names.
In the Docker age this is not recommended.
The rationale is that Docker containers limit the potential destruction if someone breaks in through a bug in the Mosquitto service. Any intruder won't be able to damage anything outside the container. Since the container is easily destroyed and recreated if there are problems, recovery is straight-forward.
The Docker container for Mosquitto contains the exact same server and client programs that we discuss in the rest of this article. That means the commands and configuration files we discuss are directly applicable if you prefer to install Mosquitto on the host system rather than inside Docker.
A simple Docker Compose file for Mosquitto
On the Docker Hub page for the Mosquitto server, we're given this
$ docker run -it -p 1883:1883 -p 9001:9001 \ -v mosquitto.conf:/mosquitto/config/mosquitto.conf \ eclipse-mosquitto
This serves to acquaint us with running the Mosquitto container. It mounts a
mosquitto.conf file into the container, and it exposes a pair of ports. Looks simple, doesn't it?
For the configuration file, we're suggested to use this:
persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log
An issue with this is the two directories,
/mosquitto/log/ are not persisted outside the container. There's another issue that we'll talk about later, but this is a good starting point for configuring Mosquitto.
When using Docker, I prefer Docker Compose because of its flexibility. The website
https://www.composerize.com/ can help you with converting a
docker run command into a
docker-compose.yml. After a bit of tweaking, we get this:
services: mosquitto: image: eclipse-mosquitto ports: - 1883:1883 - 9001:9001 volumes: - ./mosquitto.conf:/mosquitto/config/mosquitto.conf - ./data:/mosquitto/data/ - ./log:/mosquitto/log/
This is the same as the
docker command, but it also specifies volume mounts for the
To launch this you run:
$ docker compose up
Note that I have used
docker compose rather than
docker-compose. The old
docker-compose command has been replaced by the new
docker compose command. Let's wish
docker-compose a peaceful retirement. The implementation is complete enough that for most purposes you can replace the
- with a space character for the same effect.
up command will download the
eclipse-mosquitto image if required, set up containers, etc, then launches the stack described in
docker-compose.yml. By default the service will be launched in the foreground so you can see any logging output from the server.
$ docker compose up -d
Run this way, it runs the services detached from the terminal, and they will run in the background.
up -d command is almost suitable for a long-term background server. One issue is whether the service will automatically restart if (when) it crashes. In the cloud computing era we're admonished to always plan for failure of system components. As it stands, if the Mosquitto server crashes it will not restart automatically.
To fix this, make the following change to
services: mosquitto: image: eclipse-mosquitto restart: unless-stopped # Add this ...
restart tag controls the conditions under which to restart a service. The
unless-stopped will ensure the service automatically restarts unless you explicitly stop it.
If you forget to create the
mosquitto.conf you'll get this error:
Error response from daemon: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "/home/david/Projects/nodejs/mqtt/mosquitto.conf" to rootfs at "/mosquitto/config/mosquitto.conf": mount /home/david/Projects/nodejs/mqtt/mosquitto.conf:/mosquitto/config/mosquitto.conf (via /proc/self/fd/6), flags: 0x5000: not a directory: unknown: Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type
I mention this because I made this mistake several times and maybe others will do the same. Simply create the file, however Docker will have created a directory that you must remove first.
Stopping, restarting, and updating the container
Your deployed service can be easily managed using the
docker compose. To do so your terminal session must be in the containing the
docker-compose.yml file. The commands for this are:
# Start the service $ docker compose up -d # Shut down the service $ docker compose down # Restart the service $ docker compose restart # Update the service $ docker compose stop $ docker compose pull $ docker compose up -d
The last will update the service if the container image on Docker Hub has been updated.
Running Mosquitto commands inside the container
If you run
docker compose ps or
docker ps -a you'll see that the container has started.
To see it in action let's listen to an MQTT topic, look at the log file, and send some messages.
In one terminal window you can run this command:
$ sudo tail -f log/mosquitto.log [sudo] password for david: 1665640941: Saving in-memory database to /mosquitto/data//mosquitto.db. 1665641912: mosquitto version 2.0.15 terminating 1665641912: Saving in-memory database to /mosquitto/data//mosquitto.db. 1665642425: mosquitto version 2.0.15 starting 1665642425: Config loaded from /mosquitto/config/mosquitto.conf. 1665642425: Opening ipv4 listen socket on port 1883. 1665642425: Opening ipv6 listen socket on port 1883. 1665642425: mosquitto version 2.0.15 running 1665642425: New connection from 172.29.0.1:37076 on port 1883. 1665642425: Client auto-7F81B465-FE74-A7CC-7A16-854BC3AA23E0 disconnected, not authorised.
This watches the log. It must be run with
sudo because this directory is protected.
Next, if we try to enter the container to run commands we'll get this message:
$ docker exec -it mqtt-mosquitto-1 bash OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found in $PATH: unknown
This is because the
eclipse-mosquitto container is built on Alpine Linux which doesn't have
sh and you'll get a command prompt inside the container.
This command should start listening to messages on a specific topic:
mosquitto_sub -v -t test/message Connection error: Connection Refused: not authorised.
But, as you can see, there is a lack of authorization. It's good to know that Mosquitto has an authorization system. In production use it's necessary that the MQTT service is not wide open to the public.
A quick fix is to change the configuration file to this:
allow_anonymous true persistence true persistence_location /mosquitto/data/ log_dest file /mosquitto/log/mosquitto.log listener 1883
What we're doing is allowing anyone in the world to use this MQTT broker. Clearly this is not something to do in a production deployment. It lets us proceed with this quick tutorial.
We must restart the service (
docker compose restart) and then rerun the command. A simpler way to run commands inside the container is this:
docker exec -it mqtt-mosquitto-1 \ mosquitto_sub -v -t test/message
This sets up a subscriber to the
test/message topic. Any messages posted to this topic will be printed.
To send a message we can do this:
docker exec -it mqtt-mosquitto-1 \ mosquitto_pub -t test/message -m 'Hello World!'
This publishes a message to the named topic. In the other command window, the subscriber process will print this:
test/message Hello World!
Message delivered, hello to the world.
Using the Mosquitto client programs outside the Docker container
We've used the two Mosquitto client programs,
mosquitto_pub, running them inside the container. The
docker exec command lets us enter the running container, and execute commands. While useful for a simple demonstration, this is not at all how a production system would operate. Instead, our applications would connect over the network to the service. To mimic that, let's run the Mosquitto clients outside the container.
Often we can install the clients on our laptop. For example, my laptop runs Ubuntu, and I ran this command:
$ sudo apt install mosquitto-clients
For macOS there are packages in the MacPorts or HomeBrew repositories, and on Windows it is recommended to look at the Chocolatey repository.
This means I can run Mosquitto commands from the laptop, such as these:
mosquitto_sub -h localhost -p 1883 -v -t test/message mosquitto_pub -h localhost -p 1883 -t test/message -m 'Hello World!'
-h option specifies a host name or IP address for the Mosquitto server. The
-p option specifies the port number. You might have deployed Mosquitto to a distant server, and this is how you get there.
Implementing authentication for Mosquitto
The mosquitto server supports several kinds of authentication. As we said earlier, this is necessary for a production deployment. The configuration file shown above allows anonymous access, which throws any sense of security out the window.
What we'll do is set up a simple password file.
mosquitto.conf add this line:
This says to use the named file to store username/password pairs. The format is
username:password, and the contents are managed using the
To support this we need to change
docker-compose.yml to mount a new directory:
services: mosquitto: image: eclipse-mosquitto ... volumes: ... - ./etc:/mosquitto/etc/
We mount a directory into the container, and therefore must create that directory:
mkdir etc touch etc/passwd
Next, you can start or restart the Mosquitto container. There are no users defined in the
passwd file, so let's create one.
docker exec -it mqtt-mosquitto-1 mosquitto_passwd /mosquitto/etc/passwd henry Password: Reenter password:
This works similarly to the Unix/Linux/etc
passwd command, of course.
It is necessary at this point to restart the Mosquitto container. In testing, it seemed that the server would not recognize new users or changed passwords until it is restarted.
At this point you can subscribe to a topic by adding the user name and password:
mosquitto_sub -u henry --pw passw0rd -h localhost -p 1883 -v -t test/message
The new options are
-u, specifying the user name, and
--pw, specifying the password.
To send messages requires a similar change:
mosquitto_pub -u henry -P passw0rd -h localhost -p 1883 -t test/message -m 'Hello World!'
-P option is an alternate way of specifying
--pw. As before, running this command will cause the message to be printed by
The Mosquitto server supports many more capabilities than we've touched on in this article. For example, we can authenticate users using SSL certificates, and each user can have an ACL limiting their capabilities. Another important feature is the ability to persist data.
Setting up the Mosquitto server in Docker is very simple. Doing so simply requires a few configuration files and settings.