# EMQX con SSL/TLS Configurado - iot.lambicall.com

## Estado de la Configuración SSL

✓ SSL/TLS está completamente configurado y funcionando en EMQX
✓ Certificados Let's Encrypt instalados y válidos
✓ Renovación automática de certificados configurada

## Información del Certificado

- **Dominio**: iot.lambicall.com
- **Emisor**: Let's Encrypt (CN=E8)
- **Válido desde**: Dec 6 02:44:52 2025 GMT
- **Válido hasta**: Mar 6 02:44:51 2026 GMT (90 días)
- **Tipo**: ECC (Elliptic Curve Cryptography) - 256 bits
- **Renovación**: Automática (Certbot)

## Puertos Disponibles

### MQTT
| Puerto | Protocolo | SSL/TLS | Descripción |
|--------|-----------|---------|-------------|
| 1883 | MQTT | No | MQTT estándar sin cifrar |
| 8883 | MQTTS | Sí | MQTT con SSL/TLS |

### WebSocket
| Puerto | Protocolo | SSL/TLS | Descripción |
|--------|-----------|---------|-------------|
| 8083 | WS | No | WebSocket sin cifrar |
| 8084 | WSS | Sí | WebSocket con SSL/TLS |

### Dashboard
| Puerto | Protocolo | SSL/TLS | Descripción |
|--------|-----------|---------|-------------|
| 18083 | HTTP | No | Dashboard web y API REST |

## Conexión MQTT con SSL/TLS

### Usando mosquitto_pub/sub

**Publicar mensaje con SSL:**
```bash
mosquitto_pub -h iot.lambicall.com -p 8883 \
  -t "test/topic" \
  -m "Mensaje seguro" \
  --capath /etc/ssl/certs/
```

**Suscribirse con SSL:**
```bash
mosquitto_sub -h iot.lambicall.com -p 8883 \
  -t "test/topic" \
  -v \
  --capath /etc/ssl/certs/
```

**Con autenticación de usuario:**
```bash
mosquitto_pub -h iot.lambicall.com -p 8883 \
  -t "test/topic" \
  -m "Mensaje seguro" \
  -u "usuario" \
  -P "password" \
  --capath /etc/ssl/certs/
```

### Cliente JavaScript/Node.js

```javascript
const mqtt = require('mqtt');

const options = {
    host: 'iot.lambicall.com',
    port: 8883,
    protocol: 'mqtts',  // MQTT sobre TLS
    clientId: 'cliente_' + Math.random().toString(16).substr(2, 8),
    clean: true,
    connectTimeout: 4000,
    // username: 'tu_usuario',
    // password: 'tu_password',
    rejectUnauthorized: true,  // Verificar certificado del servidor
};

const client = mqtt.connect(options);

client.on('connect', () => {
    console.log('Conectado a EMQX con SSL/TLS');
    client.subscribe('test/topic', (err) => {
        if (!err) {
            client.publish('test/topic', 'Hola desde Node.js con SSL');
        }
    });
});

client.on('message', (topic, message) => {
    console.log(`Mensaje recibido: ${message.toString()}`);
});

client.on('error', (error) => {
    console.error('Error de conexión:', error);
});
```

### Cliente Python

```python
import paho.mqtt.client as mqtt
import ssl

def on_connect(client, userdata, flags, rc):
    print(f"Conectado con código: {rc}")
    client.subscribe("test/topic")

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

# Crear cliente
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# Configurar SSL/TLS
client.tls_set(
    ca_certs=None,  # Usa certificados del sistema
    certfile=None,
    keyfile=None,
    cert_reqs=ssl.CERT_REQUIRED,
    tls_version=ssl.PROTOCOL_TLS,
    ciphers=None
)

# Autenticación (opcional)
# client.username_pw_set("usuario", "password")

# Conectar con SSL
client.connect("iot.lambicall.com", 8883, 60)

# Loop
client.loop_forever()
```

### Cliente ESP32/Arduino

