翻譯:如何在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/temp
、sensors/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)的標準端口。接下來三行,certfile
,cafile
,keyfile
,都是為了將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/certs
為mosquitto_pub
啟動了SSL,並指定了去何處尋找根證書。這些證書被你的操作系統安裝在特定的位置,所以這個地址在MacOS、Windows等系統上是不一樣的。mosquitto_pub
采用根證書來來檢查Mosquitto服務器的證書是否是否被Let‘s Encrypt的證書授權機構認證過。有一點需要註意的是,沒有這個選項,mosquitto_pub
和mosquitto_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能力。在讓你的“物”彼此通信的過程中享受樂趣吧。
翻譯:如何在Ubuntu16.04上安裝Mosquitto這個MQTT消息服務器並對其進行安全配置