☰
EMQX与MQTT的SSL/TLS加密配置实战:从安装到证书部署全指南
2026/9/30 6:11:16 网站建设 项目流程

跑了四五年 IoT 项目,MQTT Broker 换过不少,EMQX 一直是我在 Linux 服务器上的常驻选择。不是因为它功能最花哨,而是它在海量长连接场景下的稳定性、开箱即用的 Dashboard,以及把 SSL/TLS 加密这件事做得足够省心。最近给一台新服务器完整走了一遍“安装 EMQX → 配置 MQTT → 启用 TLS 加密”的流程,顺手把踩过的坑也整理出来,这篇就当给后面要搭设备接入平台的同学留一份可复现的操作笔记。

这个流程适合谁?如果你的设备需要公网接入、数据链路必须加密,或者公司安全扫描要求你关掉一批弱加密套件,这篇文章基本都能覆盖到。下面操作我分别在 Ubuntu 20.04/22.04 和 CentOS 7/8 上验证过,Debian 系用 apt、RHEL 系用 yum/dnf,命令略有差异但思路完全一致。

1. 动手之前:先想清楚三个问题

1.1 为什么用 EMQX,不用 Mosquitto 或自研 Broker

很多人一上来就问“EMQX 和 Mosquitto 哪个好”,我的答案是:先看你的设备规模和业务复杂度。如果只是几十台设备、单机跑一个轻量转发,Mosquitto 完全够用,配置文件几行就能搞定。但一旦设备量上了几百台,或者你需要规则引擎做消息预处理、需要把数据桥接到 Kafka/数据库、需要多节点集群横向扩容,Mosquitto 就会变得很吃力,因为这些能力它默认都不带,得靠你写插件或者在外面再包一层服务。

EMQX 的价值在于把“大规模长连接管理”这件事做扎实了。它底层基于 Erlang/OTP,天生适合高并发、低延迟的连接密集场景,单节点承载百万级连接不是口号,我在压测环境里跑到过几十万连接,内存和 CPU 表现确实稳。再加上 Dashboard 可视化管理、REST API、内置 ACL、支持 MQTT 5.0,这些对于生产环境来说都是刚需。还有一个实际点:EMQX 的 SSL/TLS 配置是开箱即用的,证书放进去、监听器一开就能跑,不用像某些 Broker 还要自己编译 OpenSSL 模块。

1.2 版本选型与运行环境

EMQX 目前主流是 4.x 和 5.x 两个大版本。4.x 用了很多年,网上教程多,配置格式相对传统;5.x 是重构后的版本,配置改成了 HOCON 格式,Dashboard 也换了皮肤,API 变化比较大,但对新功能和性能优化更积极。

如果你是新项目,我建议直接上 5.x,毕竟 4.x 已经逐步进入维护期,新特性不会再加了。这篇文章以 5.x 为例,部署后配置路径在/etc/emqx/emqx.conf,证书目录在/etc/emqx/certs/。如果你用的是 4.x,配置语法略有差异,我会在对应位置标注出来。

运行环境方面,官方支持主流 Linux 发行版。硬件上,测试环境 1 核 1G 内存就能跑起来,但生产环境建议至少 2 核 4G,尤其是你要开 TLS 时,加解密运算会消耗 CPU。磁盘倒是没太多要求,EMQX 本身不存储消息,除非你开了持久化会话或消息回溯功能。

1.3 证书方案规划:自签还是 CA 签发

启用 SSL/TLS 之前,必须先想清楚证书方案。三种选择,对应三种不同场景:

  • 内网部署、设备量少、不涉及公网访问:自建 CA,用自己的 CA 签发服务端证书,设备端内置 CA 证书做验证。
  • 公网接入、设备来自不同客户:建议直接用正规 CA 签发的证书,比如 Let's Encrypt,客户端不需要额外内置根证书,体验最省事。
  • 安全等级要求高、要验证设备身份:用双向 TLS,也就是 mTLS,服务端验证客户端证书,客户端也验证服务端证书。这需要给每台设备签发唯一证书,管理成本高,但安全性最好。

