← 返回教程库

自建 MQTT Broker:让数据不再寄人篱下

最后更新 2026-06-20
L3 · 联网与 IoT ⏱ 约 18 分钟 🟢 软件/低风险
你将学到
  • 想清楚什么时候该自建 Broker,以及 Mosquitto 和 EMQX 怎么选
  • 用 Docker 几条命令把一个 Broker 跑起来,并配上用户名密码鉴权
  • 把 ESP32 从公共 Broker 切到自建 Broker,复用已有 MQTT 代码只改一个地址

你照着 MQTT 入门那节把设备连上了 broker.emqx.io,手机一发命令灯就亮,那一刻确实爽。但用着用着你会开始犯嘀咕:我家客厅的温湿度、我开关灯的每一条命令,是不是都从公司的某台公共服务器上过了一遍?这个免费 Broker 哪天拥堵了、停了,我的项目是不是就瘫了?设备一多,平台会不会开始限我连接数、找我收费?

到这一步,你需要的是一台自己的 Broker——跑在你家的树莓派上,或者你租的一台云服务器上。数据不出你的网络,连多少台设备你说了算,局域网里延迟低到可以忽略。这一节就带你用 Docker 十分钟跑起一个,把 ESP32 切过去,再加上最基本的鉴权,让它能安心放着用。前置只要你跟着 MQTT 入门跑通过一次,这里的代码几乎原样复用,只改一个地址。


为什么要自建:四个绕不开的理由

公共 Broker 是给你练手的,不是给你长期靠的。等你认真做一个项目,下面这四点迟早把你逼到自建这条路上。

数据自己掌控。 公共 Broker 上你的 topic 是完全公开的——任何人都能订阅 qifudev/demo/led,看你什么时候开了灯。家里的温湿度、门窗状态、定位,这些数据一旦上了别人的服务器,你就再也收不回来。自建之后,消息只在你自己的网络里流转,谁也偷看不了。

不限连接数、不收费。 国内 IoT 平台(巴法云、OneNET 这类)正式用起来,普遍按设备数或消息量限额,免费档常常卡在十几台、几十条/分钟。你做一套全屋传感器,二十几个节点很正常,很容易撞到上限。自建的 Broker,一台树莓派挂几百个设备毫无压力,一分钱不花。

局域网零延迟。 走公网的 Broker,命令要先出你家路由器、绕到云服务器、再绕回来,一来一回几十到几百毫秒,网络一抖还可能丢。Broker 跑在你家局域网里,命令在内网走一圈就回来了,按下开关到灯亮几乎是瞬间的。做需要"手感"的控制(比如调光、实时联动),这个差别很明显。

稳定可控。 公共测试 Broker 没有任何可用性承诺,高峰期拥堵、临时维护、限流,你都没处说理。自己的 Broker,跑挂了你能重启,配置不对你能改,版本你自己定——整条链路都在你手里。

📌 说明

