最近幫同事建立了一台測試機,我使用 Cloudflare Tunnel 提供客戶測試網址,這樣就不需要處理防火牆的種種瑣事,不但減少了許多管理上的麻煩,透過 Cloudflare 的平臺檔在前面也相對安全許多。這篇文章會記錄一下我在 Ubuntu 22.04.5 LTS 上安裝和配置 Cloudflare Tunnel 的過程。

安裝設定 Cloudflare Tunnel 步驟
-
安裝 Cloudflare Tunnel 命令列工具
wget https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb
sudo dpkg -i cloudflared-linux-amd64.deb
-
登入 Cloudflare 帳號
這邊我假設我的 Ubuntu 登入帳號為 test1
,並且已經在 Cloudflare 上建立了一個帳號(account),如果你還沒有 Cloudflare 帳號,可以到這裡建立一個帳號。
cloudflared tunnel login
接著出現以下的提示,請點擊網址開啟瀏覽器並使用你的 Cloudflare 帳號登入:
Please open the following URL and log in with your Cloudflare account:
https://dash.cloudflare.com/argotunnel?aud=&callback=https%3A%2F%2Flogin.cloudflareaccess.org%2FxxxxGASfxuYgpAxxxxGA3y4Y3QHKATnxxxxxKjQeUE%3D
Leave cloudflared running to download the cert automatically.
登入後會出現 Authorize Cloudflare Tunnel
的網頁,並顯示所有你有權限管理的 Domain Name 清單,請選擇你要使用的網域,然後點擊 Authorize
按鈕。
登入並授權之後,它會建立一把代表你 Cloudflare 帳號下某一個「域名」的憑證檔: /home/test1/.cloudflared/cert.pem
-
建立 Cloudflare Tunnel
tunnel_name="dev-test1"
# 建立通道
cloudflared tunnel create $tunnel_name
# 建立 DNS 記錄
cloudflared tunnel route dns $tunnel_name $tunnel_name-80
cloudflared tunnel route dns $tunnel_name $tunnel_name-443
cloudflared tunnel route dns $tunnel_name $tunnel_name-3000
# 取得通道 ID
tunnel_id=$(cloudflared tunnel info $tunnel_name | grep -oP 'Your tunnel \K([a-z0-9-]+)')
# 建立 cloudflared 設定檔
cat <<EOF > ~/.cloudflared/config.yml
tunnel: $tunnel_name
credentials-file: /home/test1/.cloudflared/$tunnel_id.json
ingress:
- hostname: $tunnel_name-80.miniasp.com
service: http://localhost:80
- hostname: $tunnel_name-443.miniasp.com
service: http://localhost:443
- hostname: $tunnel_name-3000.miniasp.com
service: http://localhost:3000
- service: http_status:404
EOF
上述命令可以直接建立一個通道、三個 DNS 記錄 (CNAME),並且用三個域名對應到本機的三個 Ports
Tunnel credentials written to /home/test1/.cloudflared/a010e7d5-c830-4baa-ac8a-9e67843586c7.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.
Created tunnel dev-test1 with id a010e7d5-c830-4baa-ac8a-9e67843586c7
2025-04-09T06:12:18Z INF Added CNAME dev-test1-80.miniasp.com which will route to this tunnel tunnelID=a010e7d5-c830-4baa-ac8a-9e67843586c7
2025-04-09T06:12:21Z INF Added CNAME dev-test1-443.miniasp.com which will route to this tunnel tunnelID=a010e7d5-c830-4baa-ac8a-9e67843586c7
2025-04-09T06:12:23Z INF Added CNAME dev-test1-3000.miniasp.com which will route to this tunnel tunnelID=a010e7d5-c830-4baa-ac8a-9e67843586c7
-
啟動 Cloudflare Tunnel
由於我是用一般使用者身分執行,若要持續運行 Cloudflare Tunnel,要使用 nohup
指令來執行,這樣就不會因為關閉終端機而中斷連線。
nohup cloudflared tunnel run &
如果你想跑在背景服務,請先 sudo
成 root
身分,然後執行以下命令:
cat << EOF > /etc/systemd/system/cloudflared.service
[Unit]
Description=Cloudflared Tunnel Service
After=network.target
[Service]
ExecStart=/usr/local/bin/cloudflared tunnel run
User=test1
Group=test1
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# 設定服務文件的權限
chmod 644 /etc/systemd/system/cloudflared.service
# 重新載入 systemd 配置
systemctl daemon-reload
# 啟動服務
systemctl start cloudflared
# 啟用服務(開機自動啟動)
systemctl enable cloudflared
# 查看服務狀態
systemctl status cloudflared
-
如果你還沒有網頁可以連線,我會用以下方法快速提供一個網頁供測試之用!
sudo npm i -g rimraf serve
# 建立一個測試用的網頁
cat <<EOF > index.html
<h1>Hi</h1>
EOF
# 建立本機 HTTP 伺服器
serve -l 3000 &> /dev/null &
curl -v http://localhost:30016
# 查看正在運行的 cloudflared
ps -ef | grep cloudflared
# 從 Cloudflare 網路測試連線
curl -v https://dev-test1-3000.miniasp.com/
刪除所有 Cloudflare Tunnel 的步驟
-
列出所有已經建立的 Tunnel 清單
cloudflared tunnel list
假設你的 Tunnel 名稱為 dev-test1
的話,可以用以下命令查看目前是否有任何既有的通道連線:
cloudflared tunnel info dev-test1
只要有顯示資料,就代表目前的 Tunnel 正在運作中,顯示結果大概會長這樣:
test1@myvm:~$ cloudflared tunnel info dev-test1
NAME: dev-test1
ID: a010e7d5-c830-4baa-ac8a-9e67843586c7
CREATED: 2025-04-08 18:52:40.152082 +0000 UTC
CONNECTOR ID CREATED ARCHITECTURE VERSION ORIGIN IP EDGE
788009df-fae0-49d0-b43b-be58a968df29 2025-04-09T01:32:57Z linux_amd64 2025.4.0 xxx.xxx.x.xxx 2xkhh01, 2xtpe01
我寫了一支 Bash Script 來顯示所有 Tunnel 的狀態,這樣就可以很方便的查看目前所有 Tunnel 的狀態:
#!/bin/bash
# 取得所有 tunnel ID 和名稱
tunnels=$(cloudflared tunnel list | tail -n +3 | awk '{print $1 "," $2}')
echo "===== 所有 Cloudflared Tunnel 的連線資訊 ====="
echo ""
# 對每個 tunnel 執行 info 命令
while IFS= read -r tunnel_info; do
tunnel_id=$(echo $tunnel_info | cut -d',' -f1)
tunnel_name=$(echo $tunnel_info | cut -d',' -f2)
echo "===== 通道名稱: $tunnel_name (ID: $tunnel_id) ====="
cloudflared tunnel info $tunnel_name
echo ""
echo "------------------------------------------------"
echo ""
done <<< "$tunnels"
-
刪除 Tunnel
假設你的 Tunnel 名稱為 dev-test1
的話,可以用以下命令刪除:
cloudflared tunnel cleanup dev-test1
cloudflared tunnel delete dev-test1
-
刪除之前建立的路由(域名)
目前 cloudflared 並沒有支援透過 CLI 刪除路由 (DNS),建議自己連到 https://dash.cloudflare.com/ 並手動刪除所有之前自動建立的 CNAME 記錄。
不過,我在 Cloudflare 的 DNS 管理很多子域名,要找出哪些 CNAME 是 Cloudflare Tunnel 自動建立的,可以透過以下方式檢查。
第一種方法,是直接在 Cloudflare 的 DNS 管理頁面中,拿 .cfargotunnel.com
這個關鍵字去搜尋,可以找出過往曾經透過 Cloudflare Tunnel 建立的 CNAME 記錄。
第二種方法,則是用 cloudflared tunnel list
找出 Tunnel 的 ID,再拿 ID 去搜尋也可以找到。
關於 Cloudflare Tunnel 的觀念整理
-
瞭解「域名憑證」的位置
每次透過 cloudflared tunnel login
登入會取得「域名憑證」,預設檔案會置於 ~/.cloudflared/cert.pem
。
如果在執行 cloudflared tunnel list
命令時,要指定「域名帳戶」來列出所有已建立的 Tunnel 可以執行以下命令:
cloudflare tunnel --origincert '~/.cloudflared/cert.pem' list
將憑證檔更名後,就可以再登入一次,以取得另一個「域名」的憑證,這樣就可以用多個域名在同一台主機操作:
cloudflare tunnel --origincert '~/.cloudflared/cert-domain1.pem' list
cloudflare tunnel --origincert '~/.cloudflared/cert-domain2.pem' list
-
瞭解「通道」的概念
建立通道時,會產生一個 GUID 格式的 ID
,這個 ID 會用來識別這個通道,並且會產生一個以 Tunnel ID
為名的 JSON 檔案,這是代表一個通道的密鑰。預設檔名與路徑如下:
~/.cloudflared/{ID}.json
一個 Cloudflare 域名 (domain) 有多個通道 (tunnel),每個通道可以有最多 100
個連線(connection)。
Tunnel availability and failover
Cloudflare Tunnel 可已建立多個副本 (cloudflared replicas),主要用來作為可用性和故障轉移等情境,不是用來作為負載平衡之用。如有負載平衡需求,需改用 Cloudflare Load Balancers。
-
關於 Cloudflare Tunnel 的設定檔
Cloudflare Tunnel 的設定檔預設路徑為 ~/.cloudflared/config.yml
,這個檔案在建立 Tunnel 時不會自動產生。
如果沒有這個設定檔,就無法直接用 cloudflared tunnel run
啟動通道執行,必須指定通道名稱或通道 ID。
cloudflared tunnel run {tunnel_name}
如果手動建立該檔案,可以定義 tunnel:
為預設 Tunnel ID,例如:
tunnel: {tunnel_id}
這樣就可以直接建立連線:
cloudflared tunnel run
不過,建立了通道,依然外面是無法連線的,因為你並沒有設定路由 (route) (ingress rules)。
通道通常需要一個路由 (route) 來讓網路建立連線,而每個路由通常會綁定一個域名 (dns)。
cloudflared tunnel route dns {tunnel_name} {hostname}
這裡的 {hostname}
指的是你的子域名名稱,如果你授權登入的域名是 miniasp.com
的話,這裡 hostname
設定為 test-1
,那麼你就可以透過 test-1.miniasp.com
來連線。
直接透過命令列工具建立連線的方式是:
cloudflared tunnel run --url http://localhost:3000
建立好通道連線後,就可以用 {hostname}.miniasp.com
來連到本機的 http://localhost:3000
位址。
如果想要連接多個本地網路服務,可以在 ~/.cloudflared/config.yml
設定檔中,加入多個 ingress
規則,這樣就可以透過不同的子域名來連接不同的本地網路服務。
tunnel: {tunnel_id}
ingress:
- hostname: test-1.miniasp.com
service: http://localhost:80
- hostname: test-2.miniasp.com
service: http://localhost:443
- hostname: test-3.miniasp.com
service: http://localhost:3000
- service: http_status:404
這樣就可以直接用以下命令使用預設的通道建立連線:
cloudflared tunnel run
這幾個域名記得都要先透過 cloudflared tunnel route dns {tunnel_name} {hostname}
註冊域名,否則一樣連不上
-
我覺得 cloudflared
有幾個設計不良的地方
首先,執行 cloudflared tunnel run
時所呈現的 Log 完全看不出路由資訊,對於不熟悉 Cloudflare Tunnel 的人來說,會不知道應該給別人什麼網址連線!然後,目前的 cloudflared
也完全沒有方法可以取得之前建立的路由資訊,真的要「回憶」起你當初到底建立哪一個,必須要透過以下步驟查看。
-
透過 cloudflared tunnel list
取得 Tunnel ID (你總該先知道正在用哪個 Tunnel 吧)
-
然後用瀏覽器登入 Cloudflare 帳號,進入到 DNS
頁面,然後搜尋 Tunnel ID
才能找到之前替這個 Tunnel 建立的 CNAME 記錄,這才是你可以連上這個 Tunnel 的域名。
再者,另一個不方便的地方,就是你完全找不到你正準備連線的 Tunnel 到底是綁定哪個域名。
我們需透過 cloudflared tunnel login
登入會取得「域名憑證」,這個憑證其實是綁定一個「域名」的,預設檔案會置於 ~/.cloudflared/cert.pem
。但是,該檔案看不出到底當初授權的是哪個域名,這真的很討厭啊,我域名很多,換來換去的,我自己都會忘記當初到底是建立哪一個域名的憑證。
解決方法,就是不要用「預設憑證」路徑,登入後就改名,這樣可能比較不會忘記。
例如: ~/.cloudflared/cert.pem
產生後,就立刻複製一份,叫做 ~/.cloudflared/cert-miniasp.com.pem
,這樣下次看檔名就知道是什麼域名了!
使用心得
我覺得雖然 Cloudflare Tunnel 很強大,功能也非常多,但是使用體驗真的不太好,心理負擔太多,特別是在設定和管理上,讓人感到困惑。
我目前為止,還是覺得 ngrok 最為簡單易用,使用上完全無負擔,一個命令就可以開通連線!
ngrok http 3000
或是
ngrok http http://localhost:8080
雖然 ngrok 的免費版有一些限制,但是它的使用體驗真的比 Cloudflare Tunnel 好太多了。
相關連結