本篇文章更新時間:2024/10/03
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知或向一介資男的 LINE 社群反應。
如果本站內容對你有幫助,歡迎贊助支持 。


前幾天在逛 GitHub 的時候看到這份通道服務懶人包 awesome-tunneling,覺得有趣就先筆記在粉絲頁上。

今天花點時間來消化一下這裡面介紹的開源工具,一番把玩後,真的不經讚嘆這真是太有才了! 完全沒想到一個「通道」服務可以玩得這麼多元XD

正如懶人包推薦,大多數人使用 Cloudflare Tunnel 就很完整了(還免費),再不然使用 frp 也夠強。

這類型通道服務基本就是解決內網不公開,所以從一個有對外公開的主機來當跳板,透過內網 client 建立與公開網路的 server 的連線來完成轉曝光請求服務。

先說結論,我最終會選擇 sish 這套。因為 frp 真的太強了,用在這個單一單次需求偏多的類型,算浪費! Cloudflare Tunnel 也很完整,但不是開源服務,功能太強,設定繁瑣。

做出這選擇的條件方向有兩點是:

  1. 易用性 - 要使用的時候對本機環境的需求要最低。因為有機會要對其他人開放服務。
  2. 設定豐富但簡單 - 這邊也關係到文件要清楚,使用情境越多越好,而且至少基本要能滿足傳送 Host Header 標頭的需求。

說到易用性以及對環境需求低,我挑選方向就至少是能編譯出一個跨平台執行檔的 Go 語言專案又或是本機根本不需要一個執行檔就能連線的 SSH 類型,顯然後者 SSH 優先選擇。

再來設定豐富文件也清楚,只能先往星星數多的挑,支援的功能也完整。

最後一個讓 frp 沒入選的原因就是,這樣提供通道服務的應用大多都有支援動態網域連結,又或者說是「拋棄式」的網域連結,但 frp 只能去設定一組一個固定的,使用上也是偏離「易用」。拿來只用在這樣的小服務算是把超大刀了!

這個懶人包作者自己也有推出一個 boringproxy 服務,但他的文件很不完整,一掛上就出問題,只好放棄。

以下分別筆記 frp 與 sish 這兩套的使用方式。

前提情境

我的 Mac 本機有兩種環境,一個是 MAMP 另一個是 DDEV。前者是單純的 Apache/Nginx + PHP + MySQL 架構,後者是完全的 Docker 容器環境。

兩套我都預設是使用本機的 80 阜(Port)號,所以不會同時開,不同專案情境切換使用。

MAMP 由於直接使用本機資源,沒有特別使用 SSL 憑證,所以網址大多是 http://localhost/wp/ 這樣類型,而 DDEV 完整的從網域到憑證,還有 Nginx, MySQL, PHP ...等都透過容器包裝處理過,網址像是 https://ddev-wp.ddev.site/。

會需要一組萬用字元的網域設定和憑證,本文舉例: *.tunnel.mxp.tw,內文後方再補充說明。

一個能對外公開存取的網路與主機,建議直接 VPS 處理,本文舉例: 123.123.123.123

frp 設定的方法

寫文筆記當下的 frp 版本是 v0.53.2,安裝與設定常駐執行的方式,網路上有不少教學,我為了快速測試就是直接從 GitHub 的 releases 下載。

由於這套會需要 Mac 本機 以及 VPS 的 123.123.123.123 都要安裝,所以安裝時要選對 OS 作業系統的版本。

兩台計算機都下載好檔案後,解壓縮都可以看到 frpc, frpc.toml, frps, frps.toml 四個檔案, c 結尾就是 client 內網用,s 結尾就是 server 對外主機用。

client 執行方式: ./frpc -c frpc.toml
server 執行方式: ./frps -c frps.toml

剩下就是設定問題,首先是:

frps.toml 設定組態

bindAddr = "0.0.0.0"
bindPort = 7000
kcpBindPort = 7000
vhostHTTPPort = 7080
vhostHTTPSPort = 7443
subDomainHost = "tunnel.mxp.tw"
webServer.addr = "127.0.0.1"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin"

基本上就是預設,多的部分大概就是開了 webServer 設定,可以看到目前的連線狀況。

frpc.toml 設定組態

serverAddr = "123.123.123.123"
serverPort = 7000
webServer.addr = "127.0.0.1"
webServer.port = 7400

[[proxies]]
name = "plugin_http2https"
type = "http"
subdomain = "local1"
transport.proxyProtocolVersion = "v2"
[proxies.plugin]
type = "http2https"
localAddr = "127.0.0.1:443"
hostHeaderRewrite = "ddev-wp.ddev.site"

