介绍
MQTT是一种机器对机器的消息传递协议,旨在为“物联网”设备提供轻量级的发布/订阅通信。它通常用于地理跟踪车队、家庭自动化、环境传感器网络和大规模数据收集。
Mosquitto是一个流行的MQTT服务器(或者在MQTT术语中称为broker),它拥有强大的社区支持,并且易于安装和配置。
在本教程中,我们将安装Mosquitto,从Let’s Encrypt检索SSL证书,并设置我们的broker使用SSL来保护我们的密码保护的MQTT通信。
先决条件
在开始本教程之前,您需要:
- 一个Ubuntu 16.04服务器,具有非root的sudo启用用户和基本防火墙设置,详细信息请参阅Ubuntu 16.04服务器设置教程。
- 一个指向您服务器的域名,如何在DigitalOcean上设置主机名。本教程将始终使用
mqtt.example.com
。
步骤1 — 安装Mosquitto
Ubuntu 16.04默认软件仓库中有一个相当新的Mosquitto版本。使用您的非root用户登录,并使用apt-get
安装Mosquitto。
sudo apt-get install mosquitto mosquitto-clients
默认情况下,Ubuntu将在安装后启动Mosquitto服务。让我们测试默认配置。我们将使用刚刚安装的Mosquitto客户端之一来订阅我们的broker上的一个主题。
主题是您发布消息和订阅的标签。它们被安排为一个层次结构,因此您可以有传感器/外部/温度
和传感器/外部/湿度
,例如。如何安排主题取决于您和您的需求。在本教程中,我们将使用一个简单的测试主题来测试我们的配置更改。
第二次登录服务器,这样您就可以并排拥有两个终端。在新终端中,使用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步中再次使用它进行另一个测试。
接下来,我们将使用Certbot来使用SSL保护我们的安装。
步骤2 — 安装Certbot以获取Let’s Encrypt证书
Let’s Encrypt是一个通过自动化API提供免费SSL证书的新服务。有许多客户端可以与API通信,Ubuntu在其默认仓库中包含官方客户端,但它有点过时并且缺少我们需要的一个重要功能。
相反,我们将从Ubuntu PPA(个人软件包存档)安装官方客户端。这些是打包更近期或更晦涩软件的替代存储库。首先,添加存储库。
sudo add-apt-repository ppa:certbot/certbot
您需要按ENTER
接受。之后,更新软件包列表以获取新存储库的软件包信息。
sudo apt-get update
最后,安装官方Let’s Encrypt客户端,称为certbot
。
sudo apt-get install certbot
现在我们已经安装了certbot
,让我们运行它来获取我们的证书。
步骤3 — 运行Certbot
certbot
需要回答Let’s Encrypt API发出的加密挑战,以证明我们控制我们的域。它使用端口80
(HTTP)和/或443
(HTTPS)来完成这一点。我们只会使用端口80
,所以让我们现在允许该端口的传入流量:
sudo ufw allow http
已添加规则
现在我们可以运行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
,其中包含一些帮助文本。在文件末尾粘贴以下行,然后保存并关闭。
. . . 15 3 * * * certbot renew --noninteractive --post-hook "systemctl restart mosquitto"
这行中的 15 3 * * *
部分表示“每天凌晨 3:15 运行以下命令”。Certbot 的 renew
命令将检查系统上安装的所有证书,并更新任何设置在不到三十天后到期的证书。--noninteractive
告诉 Certbot 不要等待用户输入。
--post-hook "systemctl restart mosquitto"
将重新启动 Mosquitto 以获取新证书,但仅在证书被续订时。这个 post-hook
功能是旧版本的 Let’s Encrypt 客户端所缺少的,这也是为什么我们从 PPA 安装而不是使用默认的 Ubuntu 仓库。没有它,我们将不得不每天重新启动 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
这将打开一个空文件。粘贴以下内容:
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"
消息应该被拒绝:
Connection 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
在文件末尾粘贴以下内容,保留我们已经添加的两行:
. . . 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
更新了默认的 MQTT 监听器,端口为 1883
,这是我们到目前为止连接的标准未加密 MQTT 端口。localhost
部分指示 Mosquitto 仅将此端口绑定到本地主机接口,因此它不可从外部访问。外部请求本来已经被我们的防火墙阻止,但明确指定也是好的。
listener 8883
在端口 8883
上设置了一个加密监听器。这是 MQTT + SSL 的标准端口,通常称为 MQTTS。接下来的三行 certfile
、cafile
和 keyfile
都指向适当的 Let’s Encrypt 文件,以设置加密连接。
保存并退出文件,然后重新启动 Mosquitto 以更新设置:
sudo systemctl restart mosquitto
更新防火墙以允许连接到端口 8883
。
sudo ufw allow 8883
Rule added
现在我们再次使用 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,并告诉它在哪里查找根证书。这些通常由你的操作系统安装,因此对于 Mac OS、Windows 等,路径是不同的。mosquitto_pub
使用根证书来验证 Mosquitto 服务器的证书是否由 Let’s Encrypt 证书颁发机构正确签名。重要的是要注意,即使你连接到标准的安全端口 8883
,如果没有这个选项(或类似的 --cafile
选项),mosquitto_pub
和 mosquitto_sub
将不会尝试 SSL 连接。
如果测试顺利,我们将在另一个 mosquitto_sub
终端中看到 hello again。这意味着你的服务器已经完全设置好了!如果你想扩展 MQTT 协议以使用 WebSockets,你可以按照最后一步进行操作。
第7步 — 配置 MQTT Over Websockets(可选)
为了在 web 浏览器中使用 JavaScript 来进行 MQTT 通信,该协议已经被调整以在标准的 websockets 上运行。如果您不需要这个功能,可以跳过这一步。
我们需要在 Mosquitto 配置中添加一个 listener
块:
sudo nano /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 客户端。有一些选择,但 Eclipse Paho JavaScript 客户端简单且易于使用。在浏览器中打开 Paho 客户端。您将看到以下内容:
!Paho 客户端屏幕
填写连接信息如下:
- 主机 应该是您的 Mosquitto 服务器的域名,
mqtt.example.com
。 - 端口 应该是
8083
。 - ClientId 可以保留默认值,js-utility-DI1m6。
- 路径 可以保留默认值,/ws。
- 用户名 应该是您的 Mosquitto 用户名;在这里,我们使用了 sammy。
- 密码 应该是您选择的密码。
其余字段可以保留默认值。
按下 Connect 后,Paho 基于浏览器的客户端将连接到您的 Mosquitto 服务器。
要发布消息,导航到 Publish Message 面板,填写 Topic 为 test,并在 Message 部分输入任何消息。然后,按下 Publish。消息将显示在您的 mosquitto_sub
终端中。
结论
我们现在已经设置了一个安全的、受密码保护的 MQTT 服务器,并从 Let’s Encrypt 服务获得了自动更新的 SSL 证书。这将为您梦想中的任何项目提供一个强大且安全的消息平台。一些与 MQTT 协议兼容的流行软件和硬件包括:
- OwnTracks,一个您可以在手机上安装的开源地理跟踪应用。OwnTracks 将定期向您的 MQTT 服务器报告位置信息,然后您可以将其存储并显示在地图上,或者根据您的位置创建警报并激活 IoT 硬件。
- Node-RED 是一个基于浏览器的图形界面,用于“连接”物联网。您可以将一个节点的输出拖动到另一个节点的输入,并可以通过过滤器、各种协议之间的路由信息,进入数据库等。Node-RED 对 MQTT 的支持非常好。
- ESP8266 是一款具有 MQTT 功能的廉价 wifi 微控制器。您可以将其连接到一个主题以发布温度数据,或者订阅气压主题,并在暴风雨来临时发出蜂鸣器声音!
这些只是 MQTT 生态系统中的一些流行示例。还有更多的硬件和软件支持该协议。如果您已经有喜爱的硬件平台或软件语言,它可能已经具备了 MQTT 的功能。祝您玩得开心,让您的“物”彼此交流!