Eclipse Mosquitto es un broker MQTT ligero y de código abierto que implementa las versiones 3.1.1 y 5.0 del protocolo. Es la opción habitual para recoger datos de sensores, domótica y dispositivos IoT, porque consume muy pocos recursos y funciona con cualquier cliente MQTT. En este tutorial instalarás Mosquitto en Ubuntu 24.04, crearás usuarios con contraseña, limitarás qué topics puede usar cada uno con una ACL y expondrás el broker a Internet solo por el puerto cifrado 8883 con un certificado de Let's Encrypt.

Requisitos previos

Para seguir esta guía necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath. Con 1 GB de RAM es suficiente para miles de conexiones ligeras.
  • Un usuario no root con privilegios sudo.
  • UFW activo con el acceso SSH permitido.
  • Un dominio o subdominio (en esta guía, mqtt.your_domain) con un registro DNS A que apunte a la IP pública del servidor. Es necesario para obtener el certificado TLS.
  • El puerto 80/tcp libre durante la emisión del certificado.

Paso 1: Instalar Mosquitto

Ubuntu 24.04 incluye Mosquitto 2.0 en sus repositorios. Instala el broker y los clientes de línea de comandos mosquitto_pub y mosquitto_sub:

sudo apt update
sudo apt install mosquitto mosquitto-clients

El paquete habilita e inicia el servicio automáticamente. Comprueba que está activo:

sudo systemctl status mosquitto --no-pager
● mosquitto.service - Mosquitto MQTT Broker
     Loaded: loaded (/usr/lib/systemd/system/mosquitto.service; enabled; preset: enabled)
     Active: active (running) since ...

Sin configuración adicional, Mosquitto 2.0 solo escucha en localhost:1883 y acepta clientes anónimos. Haz una prueba rápida. Abre una segunda sesión SSH y suscríbete a un topic:

mosquitto_sub -h localhost -t 'prueba/#' -v

Desde la primera sesión, publica un mensaje:

mosquitto_pub -h localhost -t 'prueba/hola' -m 'funciona'

En la sesión del suscriptor aparecerá:

prueba/hola funciona

Pulsa Ctrl+C para cerrar el suscriptor.

Paso 2: Crear usuarios con contraseña

A partir de aquí el broker exigirá usuario y contraseña. Crea el archivo de contraseñas con un primer usuario, por ejemplo sensor1. La opción -c crea el archivo, así que úsala solo la primera vez:

sudo mosquitto_passwd -c /etc/mosquitto/passwd sensor1

Añade un segundo usuario, panel, que usará una aplicación para leer los datos:

sudo mosquitto_passwd /etc/mosquitto/passwd panel

Introduce una contraseña robusta para cada uno cuando te la pida. Las contraseñas se guardan con hash, no en texto plano.

Mosquitto vuelve a leer este archivo con su propio usuario sin privilegios cuando recarga la configuración, así que ajusta el propietario y los permisos:

sudo chown mosquitto:mosquitto /etc/mosquitto/passwd
sudo chmod 600 /etc/mosquitto/passwd

Paso 3: Definir permisos por topic con una ACL

La lista de control de acceso (ACL) decide qué topics puede leer o escribir cada usuario. Sin ella, cualquier usuario autenticado podría publicar en cualquier topic. Crea el archivo:

sudo nano /etc/mosquitto/acl

Añade estas reglas:

# sensor1 solo publica sus propias lecturas y recibe comandos
user sensor1
topic write sensores/sensor1/#
topic read comandos/sensor1

# panel lee todas las lecturas y puede enviar comandos
user panel
topic read sensores/#
topic write comandos/#

# Cada usuario puede leer y escribir bajo dispositivos/<su usuario>/
pattern readwrite dispositivos/%u/#

Las líneas user aplican las reglas topic que las siguen a ese usuario, y pattern aplica a todos, sustituyendo %u por el nombre de usuario. Todo lo que no está permitido explícitamente queda denegado.

Ajusta los permisos igual que con el archivo de contraseñas:

sudo chown mosquitto:mosquitto /etc/mosquitto/acl
sudo chmod 600 /etc/mosquitto/acl

Paso 4: Obtener un certificado TLS de Let's Encrypt