[[proxies]]
name = "local"
type = "http"
subdomain = "local2"
localAddr = "127.0.0.1"
localPort = 80
hostHeaderRewrite = "localhost"

要透過 http 去連線一個 https 的 DDEV 專案網址,還要使用到 plugin。

內網的 Mac 也可以設定 webServer ,透過本機開啟 http://127.0.0.1:7400 來查看設定組態與 Hot reload 熱重載方式不用重啟服務載入設定。

針對內網與對外公開的主機設定,可以參考文件:

  1. Client 完整組態設定
  2. Server 完整組態設定

連線測試

上述組態設定好後沒意外就可以連線 http://local1.tunnel.mxp.tw:7080 看到 DDEV 開啟的網站了。

這邊就是純示範本機 HTTPS 的使用案例,基本上 DDEV 的專案因為又被包裝在內網主機內的容器環境裡,如果像是 WordPress 這樣 內容 與 網址 無分離的專案,這邊又是被包裝在內網的內網下,幾乎是不可用XD

再來是 http://local2.tunner.mxp.tw:7080/wp/ 就可以看到 MAMP 開的網站。

踩雷重點

其實研究使用這些通道的過程中,踩了一個大雷,那就是本機 Mac 上的 HTTP Server 會認「Host」這個標頭 header,如果沒有指定這個 Header 標頭,會導致伺服器也不知道你要找誰,所以會出現通道顯示有連上,但內容完全是錯誤的情況。

所以要使用通道服務來給本機想公開的網站要特別注意是不是還有使用到這個 HTTP 協議以及是不是與本機處理的網址有綁定。

至於為什麼說 DDEV 環境架設出來的 WordPress 會「不可用」?

主要是因為本身 DDEV 自己容器的內網已經先把 WordPress 對於接收請求時網域的彈性調整方式給覆寫了,外部請求沒有切入的修改機會,所以就算是對外,操作上內容都還是 DDEV 產生的網址。

關於 WordPress 的相對網址問題可以參考這個外掛 Relative URL

sish 設定的方法

這套安裝也是可以單純透過 GitHub releases,寫文當下是 v2.11.0 版本。

連線使用的情境,本機端操作只需要 Mac 內建的 SSH 就好,所以選擇主機的作業系統版本下載編譯好的程式直接跑就可以!

在 123.123.123.123 這台主機使用下面指令開啟服務:

./sish --ssh-address=:2222  --http-address=:80   --https-address=:443 --domain=tunnel.mxp.tw --https=true --sni-proxy=true --sni-proxy-https=true --verify-ssl=false

可以自行評估主機上有沒有安裝其他服務來決定要不要直接使用 80/443 這兩個 Port,但基本上預設就是使用 22 來連線進去操作,所以請求通道的 Port 我改成 2222。

下載回來的解壓縮資料夾內預設還會有預設組態需求檔案路徑 deploy 資料夾,內容還有三個子資料夾:keys, pubkeys, ssl。

  • keys 是預設會建立的私鑰
  • pubkeys 是存放要授權的 client ,類似 ssh 的 authorized_keys 檔案,存放 public key。作者推薦的 curl https://github.com/帳號名稱.keys > 帳號名稱 加入的做法超讚!
  • ssl 就是放這服務預設要對外公開用的(萬用字元)網域 SSL 憑證。以 網域名稱.crt 與 網域名稱.key 來存放。

內網 Mac 使用 SSH 連線方法

與 frp 不同,這樣類型的請求只需要使用 SSH 指令,帶一些參數過去就可以,如下指令。

將 DDEV 專案開啟通道:

ssh -p 2222 -R 443:127.0.0.1:443 tunnel.mxp.tw host-header=ddev-wp.ddev.site

將 MAMP 專案開啟通道:

ssh -p 2222 -R 80:127.0.0.1:80 tunnel.mxp.tw host-header=localhost

-R 後方的 Port 號是讓主機用什麼方式來請求,算是帶入協議的概念,要自訂一個結果連線網址也沒問題,更多這行指令的操作說明可以參考說明文件。

如果內網的網站有透過一個 HTTP 伺服器處理,那關鍵是後方的 host-header= 參數,能指定帶入 Host 標頭來請求,就能找到對應的網站。

這樣指令執行後,畫面就會產生一組拋棄式的網址給你來觀看。

使用 ACME Shell 工具建立萬用字元 Wildcard 網域憑證