自建不是非此即彼。务实的路径是:练手用公共 Broker → 给自己用的小项目可以先上巴法云(见 对接巴法云那节→ 设备多了、重隐私、或要局域网低延迟,再自建。这一节就是为最后这个阶段准备的。


Broker 怎么选:Mosquitto 还是 EMQX

能自己跑的 MQTT Broker 有不少,入门阶段你只需要在这两个里挑,它们覆盖了绝大多数场景。

Mosquitto——轻量、经典、省资源。它是 Eclipse 基金会的老牌开源 Broker,一个进程几 MB 内存就能跑,配置就一个文本文件。适合树莓派、软路由、小服务器这类资源紧张的地方,也适合你只想要一个"安静转发消息"的纯粹 Broker,不要花哨功能。缺点是没有图形界面,看设备在不在线、看消息流都得靠命令行工具,调试起来不够直观。

EMQX——功能强、有 Web 后台、面向生产。它自带一个相当好用的 Dashboard(网页管理后台),打开浏览器就能看到哪些设备在线、实时的消息流、连接数曲线,还能在线配鉴权规则。适合设备多、要长期运维、想要可视化的场景。代价是它比 Mosquitto重,一个空载实例吃几百 MB 内存,跑在最低配的树莓派上会有点紧。

我的建议很直接:如果你是边学边调、想看见设备和消息,就用 EMQX——那个 Dashboard 对新手太友好了,能省掉大量"它到底连上没有"的猜测。如果你的目标机器很弱(比如老树莓派 Zero),或者你已经懂 MQTT、只要一个稳定的转发器,就用 Mosquitto。下面两个都给,你按手头的机器选一个。


用 Docker 跑起来:十分钟搞定

为什么用 Docker?因为它把"装环境"这件最容易劝退人的事抹平了——你不用在树莓派上手动编译、装一堆依赖、改系统配置,一条命令把整个 Broker 连环境一起拉下来跑。前提是你的机器(树莓派或服务器)已经装了 Docker(树莓派上 curl -fsSL https://get.docker.com | sh 一行就能装好)。

两个端口先记住,后面到处用:

  • 1883:MQTT 的标准端口(明文),ESP32 就连这个。
  • 8083:EMQX 的 MQTT over WebSocket 端口,网页要订阅消息时走它(普通浏览器连不了 1883,只能走 WebSocket)。

方案 A:EMQX(推荐,带 Dashboard)

最快的一条命令,直接前台跑起来试水:

docker run -d --name emqx \
  -p 1883:1883 \
  -p 8083:8083 \
  -p 18083:18083 \
  emqx/emqx:5.8

三个端口的含义:1883 给 ESP32 连,8083 给网页用 WebSocket 连,18083Dashboard 管理后台的网页端口。跑起来后,浏览器打开 http://你的服务器IP:18083,默认账号 admin、密码 public第一次登录会强制你改掉,务必改)。进去你就能看到一个干净的控制台,等会儿 ESP32 一连上,这里会实时显示它在线。

方案 B:Mosquitto(轻量)

Mosquitto 需要一个配置文件才能对外开放(默认只允许本机连,这是新手最常卡住的地方)。先建个目录放配置:

mkdir -p ~/mosquitto/config ~/mosquitto/data

~/mosquitto/config/mosquitto.conf 里写上:

listener 1883
allow_anonymous true
persistence true
persistence_location /mosquitto/data/

listener 1883 让它监听所有网卡(而不是只听本机),allow_anonymous true 是先临时允许免密连接好让你快速验证——下一节我们就把它关掉。然后跑起来:

docker run -d --name mosquitto \
  -p 1883:1883 \
  -v ~/mosquitto/config:/mosquitto/config \
  -v ~/mosquitto/data:/mosquitto/data \
  eclipse-mosquitto:2

用 docker-compose 管起来(推荐长期用)

命令行 docker run 适合试一把,但参数一多就难记。长期跑建议用 docker-compose.yml,一个文件管住所有配置,以后 docker compose up -d 一条命令就拉起来。以 EMQX 为例,在某个目录建 docker-compose.yml

services:
  emqx:
    image: emqx/emqx:5.8
    container_name: emqx
    restart: unless-stopped          # 开机自启、挂了自动重启
    ports:
      - "1883:1883"                  # MQTT
      - "8083:8083"                  # MQTT over WebSocket(网页用)
      - "18083:18083"                # Dashboard 管理后台
    volumes:
      - ./emqx-data:/opt/emqx/data   # 把数据存到宿主机,重建容器不丢配置

然后在这个目录里 docker compose up -d,效果和上面的 docker run 一样,但 restart: unless-stopped 让它在树莓派重启后能自己回来,数据也持久化到了宿主机的 emqx-data 目录。这才是放着长期用的姿势。


把 ESP32 连过来:只改一个地址

好消息是,MQTT 入门那节写的那份 sketch,几乎一行不用动——MQTT 的妙处就在这里,Broker 换了,设备端的代码逻辑完全一样。你要改的只有一处:把 Broker 地址从公共的 broker.emqx.io 换成你自己机器的 IP。

// 原来连的是公共 Broker:
// const char* mqttServer = "broker.emqx.io";

// 改成你自建 Broker 的局域网 IP(树莓派/服务器的内网地址):
const char* mqttServer = "192.168.1.50";   // ← 换成你机器的实际 IP
const int   mqttPort   = 1883;             // 端口不变,还是 1883

这个 IP 怎么找?如果 Broker 跑在树莓派上,在树莓派里敲 hostname -I 就能看到它的局域网 IP(形如 192.168.x.x)。要点是 ESP32 和这台机器得在同一个局域网(连同一个路由器/WiFi),ESP32 才能直接访问到这个内网 IP。订阅 topic、收到 on 开灯、定时上报状态——这些回调和重连逻辑你已经在上一节写好了,原样保留即可。这就是 MQTT 解耦的实感:底层 Broker 怎么换,设备端无感。

你应该看到什么

烧录后打开串口监视器(115200 波特率),你会看到和之前一样的流程:WiFi 已连接连接 Broker...成功。区别在于这次连的是你自己的机器。

如果你用的是 EMQX,这时打开 http://你的IP:18083 的 Dashboard,点进「连接」(Connections)页面,你会看到那块 ESP32 赫然在列——客户端 ID、IP、连接时间一清二楚。再点「主题」相关的视图,能看到它每 5 秒往 qifudev/demo/status 发的消息在实时跳动。这种"亲眼看见自己的设备在自己的服务器上"的感觉,是公共 Broker 给不了的。


别裸奔:加上用户名密码

刚才为了快速跑通,EMQX 是默认允许匿名连接的,Mosquitto 我们也临时开了 allow_anonymous这只在纯内网、且你信任内网里所有人时才勉强能接受。一旦这台 Broker 哪天要让公网访问,或者你的内网没那么干净,裸奔的 Broker 等于把家门钥匙插在锁上——任何人都能连进来订阅你的所有数据、甚至冒充设备发命令控你的灯。

最低限度,加一组用户名密码。

EMQX: Dashboard 里「访问控制 → 认证(Authentication)」,新建一个「内置数据库」认证,然后在「用户管理」里加一个用户名密码(比如 esp32 / 你的强密码)。开启后,匿名连接会被直接拒绝。ESP32 端对应改一行 connect

// 原来:client.connect(clientId.c_str());
// 带鉴权:把用户名、密码补上
if (client.connect(clientId.c_str(), "esp32", "你的强密码")) {
  // 连接成功
}

Mosquitto: 用它自带的工具生成密码文件,然后改配置关掉匿名:

# 在容器里生成密码文件,提示输入密码
docker exec -it mosquitto mosquitto_passwd -c /mosquitto/config/passwd esp32

再把 mosquitto.conf 改成:

listener 1883
allow_anonymous false                       # 关掉匿名
password_file /mosquitto/config/passwd      # 启用密码文件
persistence true
persistence_location /mosquitto/data/

docker restart mosquitto 重启生效,之后 ESP32 也要带上用户名密码才连得上。

🚧 避坑

端口 1883 走的是明文——就算加了用户名密码,密码和消息内容在网络上还是裸的,同一个网络里抓包就能看到。在纯内网、可信环境下这够用了;但只要 Broker 要走公网,或数据有价值,就必须再上 TLS 加密(见本节末尾的变体)。别把一个明文 1883 的 Broker 直接暴露到公网,那是在给全世界发邀请函。


部署在哪:树莓派还是云服务器

这台 Broker 放哪,取决于你的设备在哪、要不要从外面访问。

放局域网里的树莓派(推荐家用)。 如果你的设备都在家、你也主要在家里控制,把 Broker 跑在一台常开的树莓派上是最优解:延迟最低(内网直连)、数据完全不出门、电费几乎可忽略。一台树莓派 4 挂几十个传感器轻轻松松。这是绝大多数 DIY 智能家居的标准做法。

放云服务器(要从外网控制时)。 如果你想人在公司也能控制家里的设备,或者设备本身就分散在不同地方(不在同一局域网),那 Broker 就得放在一台有公网 IP 的云服务器上,大家都连它。但公网 Broker 的安全要求陡然升高:不只是用户名密码,还得配 TLS 加密、收紧防火墙只放必要端口、改掉所有默认密码。如果你对"怎么把一个服务安全地暴露到公网"还没把握,先别急着上公网——把它留在内网,要远程时用更稳妥的方式打通,这块的取舍可以参考联网安全那节


故障排查:连不上的几种典型死法

自建 Broker 第一次连,新手十有八九会卡在下面几条里,对照查:

现象 最可能的原因 怎么办
ESP32 串口卡在 连接 Broker...失败 IP 写错,或 ESP32 和 Broker 不在同一局域网 在 Broker 机器上 hostname -I 确认 IP;确保 ESP32 连的是同一个路由器
本机能连、ESP32 连不上(Mosquitto) 没配 listener 1883,Broker 只监听了本机 配置文件里加 listener 1883,重启容器
容器跑起来了但端口连不上 docker run 漏了 -p 1883:1883 没映射端口 检查 run/compose 里端口映射;docker ps 看端口列对不对
内网能连、换网络就连不上 服务器/路由器防火墙挡了 1883 放行 1883 端口;云服务器还要在安全组里加规则
错误码 rc=5(连接被拒) 开了鉴权但 ESP32 没带或带错用户名密码 核对 connect() 里的用户名密码和 Broker 上配的一致
Dashboard 打不开(EMQX) 没映射 18083 端口,或防火墙挡了 run 里加 -p 18083:18083;放行该端口
容器重启后配置/用户都没了 没挂数据卷,数据存在容器里被冲掉了 -v 或 compose 的 volumes 把数据持久化到宿主机
💡 提示

排查"连不上"最高效的办法:先在 Broker 那台机器上用本机连一下自己,确认 Broker 本身没问题。EMQX 装个 mosquitto-clientsmosquitto_sub -h 127.0.0.1 -t test/# 订一下;能收到说明 Broker 正常,问题就出在网络/防火墙/IP 上,范围一下缩小一半。把你的报错码和配置发给 AI,让它帮你定位也很快。


进阶变体

跑通基础版后,下面两个升级按需要拿:

加 TLS 加密(数据上公网必做)。 把明文的 1883 换成加密的 8883 端口(MQTT over TLS),消息在网络上就是密文了,抓包也看不到内容。EMQX 里在「监听器」配置上传证书即可(自己用 mkcert 生成自签证书练手,正式上公网用 Let's Encrypt 免费证书);ESP32-S3 端则把 esp-mqtt 的 URI 从 mqtt:// 换成 mqtts://...:8883、再用 .broker.verification.certificate 塞进 CA 证书(具体见通信安全那节)。这一步稍繁,但只要 Broker 要走公网,它就不是可选项。

WebSocket 让网页能订阅。 浏览器连不了 1883,但能连 8083 的 WebSocket。配好后,你可以用 MQTT.js 写个网页,直接在浏览器里订阅 qifudev/demo/status,做一个能看实时数据、点按钮发命令的网页控制面板——不用装任何 App,发个链接别人就能用。这是把你的 IoT 项目"给别人看"的最轻量方式。


动手挑战

光连一台不够,来体会一次"自己的 Broker 当中转":

  1. 两台 ESP32 互发消息。 在树莓派或电脑上跑起 Broker,准备两块 ESP32:A 板订阅 room/msg,B 板每隔几秒往 room/msg 发一条带计数的消息(hello 1hello 2……)。看着 A 板的串口实时打出 B 板发来的内容——这两块板从不直接通话,全靠你自己那台 Broker 中转。这一刻你才算真正拥有了一套属于自己的"设备通信中枢"。
  2. 接个真实传感器上报。 把 B 板换成读 DHT11 温湿度 的数据往 topic 发,A 板(或一个手机 App)订阅着看,做成你家第一个完全自托管的温湿度监测。
  3. EMQX 用户体验一把。 在 Dashboard 里给两块板各建一个用户名密码,开启鉴权,故意填错一个密码,看 Dashboard 的连接日志里它怎么被拒——把"鉴权到底在拦什么"看明白。

卡住了?把你的 docker 命令、配置文件和 ESP32 报错一起发给 AI,让它帮你对一遍。


小结 · 下一步

  • 你想清楚了什么时候该自建:要数据自己掌控、不限连接数、局域网零延迟、稳定可控——公共 Broker 撑不到这一步。
  • 你会在 Mosquitto(轻量)和 EMQX(带 Dashboard) 之间按机器和需求选一个,并用 Docker / docker-compose 把它跑起来。
  • 你把 ESP32 从公共 Broker 切到了自建,只改了一个 IP,深刻体会了 MQTT 的解耦——Broker 换了设备端无感。
  • 你给 Broker 加了用户名密码鉴权,知道明文 1883 不能裸奔上公网,也清楚部署位置和安全的取舍。

有了自己的 Broker,你的设备就有了一个稳定、私密、低延迟的"通信中枢"。但光有中枢还不够——你还得有个地方能看数据、设规则、做联动。下一步推荐把这个自建 Broker 接进 Home Assistant:它是开源智能家居平台里最能打的一个,自带 MQTT 集成,能把你这些 ESP32 设备变成可视化面板上的开关和图表,还能写自动化规则(比如"温度超过 28 度自动开风扇")。到那时,你这套自托管的 IoT 体系才算真正成型。

往上走到 L4 阶梯,你会把这些零件组装成成体系的项目,自托管整套服务的玩法见自建服务那节。完整进阶地图见学习路线

📄 来源 / 自校链接

本文为公开资料整理,非亲测。关键参数与代码请结合实物与下列官方来源验证。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为公开资料的学习整理,非亲测。涉接线/花钱/合规的步骤请结合实物与官方最新资料验证,风险自负。见免责声明