2. 基于Mosquitto搭建矿山本地Broker
为什么矿山现场要自建 Broker
井下瓦斯、风速、水位传感器与地面监控客户端如果直接连公网云 Broker,会受井下环网抖动、出口带宽和断网影响。把 Mosquitto 部署在矿山本地服务器(如调度室工控机或边缘网关),让传感器与监控客户端走局域网,可显著降低时延并保证断网时本地仍能转发。本例在一台 Linux 本地服务器上完成 Mosquitto 的安装、监听端口、用户名密码认证与 ACL 授权,并用两个客户端验证“能连上、只能访问自己的主题”。
部署拓扑与访问控制关系
下图给出本例要落地的对象关系:井下传感器以设备账号接入,地面监控以监控账号接入,二者通过 ACL 被限制在各自的主题子树内,Broker 只开放一个内网监听端口。
安装与基础配置
以 Debian/Ubuntu 系服务器为例,安装后 Mosquitto 默认只监听本机回环地址,必须显式配置监听地址才能被井下与地面客户端访问。
sudo apt update
sudo apt install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
# 备份默认配置后编辑
sudo cp /etc/mosquitto/mosquitto.conf /etc/mosquitto/mosquitto.conf.bak
sudo tee /etc/mosquitto/conf.d/mine.conf > /dev/null <<'EOF'
# 矿山本地监听:仅绑定内网网卡,避免暴露到公网
listener 1883 192.168.10.20
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/aclfile
# 关闭持久化会话以外的多余日志噪声,保留连接与认证日志便于排障
log_type error
log_type warning
log_type notice
log_type information
connection_messages true
EOF
若服务器有多块网卡,
listener 1883 192.168.10.20 中的 IP 必须替换为实际内网地址;写成 listener 1883 会监听所有网卡,存在被外部扫描的风险。创建账号与 ACL 规则
为每类接入方建立独立账号,避免共用账号导致无法追溯。密码文件用 mosquitto_passwd 生成,ACL 文件按“用户 → 主题 → 读写权限”逐条声明。
# 创建密码文件并添加账号(-c 仅首次创建时使用,后续追加不要加 -c)
sudo mosquitto_passwd -c /etc/mosquitto/passwd dev_ch4_07
sudo mosquitto_passwd /etc/mosquitto/passwd dev_ws_03
sudo mosquitto_passwd /etc/mosquitto/passwd dev_wl_02
sudo mosquitto_passwd /etc/mosquitto/passwd mon_display
sudo mosquitto_passwd /etc/mosquitto/passwd mon_alarm
sudo tee /etc/mosquitto/aclfile > /dev/null <<'EOF'
# 设备账号:只能向自己的数据主题发布,不能订阅
user dev_ch4_07
topic write mine/ch4/area1/07/data
user dev_ws_03
topic write mine/ws/area1/03/data
user dev_wl_02
topic write mine/wl/area2/02/data
# 监控账号:只读全部矿山数据主题,禁止发布
user mon_display
topic read mine/#
user mon_alarm
topic read mine/#
EOF
sudo chown mosquitto:mosquitto /etc/mosquitto/passwd /etc/mosquitto/aclfile
sudo chmod 640 /etc/mosquitto/passwd /etc/mosquitto/aclfile
sudo systemctl restart mosquitto
sudo systemctl status mosquitto --no-pager
ACL 中
topic write 只授予发布权限,topic read 只授予订阅权限。若设备账号误写成 topic readwrite mine/#,该设备即可读取全矿数据,属于越权配置。用两个客户端验证接入与隔离
验证分三步:监控端订阅、设备端发布、越权访问被拒绝。以下命令在局域网内另一台机器执行,-h 指向 Broker 内网地址。
# 终端 A:监控账号订阅全部数据主题
mosquitto_sub -h 192.168.10.20 -p 1883 \
-u mon_display -P '监控账号密码' \
-t 'mine/#' -v
# 终端 B:瓦斯设备账号发布一条数据
mosquitto_pub -h 192.168.10.20 -p 1883 \
-u dev_ch4_07 -P '设备账号密码' \
-t 'mine/ch4/area1/07/data' \
-m '{"ch4":0.42,"ts":1730000000}'
# 终端 C:设备账号尝试发布到别人的主题,应被拒绝
mosquitto_pub -h 192.168.10.20 -p 1883 \
-u dev_ch4_07 -P '设备账号密码' \
-t 'mine/wl/area2/02/data' -m 'test'
# 终端 D:匿名连接,应被拒绝
mosquitto_pub -h 192.168.10.20 -p 1883 -t 'mine/test' -m 'x'
结果判读
| 验证项 | 预期现象 | 不符合时的排查方向 |
|---|---|---|
| 监控端订阅 | 终端 A 收到 mine/ch4/area1/07/data {"ch4":0.42,...} | 检查 ACL 是否含 topic read mine/#、账号密码是否正确 |
| 设备端发布 | 终端 B 无报错退出,终端 A 立即显示消息 | 检查 topic write 主题是否与发布主题逐段一致 |
| 越权发布 | 终端 C 连接成功但发布被拒,终端 A 收不到该消息 | 若收到消息,说明 ACL 权限过宽,需收紧为精确主题 |
| 匿名连接 | 终端 D 报 Connection Refused: not authorised | 确认 allow_anonymous false 已生效并重启服务 |
若终端 A 能连上却收不到任何消息,先看 Broker 日志 sudo journalctl -u mosquitto -n 50,重点确认是否有 Denied PUBLISH 或 not authorised 记录,再回到 ACL 文件核对主题层级是否与发布主题完全一致(ACL 不做前缀模糊匹配,mine/ch4/area1/07/data 与 mine/ch4/area1/07/data/ 视为不同主题)。
上线前检查清单
- 监听地址绑定内网 IP,未使用
0.0.0.0暴露到公网。 allow_anonymous false已开启,匿名连接被拒。- 每个设备、每个监控服务使用独立账号,密码文件权限为
640且属主为mosquitto。 - ACL 中设备账号只有
write,监控账号只有read,无readwrite mine/#类宽泛规则。 - 已用
mosquitto_sub/mosquitto_pub完成“正常收发 + 越权被拒 + 匿名被拒”三项验证。