還可以搭配 [SSL] 一次弄懂 Let’s Encrypt 以及建議使用的工具 – DNSroboCert 這篇文服用。

ACME.sh 是一套串接多家服務業者,可以使用 Bash 指令幫你申請憑證的工具。

安裝好這套工具後,使用下方指令請求憑證

acme.sh --issue --dns -d '*.tunnel.mxp.tw' --yes-I-know-dns-manual-mode-enough-go-ahead-please --server letsencrypt --dnssleep 300

大家所知名的「Let's Encrypt」服務在 ACME 2021/08/01 的改版後,不是他的預設請求主機,所以使用指令時如果要使用 Let's Encrypt 的服務,要指定 --server letsencrypt 參數。

要注意,申請萬用字元網域憑證不是走 HTTP API 驗證,而是走 DNS API 驗證。

--dns 是可以指定你的網域服務業者來幫你自動串接上 API 更新 TXT 紀錄來驗證,像是我網域代管在 Cloudflare 上就可以用 dns_cf 來串接。每家業者要帶入的參數都不同,可以參考這份 How to use DNS API 文件。

不帶入 DNS API 參數的話,會手動處理,提示你要去給網域補上一組 TXT 紀錄,此時因為有設定 --dnssleep 300 參數,會等你 300 秒,這時趕快把他提供的紀錄更新上,倒數完後驗證就沒問題了

但如果像我是使用「子」網域來請求萬用字元網域,而不是主網域來進行的話,透過 DNS API 會有一些問題。建議就是不帶參數使用手動驗證。

後記

這個「通道」主題真的是很適合練功。看到懶人包裡列出的專案,不全然都是「差不多」的,也有各種令人驚豔的、看不懂的XD

像是以為 Cloudflare Tunnel 就是一個最終商業用產品服務,沒想到還有人可以用 Cloudflare Worker 建立,再來還有直接把網路全包的 P2P 形式 n2n,把內外網主機乾脆都串在一起(類似的還有洋蔥 Tor 網路)。

切入這主題的玩法很多元,很值得玩味~ (要反向代理?還是通道服務?等,還有人拿下這網域名稱 reverseproxy.com 做內容一些這系列介紹)

還有另一種「通道」是把請求「包裝」然後出口要資料的,算是從主機內部發出請求,經過通道包裝出口來「轉請求」回原主機,可以用來避開各種偵測。 GitHub: GOST 看到這專案的時候一直用內網對外公開的通道思維去想,怎樣都看不透它 Orz

不得不說,對岸因為有那個「GFW」,所以看到這系列專案,中國的開發者很突出,環境造英雄耶,哈

最後筆記一下如果要把 sish 當正式服務發布的話,我會使用的 Docker 作法:

# docker pull antoniomika/sish:latest
docker run -itd --restart=always --name sish \
  -v /etc/letsencrypt/:/etc/letsencrypt \
  -v /root/sish/deploy/ssl:/ssl \
  -v /root/sish/deploy/keys:/keys \
  -v /root/sish/deploy/pubkeys:/pubkeys \
  --net=host antoniomika/sish:latest \
  --ssh-address=:2222 \
  --http-address=:8080 \
  --https-address=:4443 \
  --domain=mxp.tw \
  --https=true \
  --https-certificate-directory=/ssl \
  --authentication-password=mxp \
  --private-keys-directory=/keys \
  --bind-random-ports=false \
  --bind-random-aliases=false \
  --bind-random-aliases-length=10 \
  --bind-random-subdomains=false \
  --tcp-aliases=true \
  --bind-random-subdomains-length=10 \
  --service-console=true \
  --log-to-client=true \
  --verify-ssl=false \
  --idle-connection=true \
  --idle-connection-timeout=5m \
  --redirect-root=true \
  --redirect-root-location=https://www.mxp.tw/blog/

會把本機的 /etc/letsencrypt 路徑掛進去容器裡,主要是因為我憑證是在容器外部管理,如果要讓容器內也可以讀取到 /ssl 目錄中 Symbolic link 的憑證檔案,就要也掛載進去模擬在 Host 的環境。 Ref: Mount host directory with a symbolic link inside in docker container


Share:

作者: Chun

WordPress 社群貢獻者、開源社群推廣者。專注於 WordPress 外掛開發、網站效能最佳化、伺服器管理,以及 iDempiere 開源 ERP 導入與客製開發。曾參與 WordCamp Taipei 等社群活動,GitHub Arctic Code Vault Contributor。提供資訊顧問、WordPress 開發教學、主機最佳化與企業 ERP 整合服務。

發佈留言

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


文章
Filter
Mastodon