我在实际项目里最常见的是第一种和第二种。这篇文章重点讲自建 CA 的方式,因为它的流程能让你完整理解证书链的来龙去脉,换到正式 CA 证书时只是替换文件的问题。

2. 在 Linux 上安装 EMQX:两种主流方式

2.1 使用官方安装包安装(推荐)

EMQX 官方提供 .deb 和 .rpm 安装包,这是我最推荐的安装方式,因为安装后 systemd 服务、配置文件目录、日志目录全部自动就位,不用自己手工整理。

以 Ubuntu 22.04 为例,先去官网找到对应版本的下载链接:

wget https://www.emqx.com/en/downloads/broker/5.7.1/emqx-5.7.1-ubuntu22.04-amd64.deb sudo dpkg -i emqx-5.7.1-ubuntu22.04-amd64.deb

RHEL/CentOS 系统换成 .rpm 包:

wget https://www.emqx.com/en/downloads/broker/5.7.1/emqx-5.7.1-el7-amd64.rpm sudo rpm -ivh emqx-5.7.1-el7-amd64.rpm

装完之后,EMQX 会被安装在/usr/lib/emqx,配置文件在/etc/emqx,日志在/var/log/emqx,数据目录在/var/lib/emqx。先不要急着启动,可以先看一眼版本和帮助信息确认装对:

emqx version emqx ctl help

如果你不想走安装包,也可以用官方 APT/YUM 仓库安装,好处是后续升级方便。但仓库地址和配置方式不同发行版不一样,我就不贴具体命令了,官网文档写得很清楚,按它的步骤复制粘贴就行。

2.2 用 systemd 管理服务并确认健康状态

安装包装好后,systemd 服务已经注册好了,直接启动:

sudo systemctl start emqx sudo systemctl enable emqx sudo systemctl status emqx

我在第一次启动 EMQX 后,习惯先跑一遍状态检查,确认 listener 和 node 都正常:

emqx ctl status # 5.x 的命令 emqx_ctl status # 4.x 的命令

正常输出会告诉你 node 名和运行状态,类似Node 'emqx@127.0.0.1' is started。如果状态不正常,第一时间看日志,不要瞎猜:

tail -n 200 /var/log/emqx/emqx.log

另外注意,EMQX 默认有两个端口需要提前确认不被占用:1883 是 MQTT 明文端口,18083 是 Dashboard 管理界面端口。如果你在云服务器上部署,安全组规则里也要放行这两个端口,否则外部永远连不上,但你在服务器本机测试又是通的,这个坑后面我专门讲。

2.3 安装后第一件事:修改 Dashboard 密码

很多人装完 EMQX 就直接开始配业务,结果发现 Dashboard 一直用默认账号 admin/public。这个太危险了,尤其是服务器暴露在公网的情况下,相当于把管理后台送给别人。

5.x 的 Dashboard 首次访问是http://服务器IP:18083,默认用户admin,默认密码public。登录后立刻去“系统设置”里改密码,最好改成随机生成的强密码。4.x 的流程类似,只是界面样式不一样。

我还建议顺手做两件事:一是把 Dashboard 的默认端口改掉,改成 18083 以外的端口,减少被扫描器命中的概率;二是给 Dashboard 也加上 HTTPS 访问,方法是在 Dashboard 配置里启用 TLS,和后面 MQTT 的 TLS 配置是同一套证书体系,能一步到位就不留两个安全隐患。

3. 让 MQTT 先裸跑起来:基础配置与连接测试

3.1 配置文件结构和关键参数

EMQX 5.x 的主配置在/etc/emqx/emqx.conf,打开后你会发现它分了很多区块,每个区块管一个功能域。我们最关心的是listeners这个区块,它定义了所有监听器。

默认情况下,EMQX 启动两个 listener:一个是 TCP 明文 1883,一个是 WebSocket 8083。你可以登录 Dashboard 在“监听器”页面看到它们对应的运行状态。配置文件里对应的区块是这样的:

listeners.tcp.default { bind = "0.0.0.0:1883" max_connections = 1024000 }

关键参数里,我每次部署都会重点确认这几个:

  • bind:监听地址,写0.0.0.0表示所有网卡都监听,写127.0.0.1就只有本机能连。
  • max_connections:最大连接数,默认值很大,但你自己要根据服务器资源和业务量评估,不是越大越好。
  • acceptors:接收连接的进程数,连接数多时可以适当调大,但一般默认就够。

