3. Mosquitto部署与配置:单节点部署、配置文件详解、TLS/SSL加密、认证与授权、WebSocket支持

好,咱们进入正题。这一章我打算把 Mosquitto 的部署和配置彻底讲透。你想想看,消息队列能不能跑得稳,MQTT Broker 这一层是关键中的关键。我自己在多个物联网项目里都用 Mosquitto,轻量、稳定、社区活跃,说实话,中小规模的边缘场景它几乎是最优解。

3.1 单节点部署:别想复杂了,其实就三步

单节点部署,说白了就是在一台边缘设备上把 Mosquitto 跑起来。我个人习惯用 Docker,但如果你在资源受限的 ARM 板子上,直接 apt 安装更省事。

方式一:apt 安装(推荐嵌入式场景)

sudo apt update
sudo apt install mosquitto mosquitto-clients -y
sudo systemctl start mosquitto
sudo systemctl enable mosquitto

装完以后,你试试能不能连上:

mosquitto_sub -h localhost -t "test" -v

再开一个终端:

mosquitto_pub -h localhost -t "test" -m "Hello Edge"

能收到消息,说明部署成功了。嗯,这里要注意,默认配置下 Mosquitto 是允许匿名连接的,生产环境千万别这么干。

方式二:Docker 部署(适合快速迭代)

docker run -d --name mosquitto \
  -p 1883:1883 \
  -p 9001:9001 \
  -v /mosquitto/config:/mosquitto/config \
  -v /mosquitto/data:/mosquitto/data \
  -v /mosquitto/log:/mosquitto/log \
  eclipse-mosquitto:2.0.18

我在项目中遇到过一个问题:Docker 部署时如果挂载目录权限不对,Mosquitto 会直接拒绝启动。解决办法很简单,给目录 777 权限,或者把容器内的 mosquitto 用户 UID(通常是 1883)映射到宿主机。

我的小技巧: 初次部署时,先不挂载配置文件,让容器生成默认配置。然后 docker cp 出来,再按需修改。这样能避免因为配置格式错误导致容器起不来。

3.2 配置文件详解:别被吓到,核心参数就这几个

Mosquitto 的配置文件默认在 /etc/mosquitto/mosquitto.conf。我第一次看这个文件时也觉得眼花缭乱,但后来发现,真正需要你动手改的,其实就下面这些。

参数 默认值 说明
listener 1883 1883 MQTT 标准端口,明文传输
listener 8883 TLS/SSL 加密端口,需要证书
listener 9001 WebSocket 端口,用于浏览器连接
allow_anonymous true 是否允许匿名连接,生产环境必须 false
password_file 用户名密码认证文件路径
acl_file 访问控制列表文件路径

一个典型的生产环境配置长这样:

# 监听端口
listener 1883
listener 8883
listener 9001

# 协议类型
protocol mqtt
protocol websockets

# 安全配置
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl

# TLS 配置
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key
tls_version tlsv1.2

# 日志配置
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
connection_messages true
log_timestamp true

你可能会问,为什么要把 1883、8883、9001 都打开?我的经验是:内网设备用 1883 明文通信(速度快),公网设备走 8883 加密,Web 管理界面用 9001 的 WebSocket。各司其职,互不干扰。

注意: 配置文件中每个参数后面只能跟一个值,不能有空格。比如 listener 1883 是对的,listener 1883 0.0.0.0 在某些版本里会报错。我曾经因为这个排查了半小时,最后发现是格式问题。

3.3 TLS/SSL 加密:给数据穿上防弹衣

边缘设备经常部署在不受控的物理环境中,Wi-Fi 可能被嗅探,网线可能被监听。TLS 加密不是可选项,是必选项。

生成自签名证书(测试环境够用)

# 1. 创建 CA 证书
openssl req -new -x509 -days 365 -extensions v3_ca \
  -keyout ca.key -out ca.crt

# 2. 生成服务器私钥和证书请求
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr

# 3. 用 CA 签发服务器证书
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out server.crt -days 365

然后把三个文件放到 /etc/mosquitto/certs/ 目录下,配置里引用即可。客户端连接时需要指定 CA 证书:

mosquitto_sub -h your-edge-device.com -p 8883 \
  --cafile /path/to/ca.crt \
  -t "secure/topic" -v

我记得有一次在现场调试,客户端一直报证书验证失败。查了半天,发现是服务器证书的 Common Name 填的是 IP 地址,而客户端连接时用的是域名。OpenSSL 默认会做 CN 匹配,对不上就报错。后来我改用 Subject Alternative Name(SAN)才解决。

生产环境建议: 别用自签名证书,用 Let's Encrypt 免费证书。Mosquitto 2.0 以上版本支持自动续期,配合 certbot 可以做到证书永不过期。

3.4 认证与授权:谁可以做什么,必须说清楚

匿名连接是魔鬼。我见过太多项目上线后才发现任何人都能订阅所有主题,那画面太美我不敢看。

第一步:创建用户

sudo mosquitto_passwd -c /etc/mosquitto/passwd admin
# 输入密码两次
sudo mosquitto_passwd /etc/mosquitto/passwd sensor01

-c 参数会创建新文件,后续添加用户时不要加 -c,否则会覆盖已有用户。

第二步:配置 ACL(访问控制)

ACL 文件 /etc/mosquitto/acl 的内容示例:

# 所有用户可读系统主题
topic read $SYS/#

# admin 用户拥有全部权限
user admin
topic readwrite #

# sensor01 只能发布传感器数据
user sensor01
topic write sensor/+/data

# 匿名用户只能读取公共状态
topic read public/status

ACL 的匹配规则是从上到下,第一条匹配到的规则生效。所以把最宽松的规则放在最后,最严格的放在前面。

我的经验: 主题命名一定要有层次结构。比如 sensor/{device_id}/dataactuator/{device_id}/command。这样 ACL 写起来清晰,后期维护也方便。我曾经在一个项目里看到主题名是 abc,那 ACL 简直没法写。

3.5 WebSocket 支持:让浏览器也能玩 MQTT

边缘计算场景里,经常需要在浏览器里查看实时数据。MQTT 原生协议浏览器不支持,但 WebSocket 可以。

配置很简单,在 mosquitto.conf 里加两行:

listener 9001
protocol websockets

如果同时需要 TLS 加密的 WebSocket(即 WSS),再加证书配置:

listener 9001
protocol websockets
cafile /etc/mosquitto/certs/ca.crt
certfile /etc/mosquitto/certs/server.crt
keyfile /etc/mosquitto/certs/server.key

前端 JavaScript 连接示例:

const client = mqtt.connect('ws://your-edge-device.com:9001', {
  username: 'webuser',
  password: 'webpass'
});

client.on('connect', function () {
  client.subscribe('sensor/+/data', function (err) {
    if (!err) {
      console.log('订阅成功');
    }
  });
});

client.on('message', function (topic, message) {
  document.getElementById('data').innerHTML = message.toString();
});

这里有个坑:WebSocket 连接时,如果 Mosquitto 开启了 allow_anonymous false,前端必须传用户名密码。而且密码是明文传输的,所以强烈建议 WebSocket 端口也走 TLS。

性能提醒: WebSocket 连接比原生 MQTT 连接更耗资源。如果边缘设备只有 512MB 内存,建议限制 WebSocket 的最大连接数。可以在配置里加 max_connections 100,防止被恶意连接打爆。

好了,这一章的内容就这些。从单节点部署到 TLS 加密,从用户认证到 WebSocket 支持,每一步都是我在实际项目中踩过坑、填过坑之后总结出来的。下一章咱们聊聊集群部署,那才是真正考验架构能力的地方。