- 本地化命令描述(英文→中文) - 删除未使用命令文件 - 新增 summarize-conversation 命令 - 更新 AI 模型配置为 DeepSeek - 新增 agent-browser 技能 - 重构技能目录结构(重命名)
278 lines
6.7 KiB
Markdown
278 lines
6.7 KiB
Markdown
# 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 <WiFiClientSecure.h>
|
|
#include <PubSubClient.h>
|
|
|
|
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)
|