介绍
MQTT是一种机器到机器消息协议,旨在为“物联网”设备提供轻量级发布/订阅通信。它通常用于车辆的地理跟踪车队,家庭自动化,环境传感器网络和公用事业规模的数据收集。 Mosquitto是一个受欢迎的MQTT服务器(或 代理 ,在MQTT中的用法),具有良好的社区支持,易于安装和配置。 在本教程中,我们将安装Mosquitto,从Let's Encrypt检索SSL证书,并设置我们的代理使用SSL来保护受密码保护的MQTT通信。先决条件
在开始本教程之前,您需要:- 一个Debian 8服务器,具有非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
安装该
apt-key
。
sudo apt-key add mosquitto-repo.gpg.key
这允许
apt-get
验证从新存储库安装的任何软件的完整性。 现在告诉
apt-get
在哪里找到软件,通过将存储库URL添加到/etc/apt/sources.list.d/中的文件。
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
更新以
apt-get
新程序包信息。
sudo apt-get update
最后,安装
mosquitto
软件包及其客户端软件。
sudo apt-get install mosquitto mosquitto-clients
默认情况下,Debian将在安装后启动Mosquitto服务。让我们测试默认配置。我们将使用刚刚安装的一个客户端订阅我们的代理上的主题。
主题是您向其发布消息和订阅的标签。 它们被布置为层次结构,因此,例如,您可以具有
sensors/outside/temp
和
sensors/outside/humidity
。如何安排主题取决于你和你的需要。在本教程中,我们将使用一个简单的测试主题来测试我们的配置更改。 第二次登录到您的服务器,因此您有两个端子并排。在新终端中,使用
mosquitto_sub
订阅测试主题:
mosquitto_sub -h localhost -t test
-h
标志指定MQTT服务器的主机名,
-t
是主题名称。 由于
mosquitto_sub
正在等待消息到达,因此在按
ENTER
后没有输出。切换回您的其他终端并发布消息:
mosquitto_pub -h localhost -t test -m "hello world"
mosquitto_pub
的选项与
mosquitto_pub
相同,但是这次我们使用附加的
-m
选项来指定我们的消息。 按
ENTER
,你应该看到
hello world弹出在另一个终端。您发送了第一个MQTT消息! 在第二个终端中按
CTRL+C
退出
mosquitto_sub
,但保持与服务器的连接打开。我们将在第5步中再次使用它进行另一个测试。 接下来,我们将使用
Certbot (新的Let's Encrypt客户端)使用SSL保护我们的安装。
第2步 - 安装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
最后,安装官方Let's Encrypt客户端,名为Certbot,告诉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自动续订
让我们加密的证书只有九十天有效。这是为了鼓励用户自动执行证书续订过程。我们需要设置一个定期检查到期证书并自动更新的命令。 为了每天运行更新检查,我们将使用cron
作为运行周期性作业的标准系统服务。 我们通过打开和编辑名为
crontab
的文件告诉
cron
要做什么。
sudo crontab -e
系统将提示您选择文本编辑器。选择你最喜欢的,你会看到默认的
crontab
,其中有一些帮助文本。粘贴到文件末尾的下一行,然后保存并关闭它。
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客户端的旧版本缺少的,为什么我们从backports而不是默认的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.
在我们再次尝试使用密码,再次切换到您的第二个终端窗口,并订阅
测试主题,使用用户名和密码本次:
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。不幸的是,我们通过互联网发送密码未加密。我们将通过添加SSL加密到Mosquitto来解决。
第6步 - 配置MQTT SSL
要启用SSL加密,我们需要告诉Mosquitto我们的加密证书存储在哪里。打开我们以前启动的配置文件。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证书颁发机构正确签名。 请注意,即使您连接到
8883
的标准安全端口,
mosquitto_pub
和
mosquitto_sub
也不会尝试使用此选项(或类似的
--cafile
选项)的SSL连接。 如果一切顺利的测试,你会看到你
再次出现在另一个
mosquitto_sub
终端。这意味着您的服务器已完全设置!如果你想扩展MQTT协议来使用websockets,你可以按照最后一步。
第7步 - 通过Websockets配置MQTT(可选)
为了使用Web浏览器中的JavaScript来讲MQTT,协议适用于通过标准websockets工作。如果您不需要此功能,则可以跳过此步骤。 我们需要添加一个listener
块到我们的Mosqiutto配置。
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
与上一个块相同,除了端口号和
protocol websockets
行。 没有用于MQTT的官方标准化端口通过websockets,但
8083
是最常见的。 保存并退出文件,然后重新启动Mosquitto。
sudo systemctl restart mosquitto
现在,打开防火墙中的端口
8083
。
sudo ufw allow 8083
为了测试这个功能,我们将使用一个基于浏览器的公共MQTT客户端。有几个,但是
mqtt-admin是简单和直接。
在浏览器中打开mqtt-admin 。您将看到以下内容:
按如下所示填写连接信息:
- 协议应该是wss (这代表web的ocket s ecure)。
- 主机应该是您的Mosquitto服务器的域,
mqtt.example.com
。 - 端口应为
8083
。 - 用户应该是您的Mosquitto用户名; 在这里,我们使用sammy 。
- 密码应该是您选择的密码。
- ClientId可以保留默认值mqtt-admin 。
mqtt-admin
将连接到您的Mosquitto服务器。 在下一个屏幕中,填写
Topic作为
测试 ,输入任何有关
Payload的消息,然后按
发布 。 该消息将显示在
mosquitto_sub
终端中。