# MQTTS Quick Reference ## Quick Start For fast MQTTS setup with default settings: ```bash # 1. Set domain DOMAIN="mq.example.com" # 2. Verify DNS dig $DOMAIN +short # 3. Issue certificate ~/.acme.sh/acme.sh --issue --dns dns_ali -d $DOMAIN --keylength 2048 # 4. Install with auto-reload ~/.acme.sh/acme.sh --install-cert -d $DOMAIN \ --cert-file /root/certs/$DOMAIN/cert.pem \ --key-file /root/certs/$DOMAIN/key.pem \ --fullchain-file /root/certs/$DOMAIN/fullchain.pem \ --reloadcmd "docker restart emqx" # 5. Fix permissions chmod 755 /root/certs/$DOMAIN chmod 644 /root/certs/$DOMAIN/*.pem # 6. Recreate EMQX container with cert mount docker stop emqx && docker rm emqx docker run -d --name emqx --restart unless-stopped \ -p 1883:1883 -p 8083-8084:8083-8084 -p 8883:8883 -p 18083:18083 \ -v /root/emqx/data:/opt/emqx/data \ -v /root/emqx/log:/opt/emqx/log \ -v /root/certs/$DOMAIN:/opt/emqx/etc/certs:ro \ emqx/emqx:5.8.8 # 7. Verify sleep 5 docker exec emqx emqx ctl listeners | grep ssl openssl s_client -connect $DOMAIN:8883 -servername $DOMAIN < /dev/null ``` ## Client Connection ### Python (System CA) ```python import paho.mqtt.client as mqtt import ssl client = mqtt.Client() client.username_pw_set("user", "pass") client.tls_set(cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2) client.connect("mq.example.com", 8883, 60) ``` ### Python (with fullchain.pem) ```python client.tls_set(ca_certs="fullchain.pem", cert_reqs=ssl.CERT_REQUIRED) client.connect("mq.example.com", 8883, 60) ``` ### Node.js ```javascript const mqtt = require('mqtt'); const client = mqtt.connect('mqtts://mq.example.com:8883', { username: 'user', password: 'pass', rejectUnauthorized: true }); ``` ### ESP32 ```cpp #include #include const char* root_ca = "-----BEGIN CERTIFICATE-----\n"...; // from fullchain.pem WiFiClientSecure espClient; PubSubClient client(espClient); void setup() { espClient.setCACert(root_ca); client.setServer("mq.example.com", 8883); client.connect("ESP32", "user", "pass"); } ``` ## Common Commands ### Certificate Management ```bash # List certificates ~/.acme.sh/acme.sh --list # Check certificate info ~/.acme.sh/acme.sh --info -d $DOMAIN # Force renewal ~/.acme.sh/acme.sh --renew -d $DOMAIN --force # View certificate details openssl x509 -in /root/certs/$DOMAIN/cert.pem -text -noout # Check expiry openssl x509 -in /root/certs/$DOMAIN/cert.pem -noout -dates # Get fingerprint openssl x509 -in /root/certs/$DOMAIN/cert.pem -noout -fingerprint -sha256 ``` ### EMQX Management ```bash # Check listeners docker exec emqx emqx ctl listeners # Check connections docker exec emqx emqx ctl broker stats # View logs docker logs emqx --tail 100 -f # Restart container docker restart emqx # Check certificate files docker exec emqx ls -l /opt/emqx/etc/certs/ ``` ### Testing ```bash # Test SSL connection openssl s_client -connect $DOMAIN:8883 -servername $DOMAIN # Test with mosquitto mosquitto_pub -h $DOMAIN -p 8883 \ --capath /etc/ssl/certs \ -t "test/topic" -m "hello" \ -u "username" -P "password" # Test with custom CA mosquitto_pub -h $DOMAIN -p 8883 \ --cafile fullchain.pem \ -t "test/topic" -m "hello" \ -u "username" -P "password" ``` ### Backup & Export ```bash # Create backup cd /root/certs tar czf $DOMAIN-backup-$(date +%Y%m%d).tar.gz $DOMAIN/ # Download (from local machine) scp root@SERVER_IP:/root/certs/$DOMAIN-backup-*.tar.gz ./ # Extract public key openssl rsa -in $DOMAIN/key.pem -pubout -out $DOMAIN/public.pem # Get public key fingerprint openssl rsa -in $DOMAIN/key.pem -pubout 2>/dev/null | openssl md5 ``` ## Troubleshooting ### DNS not resolving ```bash dig $DOMAIN +short nslookup $DOMAIN # Wait 5-10 minutes for propagation ``` ### Certificate issuance failed ```bash # Check DNS API credentials cat ~/.acme.sh/account.conf | grep Ali_ # Test with debug mode ~/.acme.sh/acme.sh --issue --dns dns_ali -d $DOMAIN --debug 2 ``` ### SSL connection failed ```bash # Check port is open nc -zv $DOMAIN 8883 # Check firewall iptables -L -n | grep 8883 # Test with insecure (testing only) mosquitto_pub -h $DOMAIN -p 8883 --insecure -t test -m hello ``` ### Container won't start ```bash # Check logs docker logs emqx # Check permissions ls -la /root/certs/$DOMAIN/ # Fix permissions chmod 755 /root/certs/$DOMAIN chmod 644 /root/certs/$DOMAIN/*.pem ``` ## Key Concepts ### Single-Direction TLS (Current Setup) - Client verifies server identity (via certificate) - Server authenticates client (via username/password) - Client needs: System CA OR fullchain.pem - Client does NOT need: server public key, server private key ### File Purpose - `cert.pem`: Server certificate (contains public key) - `key.pem`: Server private key (CONFIDENTIAL) - `fullchain.pem`: Server cert + intermediate + root CA - `public.pem`: Public key extracted from private key - `cacert.pem`: CA certificate (usually symlink to fullchain) ### Client Requirements | Client Type | Needs | Reason | |-------------|-------|--------| | PC/Mac/Server | Nothing (system CA) | OS trusts ZeroSSL | | Android/iOS | Nothing (system CA) | OS trusts ZeroSSL | | ESP32/Arduino | fullchain.pem | No system CA access | | Docker | System CA or fullchain.pem | Depends on base image | ### Auto-Renewal - Cron: Daily at 00:34 - Threshold: 60 days before expiry - Action: Renew cert → Install → Restart EMQX - No client action needed (unless using public key pinning) ## Important Notes 1. **Domain Required**: Must use domain name (mq.example.com), NOT IP address 2. **DNS Must Resolve**: A record must point to server before certificate issuance 3. **Port 8883**: Ensure firewall allows port 8883 for MQTTS 4. **Time Sync**: Server and client clocks must be accurate for TLS 5. **Key Reuse**: acme.sh reuses private key by default (public key stays same) 6. **Certificate Chain**: Modern clients need full chain, not just server cert ## Quick Diagnosis ### Check Everything ```bash DOMAIN="mq.example.com" echo "=== DNS ===" dig $DOMAIN +short echo "=== Certificate ===" openssl x509 -in /root/certs/$DOMAIN/cert.pem -noout -dates -subject echo "=== EMQX Container ===" docker ps | grep emqx echo "=== Listeners ===" docker exec emqx emqx ctl listeners | grep -A 5 ssl echo "=== SSL Test ===" timeout 5 openssl s_client -connect $DOMAIN:8883 -servername $DOMAIN < /dev/null 2>&1 | grep -E "Verify return|subject=|issuer=" echo "=== Auto-Renewal ===" ~/.acme.sh/acme.sh --list | grep $DOMAIN echo "=== Cron ===" crontab -l | grep acme ``` ## Reference - EMQX Config: `/opt/emqx/etc/emqx.conf` (in container) - Certificates: `/root/certs/$DOMAIN/` (on host) → `/opt/emqx/etc/certs/` (in container) - acme.sh: `~/.acme.sh/` - Logs: `/root/emqx/log/` (host) or `docker logs emqx` - Dashboard: http://SERVER_IP:18083 (default: admin/public)