4.x 的配置格式是listener.tcp.external = 1883这种写法,区块名不同,但逻辑一样,你打开配置文件对照着改就行。

3.2 用命令行客户端做一次完整的发布订阅测试

启动服务后,我习惯先用命令行客户端验证一下消息通路,再碰业务代码。以 mosquitto 客户端为例,先安装:

sudo apt-get install -y mosquitto-clients # 或者 sudo yum install -y mosquitto

然后开两个终端,一个订阅,一个发布。订阅端:

mosquitto_sub -h 127.0.0.1 -p 1883 -t test/topic -v

发布端:

mosquitto_pub -h 127.0.0.1 -p 1883 -t test/topic -m "hello mqtt"

如果订阅端打印出test/topic hello mqtt,说明 MQTT 消息通路已经通了。这里有个小细节:-v参数会在输出里显示 topic 名,调试时特别有用,不加就只显示消息内容。

如果你身边没有 Linux 环境,也可以用 MQTTX 这个图形化客户端,Windows/Mac 都有,配置好 Broker 地址就能连,还内置了 SSL/TLS 配置选项,后面验证 TLS 连接时很方便。

3.3 开发测试阶段裸奔的注意事项

这一步为了让流程跑通,我们先用了明文 1883 端口。但我要提醒一句:只要 EMQX 监听在非本机地址,明文端口就等于在公网裸奔,任何能访问到这个端口的人都能订阅你的消息,而且说不定哪天就有扫描器盯上你。

所以测试阶段的底线是:第一,1883 端口只在内网开放,或者干脆绑定 127.0.0.1,只允许本机调试用;第二,必须开启 ACL 和用户名密码认证,哪怕是临时测试也建一个新账号,别用默认的。认证配置在 Dashboard 的“认证授权”里,选择内置数据库、添加用户名密码就行,一条消息都不用写,界面操作就能完成。

对了,还有一点经验:如果你打算后面马上启用 TLS,那 1883 端口可以在上线前直接关掉,不要让明文端口长期开着。我见过很多项目“暂时开着方便排查”,一开就是一年,最后彻底忘了,直到安全扫描报告砸到脸上才想起来。

4. 启用 SSL/TLS:从证书生成到安全连接

4.1 TLS 连接原理和选择 TLS 版本时的考量

MQTT 是 TCP 之上的应用层协议,可以套上 TLS 来保证传输过程中的机密性和完整性。整个过程理解成一个“先用证书握手确认身份,再协商出对称密钥加密消息”的流程即可,不需要背复杂的密码学公式。

TLS 握手时,服务端把自己的证书链发给客户端,客户端用自己信任的 CA 根证书去验证这条链,验证通过就说明“我连的确实是证书上写的那个服务器”。这一步非常重要,它解决了“中间人冒充”的问题。如果没有证书验证,你连的“服务器”可能只是一个在你和真实服务器之间搬运数据的中间节点,数据照样被看光。

部署 TLS 时尽量用 TLS 1.2 以上版本,TLS 1.0/1.1 已经过了退役时间,很多安全扫描工具会直接报漏洞。EMQX 的 Erlang/OTP SSL 库默认会启用较新的 TLS 版本,但如果你用的是老版本 EMQX,最好显式确认一下配置里没有把旧版本强制开启。

4.2 用 OpenSSL 生成自建 CA 和服务端证书

正式签发证书之前,我们需要一套自己的根 CA。这套 CA 的职责就是“自己给自己背书”:它给自己签一个根证书,然后用根证书去签发服务器证书。设备端只要信任这个根证书,就会信任所有由它签发的服务器证书。

在服务器上创建证书目录,逐步执行:

mkdir -p ~/mqtt-certs && cd ~/mqtt-certs # 第一步:生成 CA 私钥和自签名根证书 openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -days 3650 -out ca.crt \ -subj "/C=CN/ST=Shanghai/L=Shanghai/O=YourOrg/CN=YourOrg CA" # 第二步:生成服务端私钥和证书签名请求 openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr \ -subj "/C=CN/ST=Shanghai/L=Shanghai/O=YourOrg/CN=broker.example.com"

