翻译:如何在Ubuntu16.04上安装Mosquitto这个MQTT消息服务器并对其进行安全配置

原文地址: https://www.digitalocean.com/community/tutorials/how-to-install-and-secure-the-mosquitto-mqtt-messaging-broker-on-ubuntu-16-04

简介

MQTT是一个在机器和机器之间传递消息的协议,为实现物联网设备间轻量级的发布/订阅通信而设计。广泛应用于汽车地理位置追踪,智能家居自动化,环境传感网络,以及各项公共事业的数据收集。

Mosquitto是一个流行的MQTT服务器(在MQTT协议中叫中继器),拥有强大的社区支持,易于安装、配置。

在此教程中,我们将安装Mosquito,从Let's Encrypt获取证书,搭建我们自己的中继器,采用密码认证,采用SSL来确保MQTT通信安全。

前提条件

在开始这个教程之前,你需要:

  • 一个Ubuntu16.04服务器,非root并且开启了sudo的用户,设置了基本的防火墙,具体请参考这个Ubuntu16.04服务器搭建教程。
  • 一个指向了你服务器的域名,可以参照如何在DigitalOcean上创建一个域名。这篇教程将使用mqtt.example.com代替。

步骤1 安装Mosquitto

Ubuntu16.04默认软件仓库的Mosquitto版本就挺新的。用你的非root用户登录并使用 apt-get安装Mosquitto.

$ sudo apt-get install mosquitto mosquitto-clients

默认情况下,Ubuntu会在安装后启动Mosquitto服务。我们先测试一下默认配置。使用刚安装的Mosquitto客户端订阅中继器上的一个主题。

主题是发送和订阅消息的标签。它们按层次设置,比如你可以将主题设置为sensors/outside/tempsensors/outside/humidity。如何设置主题取决于的你需要。教程通篇将用一个简单的主题test来测试配置变化。

再打开一个服务器命令窗口,这样你就有两个并列的窗口了。在新的命令行中,使用mosquitto_sub来订阅test主题:

mosquitto_sub -h localhost -t test

-h用于指定MQTT服务器的主机名,-t用于指定主题。当按下回车键之后,没有任何输出,这是因为mosquitto_sub正在等待消息送达。回到另外一个命令行,发布一条消息:

mosquitto_pub -h localhost -t test -m "Hello world"

mosquitto_pub的选项和mosquitto_sub的一样,除了这次我们用了一个-m选项来指定消息内容。按下回车,将会看到Hello world在另外一个命令行中出现。你刚刚发送了你的第一条MQTT消息。

在第二个命令行输入CTRL + C,退出mosquitto_sub, 但保持和服务器的连接。在步骤五将再次使用到它。

接下来,我们将用通过Certbot的SSL来确保我们Mosquitto的安全,Certbot是Let's Encrypt的新版客户端。

步骤2 为了获得Let's Encrypt证书,安装Certbot

Let's Encrypt是一个通过自动化的API,提供免费的SSL证书的服务。很多客户端可以调用这个API。Ubuntu的默认仓库包含了官方的客户端,但有点过时了,并且缺少了一个我们需要的新特性。

因此,我们从一个Ubuntu PPA(Personal Package Archive)安装官方的客户端。很多替代仓库的打包了更新的版本,或者是小众软件。首先,添加仓库:

sudo add-apt-respository ppa:certbot/certbot

需要敲一下回车来接受安装。接下来,更新包列表来获取新仓库的包信息。

sudo apt-get update

最后,安装Let's Encrypt的官方客户端,叫做certbot

sudo apt-get install certbot

certbot已经安装完成,接下来运行它来获得我们所需的证书。

步骤3 运行Certbot

certbot需要响应一个Let's Encrypt发出的密码质询,用来证明我们对这个域名有控制权。它使用端口80(HTTP) 且/或 443(HTTPS)来完成。我们将仅使用端口80,所以我们需要在这个端口上允许入网流量。

$ sudo ufw allow http
Rule added

现在我们可以运行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

运行上述命令时,命令行会提示你输入一个邮箱地址,并同意服务条款。再之后,你将会看到一条消息,告诉你处理成功,并且告知你证书的存放位置。

我们已经获得了证书,现在我们需要确保Certot在证书快过期时自动地更新他们。

步骤4 创建Certbot的自动更新策略

Let's Encrypt的证书有效期仅为90天。这是为了鼓励用户将他们的证书更新流程自动化。我们将创建一个定期运行的命令,检查证书过期情况并自动更新它们。

我们将通过cron每天运行更新检查。这是运行周期性工作的一个系统服务。打开并编辑一个叫做crontab的文件,来指定cron要完成的工作。