MQTT sin cifrar envía usuarios, contraseñas y datos en claro, así que el acceso desde Internet debe ir por TLS. Instala Certbot y abre temporalmente el puerto 80 para la validación:

sudo apt install certbot
sudo ufw allow 80/tcp

Solicita el certificado en modo standalone, que levanta un servidor web temporal:

sudo certbot certonly --standalone -d mqtt.your_domain
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/mqtt.your_domain/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/mqtt.your_domain/privkey.pem

Mosquitto no puede leer directamente /etc/letsencrypt/live/, que solo es accesible para root. La solución recomendada es un hook de despliegue que copie los certificados a /etc/mosquitto/certs en cada renovación y recargue el broker. Crea el script:

sudo nano /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh
#!/usr/bin/env bash
set -euo pipefail

DOMAIN="mqtt.your_domain"

if [[ "${RENEWED_LINEAGE:-}" == "/etc/letsencrypt/live/${DOMAIN}" ]]; then
    install -d -m 750 -o mosquitto -g mosquitto /etc/mosquitto/certs
    install -m 644 -o mosquitto -g mosquitto "${RENEWED_LINEAGE}/fullchain.pem" /etc/mosquitto/certs/fullchain.pem
    install -m 600 -o mosquitto -g mosquitto "${RENEWED_LINEAGE}/privkey.pem" /etc/mosquitto/certs/privkey.pem
    systemctl reload mosquitto || true
fi

Hazlo ejecutable y lánzalo una vez a mano, pasando la variable que Certbot define en las renovaciones:

sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh
sudo RENEWED_LINEAGE=/etc/letsencrypt/live/mqtt.your_domain /etc/letsencrypt/renewal-hooks/deploy/mosquitto.sh
sudo ls -l /etc/mosquitto/certs
-rw-r--r-- 1 mosquitto mosquitto 2876 ... fullchain.pem
-rw------- 1 mosquitto mosquitto  241 ... privkey.pem

Certbot renueva el certificado solo mediante su temporizador de systemd, pero el modo standalone necesita el puerto 80 abierto en cada renovación. Si prefieres no dejarlo abierto permanentemente, usa un plugin DNS de Certbot para tu proveedor.

Paso 5: Configurar los listeners de Mosquitto

El archivo principal /etc/mosquitto/mosquitto.conf ya incluye los archivos de /etc/mosquitto/conf.d/ y activa la persistencia en /var/lib/mosquitto/. No lo modifiques; crea un archivo propio:

sudo nano /etc/mosquitto/conf.d/broker.conf
# Opciones globales
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl

# MQTT sin cifrar solo para clientes locales
listener 1883 localhost

# MQTT sobre TLS para clientes remotos
listener 8883
certfile /etc/mosquitto/certs/fullchain.pem
keyfile /etc/mosquitto/certs/privkey.pem
tls_version tlsv1.2

allow_anonymous, password_file y acl_file se aplican a todos los listeners porque per_listener_settings está desactivado por defecto. Las opciones de certificado afectan solo al listener que las precede, en este caso el 8883. tls_version tlsv1.2 fija la versión mínima, así que también se aceptan clientes TLS 1.3.

Reinicia el servicio para aplicar los nuevos listeners:

sudo systemctl restart mosquitto

Comprueba que escucha en los dos puertos:

sudo ss -tlnp | grep mosquitto
LISTEN 0      100        127.0.0.1:1883       0.0.0.0:*    users:(("mosquitto",pid=4121,fd=5))
LISTEN 0      100          0.0.0.0:8883       0.0.0.0:*    users:(("mosquitto",pid=4121,fd=6))
LISTEN 0      100             [::]:8883          [::]:*    users:(("mosquitto",pid=4121,fd=7))

Si el servicio no arranca, el motivo aparece en el registro:

sudo journalctl -u mosquitto -n 30 --no-pager

Paso 6: Abrir el firewall

Permite solo el puerto cifrado. El 1883 escucha en localhost y no debe abrirse:

sudo ufw allow 8883/tcp
sudo ufw status
To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
8883/tcp                   ALLOW       Anywhere

Paso 7: Probar la autenticación, la ACL y TLS

Primero comprueba que el acceso anónimo está bloqueado:

mosquitto_pub -h localhost -t 'prueba/hola' -m 'anon'
Connection error: Connection Refused: not authorised.