注意这里CN=broker.example.com一定要改成你实际的域名或公网 IP,后面验证时客户端会对这个字段和它连接的地址做比对。

接下来创建一个扩展文件,把证书的用途和地址别名写进去:

cat > server.ext <<'EOF' subjectAltName=DNS:broker.example.com,IP:8.8.8.8 extendedKeyUsage=serverAuth EOF

这里IP:8.8.8.8换成你服务器真实的公网 IP,如果设备端是用域名访问,DNS 那段就够了。最后用 CA 签发服务端证书:

openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ -out server.crt -days 825 -sha256 -extfile server.ext

我特意用了 825 天而不是 3650 天,因为现代证书规范对有效期有严格要求,超过 398 天的证书在普通浏览器里会被判定为非法,MQTT 客户端不一定严格校验有效期,但提前养成习惯没坏处。签发完验证一下:

openssl x509 -in server.crt -text -noout | grep -A1 "Subject Alternative Name" openssl verify -CAfile ca.crt server.crt

第二个命令输出server.crt: OK就代表证书链验证通过。到这里,三个关键文件齐了:ca.crt、server.crt、server.key。server.key是私钥,必须保管好,放在 EMQX 服务器上就好,不要发给任何客户端。

4.3 为 EMQX 配置 SSL/TLS 监听器

把证书复制到 EMQX 的证书目录:

sudo mkdir -p /etc/emqx/certs sudo cp ~/mqtt-certs/ca.crt ~/mqtt-certs/server.crt ~/mqtt-certs/server.key /etc/emqx/certs/ sudo chown -R emqx:emqx /etc/emqx/certs

然后修改 EMQX 5.x 的配置,在/etc/emqx/emqx.conf中新增一个 SSL listener:

listeners.ssl.default { bind = "0.0.0.0:8883" max_connections = 1024000 ssl_options { cacertfile = "/etc/emqx/certs/ca.crt" certfile = "/etc/emqx/certs/server.crt" keyfile = "/etc/emqx/certs/server.key" verify = verify_peer fail_if_no_peer_cert = false ciphers = [ "TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256", "ECDHE-ECDSA-AES256-GCM-SHA384", "ECDHE-RSA-AES256-GCM-SHA384" ] } }

几个参数逐个解释:

  • bind:8883 是 MQTT over TLS 的标准端口,建议不要改,客户端默认会尝试这个端口。
  • verify = verify_peer:表示开启证书验证。
  • fail_if_no_peer_cert = false:当前只验证服务端证书,不强制客户端证书。如果你要走 mTLS,这个值要改成true。
  • ciphers:密码套件白名单,只允许用这些套件,这是关键安全项,后面细说。

如果你用的是 EMQX 4.x,配置路径是listener.ssl.external,写法类似,只是区块名不同,把配置块里的listener.ssl.default换成listener.ssl.external即可。

改完重启并确认监听端口:

sudo systemctl restart emqx emqx ctl listeners

输出里应该能看到 SSL listener 处于正常运行状态,监听在 8883 端口。如果起不来,立刻看日志:

tail -n 50 /var/log/emqx/emqx.log

证书文件路径不对、私钥格式不对、权限不足,都会导致 listener 启动失败,日志里一般都会给出明确提示。

4.4 验证 TLS 连接:命令行和图形化客户端

先用 openssl 这个神器直接测握手,它能帮你定位证书链和密码套件的问题:

openssl s_client -connect 127.0.0.1:8883 -showcerts -servername broker.example.com < /dev/null 2>&1 | grep -E "subject=|issuer=|Protocol|Cipher"

如果证书链正常,你会看到subject是你签发的CN=broker.example.com,issuer是你自建的 CA,Protocol和Cipher显示协商出来的 TLS 版本和密码套件。

再用 mosquitto 客户端走一次真实消息发布。因为我们不做双向 TLS,客户端只需要带--cafile来验证服务端:

mosquitto_pub -h broker.example.com -p 8883 \ --cafile ~/mqtt-certs/ca.crt \ -t test/tls -m "hello tls" -d