```cpp
#include <WiFi.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>

const char* ssid = "TU_WIFI";
const char* password = "TU_PASSWORD";
const char* mqtt_server = "iot.lambicall.com";
const int mqtt_port = 8883;

// Root CA Certificate (Let's Encrypt ISRG Root X1)
const char* root_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \
"-----END CERTIFICATE-----\n";

WiFiClientSecure espClient;
PubSubClient client(espClient);

void setup_wifi() {
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("WiFi conectado");
}

void reconnect() {
    while (!client.connected()) {
        Serial.print("Conectando a MQTT...");
        if (client.connect("ESP32Client")) {
            Serial.println("conectado");
            client.subscribe("test/topic");
        } else {
            Serial.print("falló, rc=");
            Serial.print(client.state());
            delay(5000);
        }
    }
}

void callback(char* topic, byte* payload, unsigned int length) {
    Serial.print("Mensaje recibido: ");
    for (int i = 0; i < length; i++) {
        Serial.print((char)payload[i]);
    }
    Serial.println();
}

void setup() {
    Serial.begin(115200);
    setup_wifi();

    // Configurar certificado raíz
    espClient.setCACert(root_ca);

    client.setServer(mqtt_server, mqtt_port);
    client.setCallback(callback);
}

void loop() {
    if (!client.connected()) {
        reconnect();
    }
    client.loop();
}
```

## WebSocket Seguro (WSS)

### JavaScript en navegador

```javascript
const client = mqtt.connect('wss://iot.lambicall.com:8084/mqtt', {
    clientId: 'web_' + Math.random().toString(16).substr(2, 8),
    clean: true,
    // username: 'usuario',
    // password: 'password',
});

client.on('connect', () => {
    console.log('Conectado a EMQX vía WSS');
    client.subscribe('test/topic');
    client.publish('test/topic', 'Hola desde WebSocket seguro');
});

client.on('message', (topic, message) => {
    console.log(`${topic}: ${message.toString()}`);
});
```

## Verificación de SSL

### Comando para verificar certificado
```bash
openssl s_client -connect iot.lambicall.com:8883 -showcerts
```

### Script de prueba automático
```bash
/var/www/html/emqx/test-ssl.sh
```

Este script verifica:
- Validez del certificado SSL
- Conexión MQTT sobre SSL (puerto 8883)
- Conexión MQTT regular (puerto 1883)
- Estado de listeners SSL/WSS
- Fecha de expiración del certificado

## Ubicación de los Certificados

```
/etc/letsencrypt/live/iot.lambicall.com/
├── fullchain.pem  -> Certificado completo
├── privkey.pem    -> Clave privada
├── cert.pem       -> Certificado del servidor
└── chain.pem      -> Cadena de certificados

/etc/emqx/certs/
├── cert.pem       -> Copia del fullchain.pem (usado por EMQX)
├── key.pem        -> Copia del privkey.pem (usado por EMQX)
└── cacert.pem     -> Copia del chain.pem (usado por EMQX)
```

## Renovación Automática de Certificados

Certbot está configurado para renovar automáticamente los certificados antes de que expiren.

### Verificar renovación automática:
```bash
certbot renew --dry-run
```

### Renovar manualmente (si es necesario):
```bash
certbot renew
systemctl restart emqx
```

### Estado de la renovación:
```bash
systemctl status certbot.timer
```

## Seguridad Adicional Recomendada

### 1. Habilitar autenticación