Ahora suscríbete como panel por TLS. La opción --capath /etc/ssl/certs hace que el cliente valide el certificado de Let's Encrypt con las CA del sistema. Sustituye panel_password por la contraseña que elegiste:

mosquitto_sub -h mqtt.your_domain -p 8883 --capath /etc/ssl/certs \
  -u panel -P 'panel_password' -t 'sensores/#' -v

En otra sesión, publica una lectura como sensor1:

mosquitto_pub -h mqtt.your_domain -p 8883 --capath /etc/ssl/certs \
  -u sensor1 -P 'sensor1_password' -t 'sensores/sensor1/temperatura' -m '21.7'

El suscriptor recibe el mensaje:

sensores/sensor1/temperatura 21.7

Prueba ahora a publicar como sensor1 en un topic que la ACL no le permite:

mosquitto_pub -h mqtt.your_domain -p 8883 --capath /etc/ssl/certs \
  -u sensor1 -P 'sensor1_password' -t 'sensores/sensor2/temperatura' -m '99'

El comando termina sin error, porque con QoS 0 el broker descarta en silencio las publicaciones no autorizadas, pero el suscriptor no recibe nada. Así se comporta la ACL de Mosquitto.

Paso 8: Conectar un dispositivo desde Python

La mayoría de dispositivos y aplicaciones usan una librería MQTT. Este ejemplo usa paho-mqtt 2.x en un entorno virtual para simular un sensor que publica cada 10 segundos:

sudo apt install python3-venv
python3 -m venv ~/mqtt-venv
~/mqtt-venv/bin/pip install paho-mqtt

Crea el script:

nano ~/sensor.py
import json
import random
import time

import paho.mqtt.client as mqtt

BROKER = "mqtt.your_domain"
USUARIO = "sensor1"
PASSWORD = "sensor1_password"


def on_connect(client, userdata, flags, reason_code, properties):
    print(f"Conectado: {reason_code}")
    client.subscribe("comandos/sensor1")


def on_message(client, userdata, msg):
    print(f"Comando recibido en {msg.topic}: {msg.payload.decode()}")


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="sensor1")
client.username_pw_set(USUARIO, PASSWORD)
client.tls_set()  # valida el certificado con las CA del sistema
client.on_connect = on_connect
client.on_message = on_message

client.connect(BROKER, 8883)
client.loop_start()

try:
    while True:
        lectura = {"temperatura": round(random.uniform(19, 24), 1)}
        client.publish("sensores/sensor1/temperatura", json.dumps(lectura), qos=1)
        time.sleep(10)
except KeyboardInterrupt:
    client.loop_stop()
    client.disconnect()

Ejecútalo con el suscriptor de panel del paso anterior todavía abierto:

~/mqtt-venv/bin/python ~/sensor.py
Conectado: Success

El suscriptor mostrará una lectura nueva cada 10 segundos, por ejemplo sensores/sensor1/temperatura {"temperatura": 22.4}.

Solución de problemas

  • Connection Refused: not authorised: usuario o contraseña incorrectos, o el archivo /etc/mosquitto/passwd no pertenece a mosquitto. Revisa los permisos del paso 2 y reinicia el servicio.
  • Error: A TLS error occurred o fallo de verificación del certificado: te estás conectando por IP o por un nombre distinto al del certificado. Usa exactamente mqtt.your_domain.
  • El servicio no arranca tras editar broker.conf: una opción mal escrita detiene Mosquitto. sudo journalctl -u mosquitto -n 30 indica la línea exacta.
  • Los mensajes no llegan pero no hay errores: casi siempre es la ACL. Comprueba que el topic de publicación encaja en alguna regla topic write o pattern de ese usuario, respetando mayúsculas y barras.

Conclusión

Tienes un broker Mosquitto en Ubuntu 24.04 que exige autenticación, limita cada usuario a sus topics y solo acepta conexiones remotas cifradas con un certificado que se renueva de forma automática. Como siguientes pasos, puedes añadir un listener WebSocket (protocol websockets) para clientes web, conectar un bridge hacia otro broker con la sección connection de la configuración, o almacenar las lecturas en una base de datos de series temporales con un consumidor como Telegraf o Node-RED.