-d参数会打印出整个连接过程,你会看到证书验证、TLS 握手、消息发布每一步的状态。如果证书里的域名和你-h指定的地址对不上,会直接报证书校验失败,这正好能测出 SAN 配置是否正确。

如果是在 Windows/Mac 上调试,MQTTX 客户端在连接配置里也能填 CA 证书路径,填上之后连接 8883 端口即可,界面会显示连接状态和协议版本。

4.5 弱加密套件与 CVE-2016-2183 的处理

这块要单独拿出来说,因为很多安全扫描工具扫到 SSL/TLS 服务后会报一个很常见的漏洞:SSL/TLS协议信息泄露漏洞(CVE-2016-2183)【原理扫描】。

CVE-2016-2183 就是著名的 SWEET32 攻击,针对的是 3DES 这类 64 位分组的对称加密算法。攻击者可以通过足够多的采样数据,利用分组密码的碰撞概率推算密钥信息,使安全强度大幅下降。扫描器只要发现服务端还支持DES-CBC3-SHA这类 3DES 密码套件,就会把这个漏洞标记出来。

解决思路很简单:在 ssl_options 里把密码套件白名单收紧,不包含任何 3DES/CBC 弱套件。上面配置里我列的那几个都是 GCM 或 CHACHA20 系列的安全套件,没有 3DES 的位置。改完之后,你可以用 openssl 验证一下 3DES 是否真的被禁掉了:

openssl s_client -connect 127.0.0.1:8883 -cipher 'DES-CBC3-SHA' </dev/null 2>&1 | grep -E "error|Cipher is"

如果输出里有wrong version number或握手失败信息,说明服务端已经不支持 3DES,漏洞扫描自然不会命中。

还有一点要注意:禁用弱套件后,一些老设备可能连不上,因为它们的协议栈比较老旧,只支持某些已被弃用的算法。如果你遇到老设备兼容性问题,建议优先升级设备端协议栈,而不是为了兼容去开放弱套件,否则安全扫描这关永远过不了。

5. 踩坑实录:连接异常和配置问题的排查技巧

5.1 常见连接失败原因

把我在实际部署中碰到的问题列个速查表,按出现频率排序:

现象可能原因排查方法
客户端连接超时云安全组/防火墙未放行端口本机telnet 127.0.0.1 8883测试,外网用nc -vz测试
连接被拒绝EMQX 服务未启动或 listener 没起来emqx ctl listeners确认端口监听状态
证书验证失败服务器证书域名和客户端访问地址不匹配检查 SAN 里的 DNS/IP,客户端-h参数必须匹配
证书链不完整服务端证书没有带中间证书查看openssl s_client输出的证书链,缺少中间证书就补进去
握手失败,协议版本错误客户端 TLS 版本过老看-d输出里的Protocol,确认服务端要求 TLS 1.2 以上
SSL 连接被对端关闭客户端没带 CA 根证书或 CA 不对确认--cafile指向的 CA 正是签发服务端证书的那个 CA

5.2 证书相关的几个高频问题

证书问题是最容易卡壳的地方。我总结了三个高频场景:

第一个是“IP 访问正常但域名访问失败”。这是 SAN 配置缺失的典型表现。你签证书的时候只写了IP:x.x.x.x,没有写DNS:domain,客户端按域名去验证时自然对不上。反过来也同理。解决办法很简单:签证书的时候把域名和 IP 都写进 SAN,一行配置的事,别偷懒。

第二个是“客户端带 CA 证书但依然报 unknown ca”。这通常是因为 EMQX 配置里的cacertfile配错了,或者客户端信任的是另一套 CA。检查/etc/emqx/certs/ca.crt是不是真的就是签发server.crt的那个 CA,openssl verify -CAfile ca.crt server.crt能快速判断。

第三个是“证书过期导致大批设备突然掉线”。这个最让人头大。解决办法是提前做证书巡检,我的做法是在 crontab 里加一个每周任务,用脚本检查证书剩余有效期,低于 30 天就发报警通知。续期时重启 EMQX 会带来短暂断连,尽量安排在业务低峰期操作。

5.3 防火墙、SELinux 和系统层面的坑

