ngrok TCP 通道
Woow EMQX add-on 專屬的 ngrok TCP 通道:ngrok_enabled、authtoken、固定 TCP 位址、公開 1883 的風險,以及用 Cloudflare Tunnel 的替代。
為什麼要學這個
家裡的 EMQX 預設只接受區域網路的連線,外部裝置根本進不來。但只要你想「人在外面也能訂閱或發布」——例如出門要看客廳的感測器、想遠端把玄關的燈關掉——就需要在內網與外面世界之間開一條路。Woow EMQX 從 add-on 5.9.0 版本開始內建 ngrok,能用一行設定把 raw MQTT(連接埠 1883)變成公開的 TCP 通道。
如果你沒想清楚 authtoken、固定位址與暴露風險,等於把 broker 的入口直接掀給整個網際網路。讀完這章,你會懂:ngrok 三個選項各自控制什麼、公開網址要去哪一行 Log 找、什麼情況該改走 Cloudflare Tunnel,以及上線前必須先完成的保護動作。
核心概念
ngrok是內網穿透(tunnel)服務:它在你的機器上跑一個 agent,與 ngrok 雲端建立連線,外部流量就能經由它轉回到本地連接埠。Woow add-on 用這個做法,把 broker 的 1883 轉成一條公開的 TCP 位址,外部 MQTT 用戶端連這條位址即可發布或訂閱。
先分清楚兩層版本:add-on 版本5.9.0 只新增內建 ngrok TCP 通道,底下的核心仍是EMQX 5.8.9。你調整 ngrok_enabled、ngrok_authtoken 這類選項,修改的是 add-on 層,不會改變 EMQX 5.8.9 原有的驗證、ACL 或監控行為。
ngrok 通道有它自己的安全含義:把 1883 開到公網之後,任何能連到那條位址的人都能嘗試連線。EMQX 若尚未設定 Authentication,會允許所有 client 連線;所以「先設好驗證與 ACL,再決定是否開啟 ngrok」,是本章的黃金規範。
名詞對照
| 英文 | 中文 | 一句話 |
|---|---|---|
| ngrok | 內網穿透服務 | 把本地連接埠變成公開 TCP 端點 |
| TCP Tunnel | TCP 通道 | 直接轉發 raw MQTT(1883)的隧道 |
| Authtoken | 授權碼 | 你的 ngrok 帳號授權,啟用時必填 |
| Reserved Address | 固定位址 | 向 ngrok 保留的 TCP 位址,重啟後不變 |
| Public URL | 公開網址 | ngrok 產生的外部端點,印在 Log |
| Cloudflare Tunnel | Cloudflare 隧道 | 替代方案,特別適合 WebSocket(8083) |
其中 authtoken 是秘密值:它等同 ngrok 帳號權限。請不要把自己的 token 寫進 HTML 或貼進 log,教學一律以佔位符(YOUR_TOKEN、<你的 ngrok authtoken>)表示。
動手做
先檢查驗證狀態
開啟 ngrok 前,先去 EMQX Dashboard 的 Access Control → Authentication 建立一組使用者,並在 Authorization 設好最小權限。至少要確保公開後不會讓網際匿名連線。
開啟 add-on 的 ngrok 設定
到 Home Assistant:設定 → 附加元件 → Woow EMQX → 設定(Configuration)分頁,找到 ngrok 三個選項,把
ngrok_enabled改成true。填入 authtoken(必要)
在
ngrok_authtoken貼上你的 ngrok 授權碼(此處以<你的 ngrok authtoken>代替)。若你已在 ngrok 帳號保留固定 TCP 位址,就填進ngrok_tcp_addr;否則留空。重啟並確認 Log
回到概覽分頁按「重新啟動」。等 add-on 上線後,打開 Log 找一行形如
>>> MQTT ngrok: <public_url>,那就是外部 MQTT client 要連的公開位址。
add-on 的 config.yaml 把這三個選項的 schema 定義為:ngrok_enabled 是 bool(預設 false)、ngrok_authtoken 是 password?、ngrok_tcp_addr 是 str?。
ngrok 的三個選項
ngrok 功能由這三個選項控制。掌握型態與預設值,才知道自己到底開放了多少風險。
| 選項 | 型態 | 預設 | 作用 |
|---|---|---|---|
| ngrok_enabled | bool | false | 啟停 ngrok TCP 1883 通道 |
| ngrok_authtoken | password | 空 | 帳號授權,開啟時必填 |
| ngrok_tcp_addr | string | 空 | 指定保留位址以取得固定端點 |
執行行為很直接:ngrok_enabled 為 false 時,ngrok service 直接 idle;啟用了但 authtoken 沒填則記一則錯誤並保持 idle(EMQX 本體照常運行)。authtoken 有值之後,才執行 ngrok tcp 1883,若填了 ngrok_tcp_addr 則是 ngrok tcp 1883 --remote-addr=<位址>。
若只想偶爾讓外部連一下,最單純就是 authtoken 有值、其餘留空,讓 ngrok 指派臨時位址。
公開位址與 Log
啟用 ngrok 時 add-on 會跑第二個服務 ngrok-announce:它每兩秒查一次 ngrok agent 的本地 API(http://127.0.0.1:4040/api/tunnels),最長查找約 120 秒,取得第一個隧道的 public URL 後印進 add-on Log。
所以「看公開網址」的位置是:Home Assistant → 設定 → 附加元件 → Woow EMQX → Log。若啟動後一時找不到,可能它還在等 ngrok 上線,最多約兩分鐘。若超過仍沒有,再去查看 ngrok service 自己的 log(常見原因是 authtoken 沒填好)。
這條公開 URL 很有實際作用:外部裝置的 MQTT client 設定必須用它(含端口),而不是你內網的 Home Assistant 位址。
公開 1883 的風險與替代
公開 raw MQTT 不是無腦把埠推出去。看完以下幾點再決定:
- 任何人都能嘗試連線:ngrok 位址本身就是公開的,等於把 broker 的 1883 入口送到整個網際網路。Authentication 沒設好時,EMQX 會放行匿名 client。
- TLS 需另行處理:ngrok TCP 通道是原始 TCP,不會自動為整條連線加密。若要加密,請改用或另開 MQTTS(8883)式的監聽。
- 臨時位址不持久:不填固定位址時,ngrok 自動指派的端點在每次重啟都可能變號。
- 維持最小暴露:若只是偶爾需要,可只在特定時段開、用完就關;長期對外,務必先完成驗證、ACL 與必要的 TLS。
如果你的需求是 WebSocket 而不是 raw TCP,就接不上:add-on 的 ngrok 只涵蓋 1883(raw MQTT),8083(MQTT over WebSocket)不在 ngrok 範圍,此時請改用 Cloudflare Tunnel。
故障排除
- 已啟用但 Log 沒出現 URL:先確認 ngrok_enabled 是 true、authtoken 有填;再看 Log 是否有「已啟用但 authtoken 為空」的錯誤。若都正確仍沒有,重啟 add-on 或查看 ngrok service 自己的 log。
- 只看到「ngrok 未啟用」:代表設定沒有生效。回到設定分頁檢查 ngrok_enabled,重新啟動後再看 Log。
- 外部 client 連不上:確認是用 ngrok 印出的完整網址與端口,而不是內網位址;並確認已在 EMQX 建立帳號、ACL 允許該主題。位址若常變,就改用固定位址(ngrok_tcp_addr)。
- 發現公網上的任何 client 都能連進 1883:先把 ngrok 關掉,回到 EMQX 設好 Authentication 與 Authorization,再考慮要不要重新公開。匿名可連的公開 broker 是很明顯的警訊。
常見問題
一定要用 ngrok 才能讓外網連 EMQX 嗎
不是。ngrok 只是 add-on 內建最方便的方法;VPN、Cloudflare Tunnel 或其他反向代理一樣能轉到 1883。若你本來就有 VPN 或內網穿透,優先沿用,能減少把 broker 推到公網。
自動位址每次重啟真的都會變嗎
很可能。ngrok 自動指派的臨時 TCP 端點在重開後常會換號,所以希望固定的公開端點時,就到 ngrok 帳號保留並填進 ngrok_tcp_addr,如此重啟後同一個位址可以維持。
8083(MQTT over WebSocket)能用 ngrok 嗎
不行。add-on 的 ngrok 只處理 1883 raw MQTT;要對外提供 WebSocket 就改用 Cloudflare Tunnel,這是官方 CHANGELOG 與 README 指明的替代方向。
公開之前至少要完成哪些設定
至少要能拒絕匿名連線:在 EMQX 的 Access Control → Authentication 建立驗證(建議 Password-Based → Built-in Database),再以 Authorization 設定最小權限。若要加密,則考慮 MQTTS(8883)Listener。