使用 Cloudflare Tunnel 建立穩定的 SSH 遠端連線

在實務維運中,SSH 幾乎是所有 Linux 管理工作的基礎。然而,當主機沒有固定 IP、位於 NAT 環境,或基於安全考量不希望對外開放 22 Port 時,Cloudflare Tunnel(cloudflared) 成為一個非常理想的解決方案。

不過,許多人在使用 Cloudflare Tunnel 承載 SSH 時,常會遇到一個問題:

SSH 連線會無預警中斷

本文將從實務角度出發,說明如何透過正確設定,建立一套 可長時間穩定使用的 Cloudflare Tunnel SSH 架構,並同時支援 Host 與內部 Container(Incus / Docker)

目標與適用情境

本文適合以下情境的使用者:

  • 不想對外開放 SSH Port
  • 使用 Cloudflare Zero Trust 管理存取
  • 主機內有多個內部服務或 Container
  • 曾遇過 Cloudflare Tunnel SSH 無預警斷線
  • 希望 SSH 連線可用於長時間維運或管理作業

架構概覽:Host 與 Container 共用 Tunnel

本篇教學採用以下設計原則:

  • 僅 Host 執行 cloudflared
  • Container 不對外暴露
  • SSH 流量全程經 Cloudflare Tunnel
  • SSH 金鑰驗證仍由系統 sshd 控制

架構角色說明

  • Host(DEV-vm)
    • 執行 cloudflared service
    • SSH 服務位於 127.0.0.1:22
  • Container(Incus / HestiaCP)
    • 位於內部網段(如 10.10.10.50
    • 不需安裝 cloudflared
    • SSH 由 Host 轉發

Cloudflare Tunnel ingress 設定範例

以下為 Host 上的 config.yml 範例:

ingress:
  - hostname: dev-vm.example.org
    service: ssh://127.0.0.1:22

  - hostname: dev-hcp.example.org
    service: ssh://10.10.10.50:22

  - service: http_status:404

設計重點說明

  • 使用 loopback (127.0.0.1) 連接 Host 本機 SSH
  • Container 僅能由 Host 轉發存取
  • 最後一條規則防止未匹配流量誤入 Tunnel

為什麼 Cloudflare Tunnel SSH 容易斷線?

Cloudflare Tunnel 本質上是 中介傳輸層,並不保證連線永久存在。當連線長時間沒有任何封包流動時,Cloudflare 可能會將其視為 idle 並回收連線。

這也是許多使用者遇到以下錯誤的原因:

client_loop: send disconnect: Unknown error
Connection closed by remote host

這類錯誤並非 SSH 金鑰或設定錯誤,而是 傳輸通道被中斷

Client 端(Windows)SSH 穩定性設定

為了避免 Cloudflare 判定連線為 idle,Client 端必須主動送出 keepalive 封包

以下為 ~/.ssh/config 建議設定(私鑰名稱已隱藏):

Host devvm-ssh-host
  HostName dev-vm.example.org
  User james
  IdentityFile C:\Users\USERNAME\.ssh\YOUR_PRIVATE_KEY
  ProxyCommand cloudflared access ssh --hostname %h
  GSSAPIAuthentication no
  ForwardAgent yes
  ServerAliveInterval 30
  ServerAliveCountMax 3

Host devvm-ssh-container
  HostName dev-hcp.example.org
  User annie
  IdentityFile C:\Users\USERNAME\.ssh\YOUR_PRIVATE_KEY
  ProxyCommand cloudflared access ssh --hostname %h
  GSSAPIAuthentication no
  ForwardAgent yes
  ServerAliveInterval 30
  ServerAliveCountMax 3

設定重點

  • ServerAliveInterval 30:每 30 秒主動送封包
  • ServerAliveCountMax 3:避免短暫抖動立即斷線
  • 可有效防止 Cloudflare Tunnel idle timeout

Server 端(Host)SSH 補強設定

在 Host 上,同步建議調整 sshd 設定:

ClientAliveInterval 60
ClientAliveCountMax 3
AllowAgentForwarding yes

套用後重新載入 SSH 服務:

sudo systemctl reload ssh

此設定能在 Tunnel 發生短暫 reconnect 時,提高連線存活率。

Container 端的 SSH 安全建議

Container 端建議僅保留必要設定:

PasswordAuthentication no
PubkeyAuthentication yes

Container 不需要知道 Cloudflare Tunnel 的存在,所有安全性仍由 SSH 金鑰機制負責。

常見錯誤觀念釐清

  • ❌ Cloudflare Tunnel 不穩定
  • ❌ SSH 金鑰設定錯誤
  • ❌ Container 架構導致問題

實際上,問題幾乎都來自未設定 keepalive

總結

Cloudflare Tunnel 非常適合用於 SSH 遠端管理,但前提是:

必須主動處理長連線保活問題

只要在 Client 與 Server 端正確設定 keepalive,Cloudflare Tunnel SSH 完全可以用於正式維運環境,並同時兼顧安全性與便利性。

文章分享
James Tsai
James Tsai
文章: 13

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *