在物联网(IoT)开发中,Mosquitto 凭借其轻量、开源的特性,成为了最受欢迎的 MQTT 消息代理之一。这篇博文使用 Docker Compose 快速部署一个生产级的 Mosquitto 服务,开启账号密码认证,并打通 MQTT TCP 与 Websocket 双端口。

提示:Mosquitto 官方 Docker 镜像内部以 mosquitto 用户(UID=1883)运行。在宿主机挂载目录时,文件权限是最容易踩坑的地方,本文已提供最优解。

一、环境准备与目录规划

首先,拉取官方最新镜像:

docker pull eclipse-mosquitto

若拉取镜像失败,可参考Debian11上无法拉取docker镜像问题的解决方案

为了便于统一管理配置、持久化数据和日志,我们在宿主机创建专属的项目目录:

mkdir -p /mosquitto/{config,data,log}
cd /mosquitto

最终目录结构如下:

/mosquitto/
├── config/        # 存放 mosquitto.conf 和 pwfile
├── data/          # 持久化消息数据库
├── log/           # 运行日志
└── docker-compose.yml

二、编写核心配置文件

1. 创建 docker-compose.yml

在项目根目录创建 docker-compose.yml,填入以下配置(新版 Compose 已移除 version 字段):

services:
  mosquitto:
    image: eclipse-mosquitto
    container_name: mosquitto
    restart: always
    ports:
      - "1883:1883"   # MQTT TCP 协议端口
      - "9001:9001"   # MQTT over Websocket 端口
    volumes:
      - ./config:/mosquitto/config
      - ./data:/mosquitto/data
      - ./log:/mosquitto/log

2. 编写 mosquitto.conf

./config/ 目录下创建 mosquitto.conf

# 开启消息持久化,重启不丢消息
persistence true
persistence_location /mosquitto/data/

# 日志输出配置:同时输出到文件和控制台,方便 docker logs 查看
log_dest file /mosquitto/log/mosquitto.log
log_dest stdout

# 监听 MQTT TCP 端口
listener 1883
# 监听 Websocket 端口,供前端网页客户端使用
listener 9001
protocol websockets

# 生产环境安全配置:关闭匿名访问
allow_anonymous false
# 指定账号密码文件路径
password_file /mosquitto/config/pwfile

三、权限修正与账号初始化

1. 预创建密码文件并修正权限

为了避免容器启动时因权限不足报错,我们需要提前创建密码文件,并将整个目录授权给容器内的 mosquitto 用户(UID=1883):

# 创建空的密码文件
touch ./config/pwfile

# 将目录归属修改为 1883:1883
chown -R 1883:1883 /mosquitto

2. 启动容器

/mosquitto 目录下执行:

docker compose up -d

3. 创建 MQTT 登录账号

进入容器 Shell 添加用户。注意:-c 参数仅用于首次创建文件,文件已存在时切勿使用,否则会清空已有账号!

# 进入容器
docker exec -it mosquitto sh

# 添加 admin 用户,注意 不加 -c
mosquitto_passwd /mosquitto/config/pwfile admin

按提示输入两次密码后,退出容器(exit)。

补充:如果后续需要重置密码文件,可以先在宿主机执行 rm ./config/pwfile,再进容器使用 mosquitto_passwd -c ... 重新创建。

4. 重启服务使配置生效

修改密码文件后,必须重启 Mosquitto 才能加载:

docker compose restart

四、通信验证测试

新开两个终端窗口,分别测试订阅和发布:

终端 A(订阅端):

docker exec -it mosquitto mosquitto_sub -h localhost -t test -u admin -P 你的密码

终端 B(发布端):

docker exec -it mosquitto mosquitto_pub -h localhost -t test -m "Hello MQTT Docker Compose" -u admin -P 你的密码

当终端 A 成功收到 “Hello MQTT Docker Compose” 消息时,代表 Broker 已经部署成功!
订阅到消息
或者直接用MQTTX连接到broker 发布和订阅消息测试
在这里插入图片描述

五、日常运维速查

以下命令均需在 docker-compose.yml 所在目录执行:

# 后台启动服务
docker compose up -d

# 停止并删除容器(保留 config/data/log 数据)
docker compose down

# 停止并删除容器 + 清空数据卷(!!! 慎用,会丢失持久化消息)
docker compose down -v

# 实时查看运行日志
docker compose logs -f

# 重启 Mosquitto
docker compose restart

六、生产环境安全建议

  1. 严禁匿名访问:公网暴露必须设置 allow_anonymous false,并配置强密码。如有更高安全需求,建议配置 TLS 证书并使用 8883 加密端口。
  2. 防火墙放行:云服务器需在控制台安全组放行 18839001 端口;本地服务器需配置 iptables/ufw 放行。
  3. 最小权限原则:不要图省事使用 chmod 777 授权目录,坚持使用 chown 1883:1883 属主方式。
  4. 定期备份:定期备份 /mosquitto/config 目录,妥善保存密码文件与核心配置。

七、常见报错排错指南

报错现象原因分析解决方案
容器状态 Restarting(13)挂载目录权限不对,mosquitto 用户无法读写日志或密码文件执行 chown -R 1883:1883 /mosquitto
Error: Unable to open pwfilepwfile 文件不存在,或文件属主不是 1883提前创建空 pwfile,并修改属主为 1883:1883
File exists (添加用户时)密码文件已存在,但错误地使用了 -c 参数去掉 -c 参数直接添加;若需重建,先删除 pwfile
WARN: attribute version is obsolete新版 Docker Compose V2 不再需要 version 字段删除 docker-compose.yml 首行的 version: "3.8" 即可,不影响运行
Conflict. The container name “/mosquitto” is already in use之前用 docker run 创建的同名容器残留执行 docker rm -f mosquitto 强制删除旧容器,再重新 docker compose up -d

更多推荐