连接不上,EMQX 日志里也没报错,这种场景十有八九是系统层拦截。云服务器有安全组,本地服务器有 iptables、firewalld 或 ufw,还有 CentOS 的 SELinux,层层叠叠,任何一个环节漏了都连不上。

我自己的排查顺序是:

# 第一步,本机确认端口在监听 ss -lntp | grep -E "1883|8883|18083" # 第二步,本机回环地址测试 mosquitto_pub -h 127.0.0.1 -p 8883 --cafile ca.crt -t test -m ok # 第三步,从外部机器测试端口连通性 nc -vz 服务器IP 8883

如果第一步正常、第二步正常、第三步失败,问题基本锁定在防火墙或安全组。CentOS 上还要检查 SELinux:

getenforce

如果状态是Enforcing,可以临时设为 permissive 再测一次,确认是不是 SELinux 拦截了 EMQX 的端口绑定:

sudo setenforce 0

确认原因是 SELinux 后再考虑是关掉它,还是用semanage给 EMQX 端口加白名单。生产环境我建议加白名单而不是直接关闭,毕竟安全机制能保留还是保留。另外,EMQX 的 Docker 部署还要注意端口映射和容器内网络模式问题,裸机部署反而没这么复杂。

5.4 排查工具推荐

除了 openssl 和 mosquitto,还有几个工具我在排查时经常用:

  • tcpdump:抓包看握手过程,sudo tcpdump -i eth0 port 8883 -w ssl.pcap,再用 Wireshark 打开分析,能看清证书在哪一步断掉。
  • emqx ctl listeners:确认 EMQX 内部视角下所有监听器状态。
  • journalctl -u emqx:systemd 日志,有时候比 emqx.log 的信息更直接。
  • mqttx和mqtt-cli:图形化客户端,界面直观,适合快速验证不同 TLS 配置组合。

6. 上线前最后再检查一遍

6.1 端口策略和监听范围检查

服务上线前,过一遍所有开放端口,确认 1883 明文端口是否必须保留。我的习惯是:如果全部客户端都支持 TLS,就直接把 1883 的 TCP listener 停掉,或者只绑定 127.0.0.1,这样即使配置出问题,也不会明文暴露在公网。

检查方式很简单:

emqx ctl listeners ss -lntp | grep emqx

把不应该对外的端口从系统防火墙和云安全组里清掉,别留着过年。

6.2 认证和 ACL 检查

启用 TLS 只解决“传输加密”,不解决“谁能连上来”。就算加密了,没有认证的 Broker 依然是开放的,任何人都可以注册一个连接然后收发消息。所以 TLS 和认证必须同时上线。

在 Dashboard 的“认证授权”里配置内置数据库认证,给每类设备建单独的账号,再用 ACL 限制它们只能订阅/发布自己的主题范围。比如设备只允许发布devices/{clientid}/data,服务端只允许订阅devices/+/data这类模式,减少越权风险。

6.3 证书备份和续期提醒

证书文件是安全根基。我强烈建议把ca.key和ca.crt离线备份到安全的地方,只要ca.key泄露,整个证书体系都要重建。服务器上的server.key权限设置为 600,只有 emqx 用户能读。

续期提醒可以写个一分钟脚本:

#!/bin/bash remaining_days=$(openssl x509 -enddate -noout -in /etc/emqx/certs/server.crt | cut -d= -f2) # 解析到期时间,小于30天就发报警

放 crontab 里每周跑一次,能帮你提前预警,避免在半夜被设备掉线警报砸醒。

另外还有一个我后期才补上的经验:EMQX 的配置变更务必先备份再操作。改之前cp /etc/emqx/emqx.conf /etc/emqx/emqx.conf.bak.日期,出问题还能秒回滚。这个习惯在每次调整监听器或证书时都能救命。

最后再分享一个小技巧:升级 EMQX 或调整 TLS 配置后,别只看服务起没起来,要看客户端实际连接是否成功。用自动化测试脚本在一台独立机器上连一次 8883 端口并发布一条消息,确认端到端链路真的没问题,再宣布维护窗口结束。这些看似不起眼的检查,才是生产环境稳定运行的根本保障。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询