你的 MacBook 上跑著 AI Agent,但家裡那台 iMac 閒置著 48GB 記憶體,風扇安安靜靜地吹著冷風。能不能讓它也加入工作?
這篇文章記錄我怎麼用 Cloudflare Tunnel 加上 Zero Trust Access,把一台 M1 iMac 變成 AI 系統的「分機」。它不只能 SSH 遠端操控,還能獨立接收 LINE Bot 的 Webhook 請求。整個過程免費,因為走的是 Tunnel,所以不需要固定 IP,也不用在路由器上另外開埠。
為什麼要多裝置?
單機跑 AI Agent 遲早會碰到天花板。我的情境是這樣的:
- 算力分散:MacBook 負責主要的 Claude Code 工作流,iMac 跑 Ollama 本地模型和 Hermes 閘道服務,兩邊各司其職
- 服務分離:LINE Bot 的 Webhook 需要一個穩定的公開端點。放在 iMac 上,就不會因為 MacBook 合蓋休眠而斷線
- 冗餘備援:萬一其中一台出狀況,另一台還能撐住基本服務
問題在於,這兩台機器都在家用網路的 NAT 後面。因為卡在 NAT 後面,所以從外面打不進來,從主機也沒辦法隨時連到分機。傳統做法是設定 port forwarding,但那需要固定 IP、要改路由器設定,而且每多開一個服務就要多開一個埠。
Cloudflare Tunnel 解決了這個問題。它從機器內部主動建立一條加密通道到 Cloudflare 的邊緣節點,外部流量因此透過 Cloudflare 的網路進來,完全不需要暴露任何埠。
架構全景
先看整體的樣子。這個架構有兩條通道,各走不同的 hostname:

SSH 通道(mac-node.example.com):
MacBook (主機, primary)
| ssh + cloudflared access proxy
v
Cloudflare Edge
| Zero Trust Access (身份驗證)
v
Cloudflare Tunnel
|
v
iMac :22 (SSH, 僅金鑰認證)
LINE Webhook 通道(line-hook.example.com):
LINE 平台
| POST /line/webhook
v
Cloudflare Edge
| Zero Trust Access (路徑分流)
v
Cloudflare Tunnel
|
v
iMac :8650 (Hermes Gateway, HMAC 驗簽)
兩條通道共用同一條 Tunnel,在 config 裡用不同的 hostname 對應不同的本機服務。所以 SSH 走 22 埠,LINE Webhook 走 8650 埠,各自分流。
Tunnel 建置五步驟
以下是在 iMac(分機端)的操作流程。先安裝 cloudflared 並登入,瀏覽器裡選你的 Cloudflare 帳號與你自己的網域(本文一律用 example.com 示意)。接著建立隧道(本文示意名 mac-node),把兩個 hostname 路由到這條隧道,再把設定寫進 config.yml,最後用 launchd 裝成開機常駐服務。憑證 JSON 會落在 ~/.cloudflared/,那是 Tunnel 的身份證明,請妥善保管。
流程骨架大致是:tunnel create → route dns(兩個 hostname)→ 寫 ingress → service install 並 load launchd。細節參數以官方文件為準,下面只留關鍵設定示意:
# ~/.cloudflared/config.yml(示意)
tunnel: <TUNNEL_ID>
credentials-file: /Users/youruser/.cloudflared/<TUNNEL_ID>.json
ingress:
- hostname: mac-node.example.com
service: ssh://localhost:22
- hostname: line-hook.example.com
service: http://localhost:8650
- service: http_status:404
ingress 最後那行 http_status:404 是必要的 catch-all:沒匹配到的請求都落到這裡。DNS 路由完成後,Cloudflare 會為兩個 hostname 建立指向這條 Tunnel 的 CNAME。服務裝好後,iMac 開機就會自動拉起 Tunnel。
別忘了把主機的 SSH 公鑰加到分機的 ~/.ssh/authorized_keys,並把目錄與檔案權限收緊到只有本機使用者可讀寫。
安全強化三件事
Tunnel 建好之後,你的機器就對全球可達了。這件事很重要,值得再強調一次:Cloudflare Tunnel 讓你的機器不再是 NAT 後面的隱形狀態。所以安全措施不是「建議」,是「必須」。

第一件:關掉 SSH 密碼認證
sudo tee /etc/ssh/sshd_config.d/hardening.conf << 'EOF'
PasswordAuthentication no
ChallengeResponseAuthentication no
KbdInteractiveAuthentication no
EOF
# 改完後重載 sshd(macOS 用 launchctl unload/load ssh.plist)
為什麼家裡的機器也要關?因為暴力破解機器人不管你在哪裡,只要有個公開的 SSH 端點,它們幾分鐘內就會開始嘗試。所以只留金鑰認證,密碼攻擊就直接失效。驗證時可刻意關掉公鑰、只開密碼試連一次,預期應得到 Permission denied (publickey)。
第二件:StrictHostKeyChecking 設為 yes
alias ssh-macnode='ssh \
-o ProxyCommand="cloudflared access ssh --hostname mac-node.example.com" \
-o StrictHostKeyChecking=yes \
-i ~/.ssh/id_ed25519 \
youruser@mac-node.example.com'
很多教學會叫你設 StrictHostKeyChecking=no 來「避免麻煩」,但這等於放棄了中間人攻擊(MITM)的防護。其實只要第一次連線時確認一下主機指紋,之後就不用再煩了。
第三件:Zero Trust Access 路徑分流
這是最有趣的部分。line-hook.example.com 同時要服務兩種角色:LINE 平台打 Webhook 進來,以及我自己偶爾要上去看狀態。因為這兩者的安全需求完全不同,所以要分開處理。

