如何在Debian8上安装和保护MosquittoMQTT消息代理
介绍
MQTT 是一种机器对机器的消息传递协议,旨在为“物联网”设备提供轻量级的发布/订阅通信。 它通常用于地理跟踪车队、家庭自动化、环境传感器网络和公用事业规模的数据收集。
Mosquitto 是一种流行的 MQTT 服务器(或 broker,用 MQTT 的说法),具有强大的社区支持并且易于安装和配置。
在本教程中,我们将安装 Mosquitto,从 Let's Encrypt 检索 SSL 证书,并设置我们的代理以使用 SSL 来保护我们受密码保护的 MQTT 通信。
先决条件
在开始本教程之前,您需要:
- this Debian 8 server setup tutorial 中详细介绍的具有非 root 用户、启用 sudo 的 Debian 8 服务器。
- 使用
ufw设置的基本防火墙,在 如何在 Ubuntu 14.04 上使用 UFW 设置防火墙中进行了说明。 尽管标题以 Ubuntu 为中心,但您可以在 Debian 中跟进,确保首先使用sudo apt-get install ufw,因为 Debian 默认不包含ufw。 - 根据 如何使用 DigitalOcean 设置主机名,指向您的服务器的域名。 本教程将自始至终使用
mqtt.example.com。
第 1 步 — 安装 Mosquitto
Debian 的 mosquitto 软件包不支持我们需要的某些功能,因此我们将从 Mosquitto 项目提供的更新的存储库安装。 首先,下载他们的存储库签名密钥。
wget http://repo.mosquitto.org/debian/mosquitto-repo.gpg.key
然后用 apt-key 安装密钥。
sudo apt-key add mosquitto-repo.gpg.key
这允许 apt-get 验证您从新存储库安装的任何软件的完整性。
现在通过将存储库 URL 添加到 /etc/apt/sources.list.d/ 中的文件来告诉 apt-get 在哪里可以找到软件。
sudo nano /etc/apt/sources.list.d/mosquitto.list
这将打开一个新的空白文件。 将以下行粘贴到文件中。
/etc/apt/sources.list.d/mosquitto.list
deb http://repo.mosquitto.org/debian jessie main
保存并关闭编辑器,然后使用 apt-get 更新以获取新的包信息。
sudo apt-get update
最后,安装 mosquitto 软件包及其客户端软件。
sudo apt-get install mosquitto mosquitto-clients
默认情况下,Debian 会在安装后启动 Mosquitto 服务。 让我们测试一下默认配置。 我们将使用我们刚刚安装的客户端之一订阅代理上的主题。
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 证书的新服务。 有许多客户端可以与 API 通信,Debian 在其默认存储库中包含官方客户端,但它有点过时并且缺少我们需要的一项重要功能。
相反,我们将从 Debian 的 backports 存储库安装客户端。 这是一个官方存储库,它使选定软件的更新版本可用于已发布的 Debian 版本。 我们需要将存储库添加到我们的 APT 源列表中,就像我们在上一步中所做的那样。
首先,在/etc/apt/sources.list.d/中打开一个新文件。
sudo nano /etc/apt/sources.list.d/backports.list
将以下行粘贴到文件中:
/etc/apt/sources.list.d/backports.list
deb http://mirrors.digitalocean.com/debian jessie-backports main
保存文件,然后关闭编辑器。 之后,更新包信息。
sudo apt-get update
最后,安装名为 Certbot 的官方 Let's Encrypt 客户端,告诉 APT 使用 jessie-backports 作为其源:
sudo apt-get install certbot -t jessie-backports
现在我们已经安装了 Certbot,让我们运行它来获取我们的证书。
第 3 步 — 运行 Certbot
Certbot 需要回答 Let's Encrypt API 发出的加密挑战,以证明我们控制了我们的域。 它使用端口 80 (HTTP) 和/或 443 (HTTPS) 来完成此操作。 我们将只使用端口 80,因此允许该端口上的传入流量。
sudo ufw allow http
OutputRule added Rule added (v6)
我们现在可以运行 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 在它们即将到期时自动更新它们。
第 4 步 — 设置 Certbot 自动续订
Let's Encrypt 的证书有效期只有九十天。 这是为了鼓励用户自动化他们的证书更新过程。 我们需要设置一个命令来定期检查过期证书并自动更新它们。
为了每天运行更新检查,我们将使用 cron,这是一种用于运行定期作业的标准系统服务。 我们通过打开和编辑一个名为 crontab 的文件来告诉 cron 要做什么。
sudo crontab -e
系统将提示您选择文本编辑器。 选择您最喜欢的,您将看到默认的 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 以获取新证书,但前提是证书已更新。 这个 post-hook 功能是旧版本的 Let's Encrypt 客户端所缺少的,也是我们从后端而不是默认的 Debian 存储库安装的原因。 如果没有它,我们将不得不每天重新启动 Mosquitto,即使实际上没有更新任何证书。 尽管您的 MQTT 客户端应配置为自动重新连接,但明智的做法是避免每天无缘无故地中断它们。
现在自动证书更新已设置完毕,我们将回到配置 Mosquitto 以提高安全性。
第 5 步 — 配置 MQTT 密码
让我们将 Mosquitto 配置为使用密码,这样我们就可以控制谁可以发布消息。 Mosquitto 包含一个实用程序,用于生成名为 mosquitto_passwd 的特殊密码文件。 此命令将提示您输入指定用户名的密码,并将结果放在 /etc/mosquitto/passwd 中。
sudo mosquitto_passwd -c /etc/mosquitto/passwd sammy
现在为 Mosquitto 创建一个新的配置文件,并告诉它使用这个密码文件来要求所有连接的登录。
sudo nano /etc/mosquitto/conf.d/default.conf
这应该打开一个空文件。 粘贴以下内容:
/etc/mosquitto/conf.d/default.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.
在我们再次尝试使用密码之前,再次切换到您的第二个终端窗口,并订阅 test 主题,这次使用用户名和密码:
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 加密来解决这个问题。
第 6 步 — 配置 MQTT SSL
要启用 SSL 加密,我们需要告诉 Mosquitto 我们的 Let's Encrypt 证书的存储位置。 打开我们之前启动的配置文件。
sudo nano /etc/mosquitto/conf.d/default.conf
在文件末尾粘贴以下内容,留下我们已经添加的两行:
/etc/mosquitto/conf.d/default.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 以更新设置。
sudo systemctl restart mosquitto
更新防火墙以允许连接到端口 8883。
sudo ufw allow 8883
OutputRule added Rule added (v6)
现在使用 mosquitto_pub 再次测试,SSL 有几个不同的选项:
mosquitto_pub -h mqtt.example.com -t test -m "hello again" -p 8883 --capath /etc/ssl/certs/ -u "sammy" -P "password"
请注意,我们使用的是完整主机名而不是 localhost。 因为我们的 SSL 证书是为 mqtt.example.com 颁发的,所以如果我们尝试与 localhost 建立安全连接,我们会收到错误消息,指出主机名与证书主机名不匹配(即使它们都指向相同的 Mosquitto 服务器)。
--capath /etc/ssl/certs/ 为 mosquitto_pub 启用 SSL,并告诉它在哪里查找根证书。 这些通常由您的操作系统安装,因此 macOS、Windows 等的路径不同。 mosquitto_pub 使用根证书来验证 Mosquitto 服务器的证书是否由 Let's Encrypt 证书颁发机构正确签名。 重要的是要注意 mosquitto_pub 和 mosquitto_sub 不会在没有此选项(或类似的 --cafile 选项)的情况下尝试 SSL 连接,即使您正在连接到标准安全8883 的端口。
如果测试一切顺利,您会在另一个 mosquitto_sub 终端中再次看到 hello 。 这意味着您的服务器已完全设置好! 如果您想扩展 MQTT 协议以使用 websockets,您可以执行最后一步。
第 7 步 — 通过 Websockets 配置 MQTT(可选)
为了在 Web 浏览器中使用 JavaScript 使用 MQTT,该协议适用于标准 websockets。 如果您不需要此功能,则可以跳过此步骤。
我们需要在 Mosqiutto 配置中再添加一个 listener 块。
sudo nano /etc/mosquitto/conf.d/default.conf
在文件末尾,添加以下内容:
/etc/mosquitto/conf.d/default.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 ufw allow 8083
为了测试这个功能,我们将使用一个公共的、基于浏览器的 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 功能。 让你的“东西”互相交谈,玩得开心!