Mosquitto + TLS sobre AWS EC2
Guía paso a paso para desplegar un broker MQTT seguro con cifrado TLS sobre una instancia EC2 de AWS, con Docker: instancia, certificados, ejecución y verificación.
facumruiz/mosquitto-tlsCómo desplegar un broker MQTT (Mosquitto) con TLS habilitado sobre una instancia EC2 de AWS, usando Docker y un repositorio con la configuración y los certificados. Pensada para montar rápido un broker seguro para IoT o mensajería entre dispositivos.
El proceso se divide en dos partes: (1) creación y configuración de una instancia EC2 en AWS, y (2) instalación de Docker, clonado del repositorio y ejecución del broker con TLS. Se suman dos secciones: cómo verificar la conexión TLS y solución de problemas comunes.
Prerrequisitos
Cuenta de AWS con permisos para crear instancias EC2 · conocimientos básicos de línea de comandos y SSH · Git y un cliente SSH en tu máquina local · acceso al repo de configuración (facumruiz/mosquitto-tls).
Parte 1 · Instancia EC2 en AWS
Paso 1 — Iniciar sesión y abrir EC2
Ingresá a la consola de AWS y accedé al servicio EC2 desde el buscador superior o el panel de servicios.

Paso 2 — Crear una nueva instancia
Desde el Dashboard de EC2, entrá a «Instancias» → «Lanzar instancia». Poné un nombre descriptivo (por ej. mosquitto-tls), elegí una AMI basada en Linux (Ubuntu o Debian) y dejá el tipo t2.micro / t3.micro para mantenerte en la capa gratuita.

Paso 3 — Red y seguridad
En Configuraciones de red, el asistente ofrece checkboxes para SSH (22), HTTP y HTTPS (443, opcional). El puerto 8883 (MQTT sobre TLS) no aparece como checkbox: agregalo manualmente como regla personalizada — Tipo: TCP personalizado · Puerto: 8883 · Origen: 0.0.0.0/0 (mejor, tu rango de IPs conocidas).

Paso 4 — Par de claves (.pem)
En la sección de par de claves, elegí «Crear un nuevo par de claves», tipo RSA y formato .pem (OpenSSH/Linux/macOS) o .ppk (PuTTY en Windows). Guardá el .pem en un lugar seguro: hace falta para el SSH y no se puede volver a descargar.