在 Cloudflare Zero Trust 後台建立 Access Application:
| 設定項目 | 值 |
|---|---|
| Hostname | line-hook.example.com |
| Policy 1 | Bypass / Everyone / path: /line/webhook |
| Policy 2 | Allow / 指定使用者(我自己) |
這樣一來,LINE 平台打 /line/webhook 時直接放行(靠 Hermes 閘道的 HMAC 驗簽做第二層驗證),其他路徑則需要 Cloudflare 身份驗證才能存取。
SSH 那邊(mac-node.example.com)也加入 Access Application,用同一組 Allow 政策。第一次連線時 cloudflared access ssh 會開瀏覽器要求登入,驗證 token 會快取一段時間,我這邊實測大約一週,實際長度取決於你 Access 政策裡的 session duration 設定。之後用 ssh-macnode alias 直接連,不用重複驗證。
雙層防護的效果:
攻擊者
-> Cloudflare Access(沒有 token,直接拒絕)
-> SSH 金鑰認證(沒有 ed25519 key,再次拒絕)
要突破必須同時拿到我的 Cloudflare 帳號和我的 SSH 私鑰。因為這兩個東西不在同一個地方,所以被同時攻破的機率極低。
踩坑記錄:Bypass 路徑設錯
建置過程中最令人困擾的一個坑:LINE Bot 的 Webhook 突然收不到訊息了。
症狀:LINE 平台送出的 Webhook 請求被 Cloudflare Access 攔截,回傳 302 導向登入頁面。LINE 平台不會去登入,於是 Webhook 全部失敗。
根因:我把 Bypass 的路徑設成了 /webhook/line,因為 Hermes 設定檔裡的 webhook_path 就是這樣寫的。但實際上 LINE 平台打過來的路徑是 /line/webhook。路徑反了。
解法:在 Zero Trust 後台把 Bypass 路徑改成 /line/webhook。
驗證:
# 應穿過 Access 到達 Hermes(無合法簽章時常見 401)
curl -s -X POST https://line-hook.example.com/line/webhook \
-H "Content-Type: application/json" -d '{"probe": true}'
看到 Webhook 路徑回 401 而不是 302,就代表請求成功穿過了 Cloudflare Access,到達了 Hermes 閘道。根路徑若被 Access 攔截,通常會導向登入(302),可與 Webhook 路徑對照判斷。問題解決。
這個坑的教訓是:設定 Bypass 路徑時,一定要以「外部實際打進來的路徑」為準,不是以內部程式設定的路徑為準,因為兩者可能不一樣。
主機端操作介面
一切就緒之後,在 MacBook 上操作 iMac 就跟操作本機差不多。互動 shell 用 ssh-macnode,單次指令可掛在後面執行;要看 Hermes 是否聽在 8650、或重載 Tunnel 的 launchd 服務,也一樣走這條 alias。日常在 iMac 本機可用 launchctl list 查 cloudflared 是否在跑,並用 log show 看最近幾分鐘的 tunnel 記錄。
ssh-macnode
ssh-macnode "whoami && uname -a"
# 查閘道、重載 Tunnel 服務:同樣透過 alias 遠端執行
未來展望:主從 Agent 對話架構
這條通道現在主要做三件事:遠端執行指令、管理服務、搬移檔案。但它真正的價值在於開啟了一個可能性。
如果 iMac 上也安裝 Claude Code,就能形成真正的主從 Agent 架構:
workspace (Claude Code, primary)
| SSH Tunnel
v
第二台 Mac (Claude Code, secondary)
|
+-- Ollama 本地模型推理
+-- Hermes LINE Bot 閘道
主機上的 Agent 可以透過 SSH 把特定的推理任務派給分機上的本地模型,或者請分機上的 Agent 處理需要長時間運算的工作。因為分機只做被交派的事情,不會主動寫入共享資源,所以能避免衝突。
這就像是辦公室裡的分機系統。總機接電話、分派任務,分機各自處理自己負責的業務。差別在於這些「分機」是 AI Agent,而「電話線」是一條穿越 Cloudflare 全球網路的加密通道。
這條路後來確實走下去了。同一台機器上要讓多個 agent 互通,做法記在 讓 Claude Code 和 Codex 互相打字:tmux-bridge-mcp 實測與安全審查;再往前推到跨機器、可稽核的互相派工,則是 讓 Agent 互相指派任務:機制怎麼設計、實際怎麼用。
安全模型小結
最後整理一下這個架構的安全分層,確保每一層都各司其職:
| 層級 | 防護對象 | 機制 |
|---|---|---|
| 第一層 | 網路存取 | Cloudflare Tunnel(不暴露任何埠) |
| 第二層 | 身份驗證 | Zero Trust Access(Cloudflare 帳號登入) |
| 第三層 | SSH 認證 | ed25519 金鑰(禁用密碼) |
| 第四層 | 應用層驗證 | Hermes HMAC 簽章驗證(LINE Webhook 專用) |
四層防護,每一層各自獨立。因為彼此獨立,所以即使其中一層被繞過,後面的層級仍然在守著。
免費方案就能做到這些。Cloudflare Tunnel 免費,Zero Trust 也有免費方案,席次對個人或小團隊來說完全夠用。確切的席次上限我不寫死在這裡,Cloudflare 這幾年調整過幾次,你要用之前去官方定價頁確認一下最準。
把閒置的硬體變成 AI 基礎設施的一部分,不需要花錢買新伺服器,也不需要搞複雜的 VPN。一條 Tunnel 對應兩個 hostname,再配上四層防護,多裝置 Agent 協作就是從這裡開始的。