sudo crontab -e

你将会看到选择一个文本编辑器的提示。选一个你喜欢的,然后将会看到默认的corontab, 并且附带一个帮助说明。在文件的最后加入下面这一行,保存并关闭文件。

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客户端没有的。这也是我们从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"

这条消息会被拒绝:

Output
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增加了密码保护功能。不幸的是,我们发送密码的时候未进行加密。我们接下来将通过增加SSL加密来解决这一问题。

步骤6 配置MQTT的SSL

为开启SSL加密,需要在Mosquitto配置里制定证书存放的位置。打开刚才开始的配置文件:

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,更新了处于端口1883上的默认MQTT监听器,我们一直以来用的就是这一个。1883是标准的非加密MQTT端口。这一行的localhost部分表明Mosquitto只会把这个端口绑定到localhost接口上,所以无法从外部访问。外部请求应该已经被防火墙阻挡了,接下来会说明一下。

listener 8883在端口8883建立了一个加密的监听器。这是MQTT+SSL(通常指MQTTS)的标准端口。接下来三行,certfilecafilekeyfile,都是为了将Mosquitto指向特定的Let's Encrypt文件,这些文件将被用于创建加密的连接。

保存并退出文件,重启Mosquitto以更新配置:

sudo systemctl restart mosquitto

更新防火墙,使其允许连接到端口8883。

sudo ufw allow 8883

接下来,使用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/certsmosquitto_pub启动了SSL,并指定了去何处寻找根证书。这些证书被你的操作系统安装在特定的位置,所以这个地址在MacOS、Windows等系统上是不一样的。mosquitto_pub采用根证书来来检查Mosquitto服务器的证书是否是否被Let's Encrypt的证书授权机构认证过。有一点需要注意的是,没有这个选项,mosquitto_pubmosquitto_sub是不会尝试使用SSL链接的,即使你尝试连接到一个标准的安全端口8883。一个类似的选项为--cafile

如果测试顺利的话,会看到hello again出现在命令行中。到这里,意味着已经完成了服务器搭建!如果你对拓展MQTT协议,使其可以基于websocket协议工作的话,请参考下面最终一步。

步骤7 配置通过WebSockets来使用MQTT(可选)

为了在web浏览器中通过JavaScript调用MQTT,协议通过适配,可以支持标准的WebSockets。如果你不需要这项功能,可以跳过此步骤。

我们需要在配置文件添加一个新的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那一行。对于通过websockets方式提供的MQTT服务,没有官方的标准。但8083是最常用的。

保存并退出这个文件,然后重启Mosquitto。

sudo systemctl restart mosquitto

接下来,在防火墙开启8083端口。

sudo ufw allow 8083

为测试此功能,需要用到一个公开的,基于浏览器的MQTT客户端。这种客户端有很多,但mqtt-admin是最简单直接的。在浏览器打开mqtt-admin。将会看到设置窗口。

填入如下连接信息:

  • Protocol选择wss(websocket secure)。
  • Host填入Mosquitto服务器的域名。
  • Port填入8083
  • User填入Mosquitto的用户名。
  • Password填入你设置的密码。
  • ClientID保持默认。

点击保存设置之后,mqtt-admin会连接到Mosquitto服务器。接下来,在Topic处填入test,在Payload处填入任意信息,然后点击Publish。将会在mosquitto_sub命令行显示消息。

结语

到现在为止,我们已经建立起了一个安全,有密码保护机制的MQTT服务器,并设置了从Let's Encrypt服务自动更新SSL证书的方法。这对于你未来的任何项目都能够提供稳健和安全的消息平台。一些流行的软件和硬件在MQTT协议下运转良好:

  • OwnTracks, 是一个开源的地理位置追踪APP。OwnTracks会定期向服务器报告位置信息。随后你可以存储并将这些信息展示在底图上,创建警报器,基于地理位置激活你的物联网设备。
  • Node-RED, 一个基于浏览器的图形界面,用于将物联网设备连接起来。可以将一个节点的输出连接到另一个节点的输入上,并可以通过过滤器在不同的协议之间路由信息。存入数据库等等。
  • ESP8266是一个便宜的WiFi微控制器,并具备MQTT能力。可以通过它发布温度信息到一个主题上,或者可以订阅大气压主题再或者当暴风雨来临时让蜂鸣器响起来。

这仅是MQTT生态系统的一部分知名案例。有更多的一些硬件或者软件采用了这种协议。如果你已经有了一个自己喜爱的硬件平台,或者软件编程语言,它可能就已经具备了MQTT能力。在让你的“物”彼此通信的过程中享受乐趣吧。

相关推荐