Paso 5 — IP pública de la instancia
La necesitás para el SSH y para el certificado TLS (Parte 2, Paso 3). En EC2 → Instancias, abrí tu instancia y copiá el campo «IPv4 pública» en la pestaña Detalles.
Paso 6 — Conectarse por SSH
chmod 400 tu_clave.pem
ssh -i tu_clave.pem <usuario>@<ip-publica-instancia> Reemplazá <usuario> según la AMI: ubuntu (Ubuntu), admin (Debian) o ec2-user (Amazon Linux), y <ip-publica-instancia> por la IP del Paso 5.
Parte 2 · Docker, Git y el broker
Paso 1 — Instalar Docker y Git
# Actualizar el sistema
sudo apt update
# Instalar Docker y sus herramientas
sudo apt install docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin -y
# Instalar git
sudo apt install git -y Paso 2 — Clonar el repositorio
git clone https://github.com/facumruiz/mosquitto-tls.git
cd mosquitto-tls
git checkout version/aws La rama version/aws trae la config lista para EC2: docker-compose.yml (define y expone el broker en 8883), Dockerfile (imagen sobre eclipse-mosquitto:2.0), config/mosquitto.conf (listener TLS 8883), generate-certs.sh (genera la CA y el certificado) y la carpeta certs/ (la crea el script).
Paso 3 — Generar los certificados TLS
nano generate-certs.sh
# Reemplazar 3.132.251.70 por tu IP pública en:
# -subj ".../CN=3.132.251.70" (CSR del servidor)
# subjectAltName = IP:3.132.251.70 (extensión SAN) chmod +x generate-certs.sh
./generate-certs.sh El script crea certs/ con la autoridad certificadora (ca.key, ca.crt) y el certificado de servidor (server.key, server.crt) firmado con el CN/SAN configurado.
Paso 4 — Levantar el contenedor
sudo docker compose up -d La primera vez construye la imagen desde el Dockerfile (copiando config y certs) y levanta el contenedor mosquitto_tls en segundo plano.
Paso 5 — Verificar que corre
sudo docker ps
CONTAINER ID IMAGE PORTS NAMES
abc12345 mosquitto_tls 0.0.0.0:8883->8883/tcp mosquitto_tls Paso 6 — Verificar los logs
docker compose logs mosquitto
mosquitto-1 | mosquitto version 2.0.21 starting
mosquitto-1 | Config loaded from /mosquitto/config/mosquitto.conf.
mosquitto-1 | Opening ipv4 listen socket on port 8883.
mosquitto-1 | mosquitto version 2.0.21 running Parte 3 · Cómo funciona el repositorio
Opcional: no hace falta para levantar el broker, pero ayuda a entender cada archivo y modificarlo con confianza.
docker-compose.yml
version: '3.7'
services:
mosquitto:
build: .
container_name: mosquitto_tls
ports:
- "8883:8883"
volumes:
- ./config/mosquitto.conf:/mosquitto/config/mosquitto.conf
- ./certs:/mosquitto/certs
restart: unless-stopped build: . construye la imagen desde el Dockerfile local. container_name le da un nombre fijo (mosquitto_tls). ports mapea 8883 del host al 8883 del contenedor. volumes monta la config y los certificados adentro, así editar cualquiera solo requiere reiniciar el contenedor. restart: unless-stopped lo relevanta solo si se cae o si reiniciás la EC2.
Dockerfile
FROM eclipse-mosquitto:2.0
COPY config/mosquitto.conf /mosquitto/config/mosquitto.conf
COPY certs /mosquitto/certs Parte de la imagen oficial que ya trae el broker y copia la config y los certificados a las rutas donde Mosquitto los espera. Como el compose también los monta como volúmenes, en ejecución mandan los archivos de la instancia; el COPY deja la imagen funcional aunque un día la corras sin volúmenes.
generate-certs.sh
Crea una CA propia y un certificado de servidor firmado por ella. Analogía: la CA emite un «documento de identidad» (ca.crt) en el que los clientes confían; server.crt es el «DNI» del broker, firmado por esa CA. Lo vemos por bloques:
1 · Define los nombres de archivo dentro de certs/ y crea la carpeta.
CERT_DIR="./certs"
CA_KEY="$CERT_DIR/ca.key"
CA_CRT="$CERT_DIR/ca.crt"
SERVER_KEY="$CERT_DIR/server.key"
SERVER_CSR="$CERT_DIR/server.csr"
SERVER_CRT="$CERT_DIR/server.crt"
EXTFILE="$CERT_DIR/server_ext.cnf"
mkdir -p "$CERT_DIR" 2 · Crea la CA: una clave RSA 2048 (la «llave maestra») y con ella un certificado autofirmado válido 365 días. ca.crt es el archivo que se copia a cada cliente.
openssl genrsa -out "$CA_KEY" 2048
openssl req -x509 -new -nodes -key "$CA_KEY" -sha256 -days 365 \
-subj "/C=AR/ST=BuenosAires/L=CABA/O=FacundoRP/CN=MQTT_CA" \
-out "$CA_CRT" 3 · Genera la clave privada del servidor (nunca sale de la instancia) y un CSR: una solicitud de certificado con el CN = la IP que los clientes van a validar. Ese CN es el dato a reemplazar por tu IP (Parte 2, Paso 3).
openssl genrsa -out "$SERVER_KEY" 2048
openssl req -new -key "$SERVER_KEY" \
-subj "/C=AR/ST=BuenosAires/L=CABA/O=FacundoRP/CN=3.132.251.70" \
-out "$SERVER_CSR" 4 · Agrega el SAN (subjectAltName). Los clientes modernos —incluido mosquitto_sub— validan el SAN además del CN; sin él, el certificado sería rechazado.
cat > "$EXTFILE" <<EOF
subjectAltName = IP:3.132.251.70
EOF 5 · La CA firma el CSR del servidor incluyendo el SAN. El resultado, server.crt, es el certificado final que Mosquitto presenta a cada cliente.
openssl x509 -req -in "$SERVER_CSR" -CA "$CA_CRT" -CAkey "$CA_KEY" \
-CAcreateserial -out "$SERVER_CRT" -days 365 -sha256 \
-extfile "$EXTFILE" 6 · Borra el CSR y el archivo de extensión temporales: ya quedaron «incorporados» dentro de server.crt.
rm -f "$SERVER_CSR" "$EXTFILE" Parte 4 · Verificar la conexión TLS
Opción A — desde la misma instancia
# Instalar el cliente
sudo apt install mosquitto-clients -y
# Suscribirse a un tópico
mosquitto_sub -h localhost -p 8883 \
--cafile ./certs/ca.crt -t "test/topic" -d
# Publicar (en otra terminal)
mosquitto_pub -h localhost -p 8883 \
--cafile ./certs/ca.crt -t "test/topic" -m "¡Hola TLS!" Corré ambos parado en la carpeta del repo (donde está certs/). Si el mensaje aparece en la terminal del mosquitto_sub, el broker funciona con TLS.
Opción B — desde tu computadora
scp -i tu_clave.pem admin@<ip-publica-instancia>:~/mosquitto-tls/certs/ca.crt .
mosquitto_sub -h <ip-publica-instancia> -p 8883 \
--cafile ca.crt -t "test/topic" -d Solo funciona si el certificado se generó con el CN/SAN igual a esa IP pública (Parte 2, Paso 3) y si el 8883 está abierto en el grupo de seguridad (Parte 1, Paso 3).
Buenas prácticas de seguridad
Restringí SSH (22) y, si podés, 8883 a IPs conocidas · mantené el SO y Docker actualizados (sudo apt update && sudo apt upgrade) · sumá autenticación por usuario/contraseña o certificados de cliente además de TLS · rotá los certificados antes de que expiren · no guardes el .pem en repos ni carpetas compartidas.
Solución de problemas
No puedo conectarme por SSH
El .pem debe tener permisos 400 (chmod 400 tu_clave.pem) · el grupo de seguridad debe permitir el 22 desde tu IP · usá el usuario correcto según la AMI (ubuntu, admin, ec2-user).
No puedo conectarme al broker (8883)
Confirmá la regla de firewall TCP 8883 (Parte 1, Paso 3) · revisá docker compose logs mosquitto por errores de arranque · verificá que el contenedor corre con docker ps.
Error de certificado (hostname mismatch)
Es el error más común: el CN/SAN no coincide con la IP a la que te conectás porque no se editó generate-certs.sh (Parte 2, Paso 3). Regenerá los certificados con la IP correcta y reiniciá: docker compose up -d --build. Como último recurso solo para pruebas, existe --insecure en mosquitto_sub/pub — nunca en producción.