如何在CentOS7上安装和保护MosquittoMQTT消息代理
介绍
MQTT 是一种机器对机器的消息传递协议,旨在为“物联网”设备提供轻量级的发布/订阅通信。 它通常用于地理跟踪车队、家庭自动化、环境传感器网络和公用事业规模的数据收集。
Mosquitto 是一种流行的 MQTT 服务器(或 broker,用 MQTT 的说法),具有强大的社区支持并且易于安装和配置。
在本教程中,我们将安装 Mosquitto,从 Let's Encrypt 检索 SSL 证书,并设置我们的代理以使用 SSL 来保护我们受密码保护的 MQTT 通信。
先决条件
在开始本教程之前,您需要:
- 具有非 root、启用 sudo 的用户和基本防火墙设置的 CentOS 7 服务器。 New CentOS 7 Server Checklist 涵盖了这个(以及更多)。
- 根据 如何使用 DigitalOcean 设置主机名,指向您的服务器的域名。 本教程将自始至终使用
mqtt.example.com。 - (可选)
nano文本编辑器。 本教程将始终使用nano,您可以随时使用sudo yum -y install nano安装它,或者替换您喜欢的文本编辑器。
第 1 步 — 安装 Mosquitto
CentOS 7 默认没有 mosquitto 软件包。 要安装它,我们将首先安装一个名为 Extra Packages for Enterprise Linux 或 EPEL 的额外软件存储库。 这个存储库充满了可以很好地安装在 CentOS、Red Hat 和其他面向企业的 Linux 发行版上的附加软件。
以非 root 用户登录并使用 yum 包管理器安装 epel-release 包。
sudo yum -y install epel-release
这会将 EPEL 存储库信息添加到我们的系统中。 -y 选项在整个过程中自动对一些提示回答是。 现在我们可以安装 mosquitto 包了。
sudo yum -y install mosquitto
该软件包带有一个简单的默认配置,因此让我们运行它来测试我们的安装。
sudo systemctl start mosquitto
我们还需要启用该服务以确保它在我们重新启动系统时启动:
sudo systemctl enable mosquitto
现在让我们测试一下默认配置。 mosquitto 软件包带有一些命令行 MQTT 客户端。 我们将使用其中一个订阅代理上的主题。
Topics 是您发布和订阅消息的标签。 它们按层次结构排列,例如,您可以使用 sensors/outside/temp 和 sensors/outside/humidity。 您如何安排主题取决于您和您的需求。 在本教程中,我们将使用一个简单的测试主题来测试我们的配置更改。
再次登录您的服务器,这样您就有了两个并排的终端。 在新终端中,使用 mosquitto_sub 订阅测试主题:
mosquitto_sub -h localhost -t test
-h用于指定MQTT服务器的主机名,-t为主题名。 点击 ENTER 后您将看不到任何输出,因为 mosquitto_sub 正在等待消息到达。 切换回您的另一个终端并发布一条消息:
mosquitto_pub -h localhost -t test -m "hello world"
mosquitto_pub 的选项与 mosquitto_sub 相同,但这次我们使用附加的 -m 选项来指定我们的消息。 点击 ENTER,你应该会看到 hello world 在另一个终端弹出。 您已经发送了您的第一条 MQTT 消息!
在第二个终端输入CTRL+C退出mosquitto_sub,但保持与服务器的连接打开。 我们将在第 5 步中再次使用它进行另一个测试。
接下来,我们将使用新的 Let's Encrypt 客户端 Certbot 通过 SSL 保护我们的安装。
第 2 步 — 为 Let's Encrypt 证书安装和运行 Certbot
Let's Encrypt 是一项通过自动化 API 提供免费 SSL 证书的新服务。 官方的 Let's Encrypt 客户端称为 Certbot,它包含在我们在上一步中安装的 EPEL 存储库中。
使用 yum 安装 Certbot。
sudo yum -y install certbot
Certbot 需要回答 Let's Encrypt API 发出的加密挑战,以证明我们控制了我们的域。 它使用端口 80 (HTTP) 和/或 443 (HTTPS) 来完成此操作。 我们将只使用端口 80,所以现在让我们允许该端口上的传入流量。
使用 firewall-cmd 添加 HTTP 服务。
sudo firewall-cmd --permanent --add-service=http
重新加载防火墙以使更改生效。
sudo firewall-cmd --reload
我们现在可以运行 Certbot 来获取我们的证书。 我们将使用 --standalone 选项告诉 Certbot 自行处理 HTTP 质询请求,并且 --standalone-supported-challenges http-01 将通信限制为端口 80。 -d 用于指定您想要证书的域,certonly 告诉 Certbot 只检索证书而不执行任何其他配置步骤。
sudo certbot certonly --standalone --standalone-supported-challenges http-01 -d mqtt.example.com
运行命令时,系统会提示您输入电子邮件地址并同意服务条款。 完成此操作后,您应该会看到一条消息,告诉您该过程成功以及您的证书存储在哪里。
我们有我们的证书。 现在我们需要确保 Certbot 在它们即将到期时自动更新它们。
第 3 步 — 设置 Certbot 自动续订
Let's Encrypt 的证书有效期只有九十天。 这是为了鼓励用户自动化他们的证书更新过程。 我们需要设置一个定期运行的命令来检查过期证书并自动更新它们。
为了每天运行更新检查,我们将使用 cron,这是一种用于运行定期作业的标准系统服务。 我们通过打开和编辑一个名为 crontab 的文件来告诉 cron 要做什么。
sudo EDITOR=nano crontab -e
EDITOR=nano 将使 crontab 文件在 nano 编辑器中打开。 如果您更喜欢默认的 vi 编辑器,请将其关闭。
您现在应该看到默认的 crontab,一个空白文件。 粘贴以下行,然后保存并关闭文件。
crontab
15 3 * * * certbot renew --noninteractive --post-hook "systemctl restart mosquitto"
该行的 15 3 * * * 部分表示“每天凌晨 3:15 运行以下命令”。 Certbot 的 renew 命令将检查系统上安装的所有证书,并更新任何设置为在 30 天内到期的证书。 --noninteractive 告诉 Certbot 不要等待用户输入。
--post-hook "systemctl restart mosquitto" 将重新启动 Mosquitto 以获取新证书,但前提是证书已更新。
现在自动证书更新已设置完毕,我们将回到配置 Mosquitto 以提高安全性。
第 4 步 — 配置 MQTT 密码
让我们将 Mosquitto 配置为使用密码。 Mosquitto 包含一个实用程序,用于生成名为 mosquitto_passwd 的特殊密码文件。 此命令将提示您输入指定用户名的密码,并将结果放在 /etc/mosquitto/passwd 中。
sudo mosquitto_passwd -c /etc/mosquitto/passwd sammy
现在我们将替换默认配置文件并告诉 Mosquitto 使用此密码文件来要求所有连接的登录。 首先,删除现有的mosquitto.conf。
sudo rm /etc/mosquitto/mosquitto.conf
现在打开一个新的空白配置。
sudo nano /etc/mosquitto/mosquitto.conf
粘贴在下面。
/etc/mosquitto/mosquitto.conf
allow_anonymous false password_file /etc/mosquitto/passwd
allow_anonymous false 将禁用所有未经身份验证的连接,并且 password_file 行告诉 Mosquitto 在哪里查找用户和密码信息。 保存并退出文件。
现在我们需要重新启动 Mosquitto 并测试我们的更改。
sudo systemctl restart mosquitto
尝试在没有密码的情况下发布消息。
mosquitto_pub -h localhost -t "test" -m "hello world"
该消息应被拒绝:
OutputConnection Refused: not authorised. Error: The connection was refused.
在我们再次使用密码尝试之前,再次切换到您的第二个终端窗口,并订阅“测试”主题,这次使用用户名和密码:
mosquitto_sub -h localhost -t test -u "sammy" -P "password"
它应该连接并坐下,等待消息。 您可以在本教程的其余部分保持此终端打开并保持连接,因为我们会定期向它发送测试消息。
现在使用您的另一个终端发布消息,再次使用用户名和密码:
mosquitto_pub -h localhost -t "test" -m "hello world" -u "sammy" -P "password"
消息应该像第 1 步一样通过。 我们已经成功地为 Mosquitto 添加了密码保护。 不幸的是,我们通过互联网发送未加密的密码。 接下来我们将通过向 Mosquitto 添加 SSL 加密来解决这个问题。
第 5 步 — 配置 MQTT SSL
要启用 SSL 加密,我们需要告诉 Mosquitto 我们的 Let's Encrypt 证书的存储位置。 打开我们之前启动的配置文件。
sudo nano /etc/mosquitto/mosquitto.conf
在文件末尾粘贴以下内容,留下我们已经添加的两行:
/etc/mosquitto/mosquitto.conf
. . . listener 1883 localhost listener 8883 certfile /etc/letsencrypt/live/mqtt.example.com/cert.pem cafile /etc/letsencrypt/live/mqtt.example.com/chain.pem keyfile /etc/letsencrypt/live/mqtt.example.com/privkey.pem
我们将两个单独的 listener 块添加到配置中。 第一个,listener 1883 localhost,更新端口 1883 上的默认 MQTT 侦听器,这是我们迄今为止一直连接的。 1883 是标准的未加密 MQTT 端口。 该行的 localhost 部分指示 Mosquitto 仅将此端口绑定到 localhost 接口,因此无法从外部访问。 无论如何,外部请求都会被我们的防火墙阻止,但最好是明确的。
listener 8883 在端口 8883 上设置加密侦听器。 这是 MQTT + SSL 的标准端口,通常称为 MQTTS。 接下来的三行 certfile、cafile 和 keyfile 都将 Mosquitto 指向相应的 Let's Encrypt 文件以设置加密连接。
保存并退出文件。
在我们重新启动 Mosquitto 以加载新配置之前,我们需要在默认的 mosquitto 服务文件中修复一件事。 这是 systemd 用来确定如何运行 mosquitto 的文件。 在您喜欢的编辑器中打开它。
sudo nano /etc/systemd/system/multi-user.target.wants/mosquitto.service
查找显示 User=mosquitto 的行并将其删除,然后保存并退出文件。
Mosquitto 仍然会以 mosquitto 用户身份运行,但是当它第一次启动时,它将拥有 root 权限,并且能够加载我们的 Let's Encrypt 证书(仅限于 [ X206X]root 访问,出于安全原因)。 加载证书后,它会下拉到 mosquitto 用户。
我们需要重新加载 systemd 本身,因此它会注意到我们对服务文件所做的更改。
sudo systemctl daemon-reload
现在我们可以重新启动 Mosquitto 来更新设置。
sudo systemctl restart mosquitto
更新防火墙以允许连接到端口 8883。
sudo firewall-cmd --permanent --add-port=8883/tcp
并重新加载防火墙。
sudo firewall-cmd --reload
现在我们再次使用 mosquitto_pub 进行测试,并为 SSL 提供了一些不同的选项。
mosquitto_pub -h mqtt.example.com -t test -m "hello again" -p 8883 --cafile /etc/ssl/certs/ca-bundle.crt -u "sammy" -P "password"
请注意,我们使用的是完整主机名而不是 localhost。 因为我们的 SSL 证书是为 mqtt.example.com 颁发的,所以如果我们尝试与 localhost 建立安全连接,我们会收到错误消息,指出主机名与证书主机名不匹配(即使它们都指向相同的 Mosquitto 服务器)。
--cafile /etc/ssl/certs/ca-bundle.crt 为 mosquitto_pub 启用 SSL,并告诉它在哪里查找根证书。 这些通常由您的操作系统安装,因此 Mac OS、Windows 等的路径不同。 mosquitto_pub 使用根证书来验证 Mosquitto 服务器的证书是否由 Let's Encrypt 证书颁发机构正确签名。 重要的是要注意 mosquitto_pub 和 mosquitto_sub 不会在没有此选项(或类似的 --capath 选项)的情况下尝试 SSL 连接,即使您正在连接到标准安全8883 的端口。
如果测试一切顺利,我们将在另一个 mosquitto_sub 终端中再次看到 hello 。 这意味着您的服务器已完全设置好! 如果您想扩展 MQTT 协议以使用 websockets,您可以执行最后一步。
第 6 步 — 通过 Websockets 配置 MQTT(可选)
为了在 Web 浏览器中使用 JavaScript 使用 MQTT,该协议适用于标准 websockets。 如果您不需要此功能,则可以跳过此步骤。
我们需要在 Mosquitto 配置中再添加一个 listener 块。
sudo nano /etc/mosquitto/mosquitto.conf
在文件末尾,添加以下内容:
/etc/mosquitto/mosquitto.conf
. . . listener 8083 protocol websockets certfile /etc/letsencrypt/live/mqtt.example.com/cert.pem cafile /etc/letsencrypt/live/mqtt.example.com/chain.pem keyfile /etc/letsencrypt/live/mqtt.example.com/privkey.pem
除了端口号和 protocol websockets 行之外,这与前一个块基本相同。 MQTT over websockets 没有官方标准化端口,但 8083 是最常见的。
保存并退出文件,然后重新启动 Mosquitto。
sudo systemctl restart mosquitto
现在,在防火墙中打开端口 8083。
sudo firewall-cmd --permanent --add-port=8083/tcp
最后一次重新加载防火墙。
sudo firewall-cmd --reload
为了测试这个功能,我们将使用一个公共的、基于浏览器的 MQTT 客户端。 有一些,但 mqtt-admin 简单明了。 在浏览器中打开 mqtt-admin 。 您将看到以下内容:
填写连接信息如下:
- Protocol 应该是 wss(代表 websocket secure)。
- Host 应该是 Mosquitto 服务器的域
mqtt.example.com。 - 端口应该是
8083。 - User 应该是你的 Mosquitto 用户名; 在这里,我们使用了 sammy。
- Password 应该是您选择的密码。
- ClientId可以保留默认值,mqtt-admin。
按保存设置后,mqtt-admin将连接到你的Mosquitto服务器。 在下一个屏幕中,将 Topic 填写为 test,为 Payload 输入任何消息,然后按 Publish。 该消息将显示在 mosquitto_sub 终端中。
结论
我们现在已经设置了一个安全的、受密码保护的 MQTT 服务器,它可以自动更新来自 Let's Encrypt 服务的 SSL 证书。 这将为您梦想的任何项目提供强大且安全的消息传递平台。 一些适用于 MQTT 协议的流行软件和硬件包括:
- OwnTracks,一款可以安装在手机上的开源地理追踪应用。 OwnTracks 会定期向您的 MQTT 服务器报告位置信息,然后您可以将其存储并显示在地图上,或者根据您的位置创建警报并激活 IoT 硬件。
- Node-RED 是一个基于浏览器的图形界面,用于将物联网“连接”在一起。 您将一个节点的输出拖到另一个节点的输入,并且可以通过过滤器、在各种协议之间、将信息路由到数据库等。 Node-RED 很好地支持 MQTT。
- ESP8266 是具有 MQTT 功能的廉价 wifi 微控制器。 您可以连接一个以将温度数据发布到主题,或者订阅气压主题并在暴风雨来临时发出蜂鸣声!
这些只是 MQTT 生态系统中的几个流行示例。 有更多的硬件和软件可以使用该协议。 如果您已经拥有喜欢的硬件平台或软件语言,它可能具有 MQTT 功能。 让你的“东西”互相交谈,玩得开心!