Desde el Dashboard web (http://iot.lambicall.com:18083):
- Ve a **Authentication**
- Añade un nuevo proveedor de autenticación
- Configura usuarios y contraseñas

### 2. Configurar ACL (Control de Acceso)

Desde el Dashboard:
- Ve a **Authorization**
- Configura reglas de acceso por tema (topic)
- Limita qué clientes pueden publicar/suscribirse a qué temas

### 3. Usar autenticación mutua (mTLS)

Para mayor seguridad, puedes requerir que los clientes también presenten certificados:

Editar `/etc/emqx/emqx.conf`:
```hocon
listeners {
    ssl {
        default {
            bind = "0.0.0.0:8883"
            ssl_options {
                certfile = "${EMQX_ETC_DIR}/certs/cert.pem"
                keyfile = "${EMQX_ETC_DIR}/certs/key.pem"
                cacertfile = "${EMQX_ETC_DIR}/certs/cacert.pem"
                verify = verify_peer  # Cambiar de verify_none
                fail_if_no_peer_cert = true
            }
        }
    }
}
```

## Troubleshooting SSL

### Problema: "Certificate verify failed"
```bash
# Verificar que el certificado sea válido
openssl s_client -connect iot.lambicall.com:8883

# Usar certificados del sistema
mosquitto_pub -h iot.lambicall.com -p 8883 -t "test" -m "test" --capath /etc/ssl/certs/
```

### Problema: "Connection refused"
```bash
# Verificar que el puerto esté abierto
netstat -tulpn | grep 8883

# Verificar firewall
ufw status | grep 8883

# Ver logs de EMQX
journalctl -u emqx -f
```

### Problema: Certificado expirado
```bash
# Renovar certificado
certbot renew

# Copiar nuevos certificados a EMQX
cp /etc/letsencrypt/live/iot.lambicall.com/fullchain.pem /etc/emqx/certs/cert.pem
cp /etc/letsencrypt/live/iot.lambicall.com/privkey.pem /etc/emqx/certs/key.pem
chown -R emqx:emqx /etc/emqx/certs
chmod 600 /etc/emqx/certs/*.pem

# Reiniciar EMQX
systemctl restart emqx
```

## Monitoreo

### Ver conexiones SSL activas:
```bash
emqx ctl listeners | grep -A 10 "ssl:default"
```

### Ver clientes conectados:
```bash
emqx ctl clients list
```

### Estadísticas:
```bash
emqx ctl broker stats
```

---

**SSL/TLS está completamente configurado y funcionando en iot.lambicall.com**

Para soporte adicional, consulta:
- Documentación de EMQX: https://www.emqx.io/docs/
- Let's Encrypt: https://letsencrypt.org/

---

## 🔄 Renovación Automática de Certificados

### ✅ Estado: Completamente Configurado

La renovación automática está configurada y funcionando. No requiere intervención manual.

**Certificado actual:**
- Válido hasta: Mar 6, 2026
- Renovación automática: Cuando falten 30 días (~Feb 4, 2026)

### Cómo Funciona

1. **Timer de Certbot** se ejecuta 2 veces al día (00:00 y 12:00)
2. Cuando el certificado tiene menos de 30 días, **Certbot lo renueva automáticamente**
3. **Hook de deployment** copia automáticamente los nuevos certificados a EMQX
4. **EMQX se reinicia** automáticamente para aplicar los cambios
5. Todo queda registrado en `/var/log/emqx-cert-renewal.log`

### Verificar Estado de Renovación

```bash
# Script completo de verificación
/usr/local/bin/check-emqx-ssl-expiration.sh

# Resultado esperado:
# ✓ Certificado válido y con XX días restantes
# ✓ certbot.timer está activo
# ✓ Hook de renovación configurado
```

### Prueba de Renovación (Dry-Run)

```bash
# Simular renovación sin hacer cambios
sudo certbot renew --dry-run

# Resultado esperado para iot.lambicall.com:
# The following simulated renewals succeeded:
#   /etc/letsencrypt/live/iot.lambicall.com/fullchain.pem (success)
```

### Logs y Monitoreo

```bash
# Ver historial de renovaciones
cat /var/log/emqx-cert-renewal.log

# Ver verificaciones diarias
cat /var/log/emqx-ssl-check.log

# Ver próxima ejecución del timer
systemctl list-timers | grep certbot
```

### Documentación Completa

Para información detallada sobre renovación automática, troubleshooting y configuración:

```bash
cat /var/www/html/SSL_AUTO_RENEWAL.md
```

Este documento incluye:
- Cómo funciona la renovación paso a paso
- Comandos de troubleshooting
- Configuración de alertas por email
- Checklist de verificación
- Ubicación de todos los archivos y logs

---
