前幾個月買了 Racknerd,上面掛了很多 n8n 等等的服務。最近用的時候發現一些奇怪的問題:我電腦打 API 都正常,但 n8n 就會一直報錯。研究一下發現有些 API 不同地區回的資料居然不一樣?(在某些狀況這正常,但對於一個資料庫屬性的 API 好像就哪裡怪怪的。)而我也有買很久的 Surfshark VPN,就想拿來頂一下。
TLDR
就結論而言,我放棄使用 Surfshark,最後改用 Webshare 的 2.99 美金 100 IP 方案。Webshare 也有提供 IP Rotating 的功能,所以也省去自己管理的麻煩。
這篇文主要將會說一下怎麼用以及被鎖的過程(好消息,客服後來幫我解鎖,但我不敢再試了)。
目標
因為我是在機器上開 Docker,然後上面塞各種服務(參考這篇[在 Raspberry Pi 亂塞東西的文章]),所以我主要想做到的是開一台 Proxy,需要時再通過他。我不需要所有連線都經過,這就讓我不能直接在機器上設定 Proxy。
而既然都開 Proxy,我就也想做 IP 輪換(這可能不是好主意,後面被封的原因說明),所以也研究了怎樣把他變成連接池。
Gluetun
亂搞了一陣子之後才發現 Gluetun 這個 Docker Image。
他可以很輕易的把各種 VPN 訂閱變成一台 Proxy 伺服器,Surfshark 也包含在內,而且方法非常簡單。
使用 Portainer,只需要設定一個 Volume 到 /gluetun(甚至我不確定有沒有必要,我感覺他全部靠環境變數就可以動了)、配好環境變數、給 Device 和 NET_ADMIN 權限就好。如果和我一樣是有其他服務,可能要特別留意 Network 的設定,要在同一個網路才有辦法被其他容器使用。

環境變數部分,Surfshark 的話長這樣:
1 | HTTPPROXY=on |
其中 OPENVPN_USER 和 OPENVPN_PASSWORD 使用 Surfshark 手動設置頁面提供的資訊。

HTTPPROXY 記得要加,沒加用不了,如果要對外記得做好認證設定。
如果需要設定國家,可以使用 SERVER_COUNTRIES,並透過 docker run --rm -v /yourpath:/gluetun qmcgaw/gluetun format-servers -yourprovider 查看支援的國家名稱。
完成後啟動,就可以得到一個 Proxy 服務了,需要使用時,從其他容器透過 http://<container>:8888 發出請求就可以了。
連接池
因為只有一個 VPN 偶爾還是會遇到問題,所以就也研究了如何開多個,並且隨機拿其中一個連。直覺想法是開多個 Gluetun 容器就好,但原本想到的問題是:我怎麼知道要連到哪台。
後來在研究設定時,AI 提到 Docker 有 DNS Round Robin 功能,所以只要把多個容器的 Hostname 設成同一個,然後使用 Hostname 訪問就會自然解決這個問題。
酷,學到了。
Docker Compose
但手動的話實在很麻煩,所以我們可以請出 Docker Compose 來幫忙。這個 Docker Compose 是我剪貼簿的內容,我不太確定完不完整(目測正常)。
1 | services: |
其中 services.vpn.hostname 是重點,不管 Gemini 還是 Claude 都跟我說是 Networks 那邊要用
1 | networks: |
來達到同一個 Hostname 的效果,一直不成功跑去看文件才發現有 hostname 這個欄位。
這樣就可以透過 services.vpn.deploy.replicas 來控制要幾台機器了,而需要使用時,http://vpn:8888 就會隨機(好啦 Round Robin 不隨機,但總之就是那個概念)選擇一個 VPN 出去。
換 IP
而我也希望能夠偶爾換新 IP,所以研究了一下怎麼換,但結果而言我覺得換 IP 這件事可能會提高被判斷成濫用的機會,所以僅供參考。
換 IP 的流程我是用 n8n 搭建,可以比較簡單的做到定時和按需觸發。
方法一:Gluetun 的 API
Gluetun 有提供管理 API(透過 :8000),在環境變數加入 HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE 就可以透過 HTTP 來控制。
HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE 有兩種模式,可以參考官方 Wiki 了解。我選擇用 API Key,所以我設定 HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE='{"auth":"apikey","apikey":"..."}'。
(實際上我從 n8n 發送,全部都在私人網路中的話應該是不用驗證,直接 HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE='{"auth":"none"}' 就好。)
然後透過 PUT http://<vpn-ip>:8000/v1/vpn/status 發送兩次請求
1 | { "status": "stopped" } |
和
1 | { "status": "running" } |
就可以重連,但我發現偶爾會失敗,所以這個方式可能要加上檢查有沒有拿到 IP(GET /v1/publicip/ip),如果沒有要重新跑一次。
方法二:Docker HTTP API
因為會失敗,我想到另外一個方法就是重新啟動容器,這樣他也會自然取得新的 IP。
而 Portainer 也有提供 Docker HTTP API 的 Proxy,所以只需要建立 Access Token 就可以透過
1 | GET https://<portainer>:9443/api/endpoints/<endpoint>/docker/containers/json?filters={"name":["^vpn"]} |
來找到所有以 vpn 開頭的容器。取得其中的容器 ID 後透過
1 | POST https://portainer:9443/api/endpoints/<endpoint>/docker/containers/<container>/restart |
來重新啟動。這個方式我覺得簡單很多。
這兩個方式都會讓 Proxy 短暫停止服務,因為 DNS Round Robin 策略不會檢查有沒有辦法用,所以也要搭配重試機制來避免 Proxy 暫時下線的狀況。
悲劇
正當我終於解決問題時,我發現我的 VPN 容器冒出很多 unhealty。在剛設定時其實也常常發生,所以我原本猜是 Surfshark 的登入有 Rate limit,但之前都會慢慢全亮,這次卻一直滿不了。
我看了一下,錯誤說 Credential 錯誤,我記得一開始我一次開五台也會,等一下就好了。
但此時,我電腦的 Surfshark 被登出了!
然後我就看到我的 Email 躺著一封:《違反 ToS 帳號封鎖,無退款》的信。
雖然我真心不覺得我有到濫用(雖然我登入很多個,但我根本就還沒有流量出去),但也沒辦法,只好去問客服說:「我剛剛在用 VPS,可能搞錯一些設定,可以幫我解鎖嗎?」
Surfshark 客服人很好,讓我去用重設密碼把所有帳號登出,然後就恢復了。
仔細想想,Replica 本來就會開啟多個登入,輪換 IP(雖然我是設定 10 分鐘換 1 台)也會產生登入紀錄,又加上我一直找問題開開關關,可能一小時就有一兩百個登入,也難怪 Surfshark 會判斷濫用。
結尾
這次搞這些東西學到了一些東西,主要是 Docker 的一些細節功能。Portainer 的 API 文件沒有列,但有小小提到他有代理 Docker HTTP,這未來可能還有許多玩法。
像是我沒想過 Docker 本身就可以 DNS Round Robin,我原本還在想要弄 Nginx 之類的來,但還好在我把麻煩擴大之前 AI 提到這件事,省下許多時間。
但省下的時間也被 AI 用掉,我實在不知道為什麼兩個 AI 都沒有提到 services.<app>.hostname 這個。還是我邊看 Portainer 的設定介面邊看 Docker 文件才找到。
不過,弄這麼久,最後被封讓我覺得還是不要這樣瞎搞比較好。所以我最後還是買了 Webshare 的方案,一個月 2.99 美金更簡單的處理掉這些雜事,還有 100 個 IP 可以用,讚 👍。