EMQX 配置与安全
EMQX Broker 的认证、ACL、TLS、共享订阅配置参考。
1. 设备认证配置(PostgreSQL 直连)
方案选择
设备认证采用 EMQX 直连 PostgreSQL,不走 HTTP 回调。
相比 HTTP Auth,直连方案的优势:
- 少一层 HTTP 往返,认证延迟更低
- MQTT 链路不依赖后端存活,后端重启不影响设备连接
- 测试与生产环境共用同一数据库,EMQX 配置完全一致,消除环境差异
流程
设备 MQTT CONNECT → EMQX 直接查 PostgreSQL devices 表 → 校验凭证 → allow/denyEMQX Dashboard 配置要点
在 EMQX Dashboard → Authentication → PostgreSQL 中配置:
| 配置项 | 值 | 说明 |
|---|---|---|
| Server | postgres:5432 | PostgreSQL 地址 |
| Database | yunstack_iot | 数据库名 |
| Username | emqx | 数据库用户(建议使用只读账号) |
| Password | (从环境变量获取) | 数据库密码 |
| Password Hash Algorithm | bcrypt | 密码哈希算法 |
SQL 查询语句
认证查询(Authentication Query):
sql
SELECT password_hash AS password_hash, 'sha256' AS password_hash_algorithm
FROM devices
WHERE physical_id = ${clientid}
AND username = ${username}
AND deleted_at IS NULL
LIMIT 1${clientid}对应 MQTT ClientId(设备物理 ID / MAC 地址)${username}对应 MQTT Username(产品 ProductKey)${password}由 EMQX 根据password_hash_algorithm自动与查询结果对比,无需在 SQL 中手动比较- 返回行 = 认证通过,无返回 = 认证拒绝
注意:设备需提前在数据库中创建(通过配网流程或管理后台预录入),不支持连接时自动注册。
2. ACL 权限规则(EMQX 内置)
概述
使用 EMQX 内置 ACL(基于文件或内置规则),无需 HTTP 回调,也不需要额外配置 PostgreSQL ACL。
核心规则
EMQX 内置 ACL 通过 Topic 模式匹配实现设备隔离:
| 设备身份 | 允许操作 | Topic 模式 |
|---|---|---|
| 设备自身({did}) | Pub | sys/{pid}/{did}/thing/event/+/post、sys/{pid}/{did}/thing/service/+/set_reply、sys/{pid}/{did}/thing/config/set_reply、sys/{pid}/{did}/thing/ota/progress |
| 设备自身({did}) | Sub | sys/{pid}/{did}/thing/service/+/set、sys/{pid}/{did}/thing/config/set、sys/{pid}/{did}/thing/ota/upgrade |
| 后端服务(admin 客户端) | Pub/Sub | sys/+/+/thing/#(共享订阅前缀由后端客户端自行添加) |
| 其他设备 | 拒绝 | 所有 Topic |
EMQX Dashboard 配置
在 EMQX Dashboard → Authorization → Built-in Database 中配置规则,使用 ${username}(ProductKey)和 ${clientid}(Physical ID)变量动态匹配。
详细 Topic 定义见 06.MQTT通信协议。
3. 共享订阅组配置
对应 06.MQTT通信协议 3.1 节。
订阅列表
后端服务作为 MQTT 客户端,使用共享订阅前缀 $share/group1/ 订阅以下通配符 Topic:
$share/group1/sys/+/+/thing/event/#
$share/group1/sys/+/+/thing/service/+/set_reply
$share/group1/sys/+/+/thing/config/set_reply
$share/group1/sys/+/+/thing/ota/progress负载均衡
- 策略:EMQX 默认
round_robin,多个 NestJS 实例平均分摊设备消息 - 同一条消息只会投递给组内的一个订阅者,不会重复处理
- 共享订阅在客户端订阅时通过 topic 前缀声明,EMQX 侧无需额外配置
4. 在线状态机制
在线状态由属性上报驱动,不使用 Webhook:
- 设备上报属性时,后端在 Redis 中设置在线标记,TTL 120 秒
- 120 秒内无新上报 → Redis key 自动过期 → 设备判定离线
- 无需配置 EMQX Webhook,与 EMQX 部署无关,后端独立运作
详细流程见 02.核心业务流程 第 2 节。
5. MQTTS TLS 配置
生产环境必须启用 TLS,设备端使用 MQTTS 端口 8883 连接。
EMQX 侧配置
| 配置项 | 说明 |
|---|---|
| SSL 监听端口 | 8883 |
| TLS 证书文件 | PEM 格式公签证书或自签名证书 |
| 私钥文件 | PEM 格式,权限 600 |
| 客户端证书 | 暂用单向认证(EMQX 不验证设备证书) |
证书获取
| 环境 | 方案 |
|---|---|
| 测试/内网 | 自签名证书或 mkcert |
| 生产 | Let's Encrypt 或云厂商 SSL 证书 |
设备端要求
ESP32 固件需配置 CA 证书以验证服务器身份,避免中间人攻击。详见 设备接入指南。
Nginx 侧
若前端通过 WebSocket over TLS 连接 EMQX,Nginx 也需要配置对应 SSL 证书,将 WSS 请求代理到 EMQX 8083 端口。
6. Dashboard 管理账号
| 操作 | 说明 |
|---|---|
| 默认端口 | http://<host>:18083 |
| 初始密码 | 首次登录后立即修改默认 admin/public |
| 只读账号 | 建议创建仅 Dashboard 查看权限的账号用于日常监控 |
| 数据库只读账号 | 建议为 EMQX 认证创建独立的 PostgreSQL 只读用户,仅能查询 devices 表,遵循最小权限原则 |
7. 部署参考
emqx.conf 关键配置片段
# --- 认证(PostgreSQL 直连)---
authentication = [
{
mechanism = "password_based"
backend = "postgresql"
server = "postgres:5432"
database = "yunstack_iot"
username = "emqx"
password = "${EMQX_DB_PASSWORD}"
password_hash_algorithm {
name = "sha256"
salt_position = "suffix"
}
query = """
SELECT password_hash AS password_hash, 'sha256' AS password_hash_algorithm
FROM devices
WHERE physical_id = ${clientid}
AND username = ${username}
AND deleted_at IS NULL
LIMIT 1
"""
}
]
# --- ACL(内置规则)---
authorization {
sources = [
{
type = "built_in_database"
enable = true
}
]
no_match = "deny"
}
# --- MQTTS ---
listeners.ssl.default {
bind = "0.0.0.0:8883"
ssl_options {
certfile = "/etc/emqx/certs/server.pem"
keyfile = "/etc/emqx/certs/server.key"
}
}Docker Compose 示例
yaml
emqx:
image: emqx/emqx:5.x
ports:
- "1883:1883" # MQTT
- "8883:8883" # MQTTS
- "8083:8083" # WebSocket
- "18083:18083" # Dashboard
environment:
- EMQX_DASHBOARD__DEFAULT_PASSWORD=your_secure_password
- EMQX_DB_PASSWORD=your_db_password
volumes:
- ./emqx/data:/opt/emqx/data
- ./emqx/certs:/etc/emqx/certs