Tuwunel¶
Tuwunel 係一個部署喺 oracle-cloud 上嘅自託管服務;佢以 docker 容器執行,鏡像來自 GitHub Container Registry 上嘅 ghcr.io/matrix-construct/tuwunel:main。喺 benhoweb.com 嘅架構入面,Tuwunel 用嚟提供 Matrix Construct 生態相關服務,並以獨立 container 方式長駐,唔直接依賴宿主机上面手動執行嘅 process。
呢條目以實際部署環境為基礎,記錄 Tuwunel 嘅網絡位置、組態方式、更新同維運操作。
Overview¶
Tuwunel 嘅部署重點如下:
- 服務使用官方鏡像
ghcr.io/matrix-construct/tuwunel:main; - container 名稱固定為
tuwunel; - 設定檔以
tuwunel.toml形式掛入容器; - 資料一律保存喺命名 volume
tuwunel-data; - 服務連接外部 Docker network
cf_network,固定使用172.21.0.86; - 唔直接映射 public port,流量主要由 edge/tunnel 層轉發;
- 記憶體上限設定為
1g,防止 runaway process 食爆 Oracle Cloud VM; - 鏡像採用 distroless 設計,容器內冇 shell、curl、wget,因此唔可以依賴 container-level healthcheck。
Oracle Cloud 嘅部署唔只係「開咗部 VM 然後行 container」,更加需要有明確嘅 Docker network、volume、以及外部注入 secret 嘅方法。Tuwunel 嘅組態正正反映咗呢一套做法。
Architecture¶
Tuwunel 喺 VM 上同其他自託管服務共享一個名為 cf_network 嘅 external Docker bridge network。佢冇 ports: 設定,所以外界唔能夠直接經 host IP 去撞個 container;實際流量會由 edge 服務處理。
簡化架構如下:
Internet
│
▼
Cloudflare Edge
│ Cloudflare Tunnel(outbound-only)
▼
cf_network bridge(172.21.0.0/24)
├── cloudflared / reverse-proxy container
└── tuwunel(172.21.0.86)
└── tuwunel-data(persistent volume)
Tuwunel 之所以要墮入 cf_network,係為咗可以同 Cloudflare Tunnel 或其他代理容器以固定 IP 溝通。ipv4_address: 172.21.0.86 確保每次 recreate 之後,Tuwunel 都攞到同一個地址,唔會因為 DHCP 改變而令 proxy 設定失效。
呢種架構亦符合「自託管但唔自行公開 port」嘅安全原則:Tuwunel 本身唔需要暴露喺公網,只有 edge 先至需要對外。
Deployment¶
Tuwunel 嘅部署假設 Docker 同 Docker Compose plugin 已經裝好。以下係喺 Oracle Cloud VM 上使用嘅 compose 設定:
services:
tuwunel:
image: ghcr.io/matrix-construct/tuwunel:main
container_name: tuwunel
restart: unless-stopped
mem_limit: 1g
networks:
cf_network:
ipv4_address: 172.21.0.86
environment:
- TZ=Asia/Hong_Kong
- TUWUNEL_CONFIG=/etc/tuwunel.toml
# 註冊 token 由 Dockhand env 注入(env override TOML;唔寫死喺 repo)
- TUWUNEL_REGISTRATION_TOKEN=${MATRIX_REGISTRATION_TOKEN}
volumes:
- ./tuwunel.toml:/etc/tuwunel.toml:ro
- tuwunel-data:/var/lib/tuwunel
# distroless 鏡像冇 shell/curl/wget,容器內 healthcheck 不可行;E2E 用外部 curl 驗證
healthcheck:
test: ["NONE"]
networks:
cf_network:
external: true
volumes:
tuwunel-data:
部署步驟:
- 確認
cf_network已經存在:
docker network inspect cf_network
如果未存在,可以建立一個 subnet 相容嘅 bridge network:
docker network create cf_network \
--driver bridge \
--subnet 172.21.0.0/24
-
準備
tuwunel.toml,放喺 compose 檔案同一個目錄。佢會以 read-only 方式掛入/etc/tuwunel.toml。 -
設定
MATRIX_REGISTRATION_TOKEN。喺 CI/CD 入面可以交由 dockhand 注入,避免將 secret 寫入 repo。 -
執行:
docker compose up -d tuwunel
Configuration¶
Tuwunel 主要使用兩個層面嘅設定:TOML 設定檔同環境變數。
TUWUNEL_CONFIG 指住 /etc/tuwunel.toml,即係話 Tuwunel 啟動時會讀取呢個檔案。因為 mount 咗 :ro,container 入面冇得改設定檔,改設定一定要經返宿主機。
環境變數方面,最重要係 TUWUNEL_REGISTRATION_TOKEN。呢個 token 用於 Matrix 註冊流程,佢由 MATRIX_REGISTRATION_TOKEN 傳入。呢個設計代表 secret 由環境注入,唔會寫死喺 tuwunel.toml 或者 git repo。使用者需要理解:container 環境變數嘅優先序高過 TOML 入面同名設定,所以即使 tuwunel.toml 有相關欄位,實際執行時都會由環境變數覆蓋。
TZ=Asia/Hong_Kong 確保 log 同內部時間處理使用香港時區。
資料目錄 /var/lib/tuwunel 對應 tuwunel-data volume。任何要保留嘅狀態都應該寫入呢度,而唔好寫入 container root filesystem。
Operations¶
Tuwunel 日常維運主要喺 Oracle Cloud VM 上面執行。
檢查服務狀態:
docker compose ps
睇 log:
docker compose logs -f --tail=200 tuwunel
手動重啟:
docker compose restart tuwunel
更新鏡像:
docker compose pull tuwunel
docker compose up -d tuwunel
docker image prune -f
注意 main tag 係一個移動 target,更新前最好確認上游鏡像 digest,避免無預警升級。
由於鏡像係 distroless,唔可以依賴 docker compose exec tuwunel sh。容器內冇 shell;如果想要檢查 process,可以用:
docker stats tuwunel
docker inspect tuwunel
Healthcheck 方面,compose 入面寫咗 test: ["NONE"],即係停用 Docker healthcheck。實際監控應由外部節點以 curl 或者其他 HTTP client 打入 Tuwunel 嘅 edge endpoint,驗證成個路徑通唔通。
備份方面,需要同時備份設定檔同 volume:
tar czf tuwunel-config-backup.tgz tuwunel.toml
docker run --rm \
-v tuwunel-data:/data \
-v "$PWD":/backup \
alpine:3.18 \
tar czf /backup/tuwunel-data-backup.tgz -C /data .
Oracle Cloud 嘅 VCN security list 唔需要開放 Tuwunel 嘅 port,因為流量係經 Cloudflare Tunnel outbound 進入。若然直接開放 host port,反而會擴闊攻擊面。
FAQ¶
點解唔用 container healthcheck?
ghcr.io/matrix-construct/tuwunel:main 係 distroless 鏡像,入面冇 /bin/sh、curl、wget,Docker healthcheck 好難正常執行。與其整一個假 healthcheck,不如直接停用,改為由外部做 E2E curl 檢查。
點解要指定 static IP 172.21.0.86?
Tuwunel 同其他服務共用 cf_network。如果每次 recreate 都攞唔同 IP,proxy 或者 tunnel 設定就會失效。static IP 令服務位置確定,並可以喺唔同 container 之間以內部網域名稱或 IP 溝通。
點解 token 要用環境變數而唔寫入 TOML?
因為 tuwunel.toml 好可能被版控,或者由共享設定檔產生。Token 屬於 secret,唔應該入 repo。環境變數可以結合 dockhand、CI/CD secret manager 或者部署工具注入,重可以令同一份 TOML 喺唔同環境重用。
點解冇 ports 對外?
Tuwunel 只需要喺 cf_network 入面俾 edge/proxy 連接。直接公開 port 會令服務暴露喺公網,增加被掃描同攻擊嘅風險。Oracle Cloud 上應該保留呢個架構,唔好隨意加 ports:。
點解要 mem_limit: 1g?
呢個係保障機制。Oracle Cloud VM 如果同其他 self-hosted 服務共用,單一容器冇限制嘅話,記憶體壓力可能令成部 VM OOM。1g 限制可以令 Tuwunel 唔會拖冧隔離嘅 litellm 或者其他服務。
點解容器內冇得 exec?
Distroless 鏡像只包含應用程式同必要 runtime,唔包含 shell、package manager 同其他工具。呢個係刻意設計,用意係減少攻擊面同 image size。若果需要深入排查,應該靠 log、docker inspect 同外部 network probe。
Related Links¶
- docker
- oracle-cloud
- cloudflare-tunnel
- Matrix
- litellm
- dockhand
- TOML
- git
- proxy
Source¶
Coverage auto (container scan)