如何在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 功能。 让你的“东西”互相交谈,玩得开心!