Appearance
之前寫了一篇 使用遠端 Windows 主機編譯 Docker Image - Cloudflare Tunnel 代理 SSH 實現篇 介紹如何把我平常遊戲用、效能過剩的 Windows 主機拿來編譯 Docker Image,作為 Mac 開發機的輔助,這次同樣地要再次壓榨它來當作我的 Ollama 語言模型伺服器。
Windows 主機設定
安裝 Ubuntu
執行 Powershell 運行指令 wsl --install -d ubuntu
安裝 Ubuntu Linux。
接下來所有的指令都是在 Ubuntu 環境下執行,使用 wsl -d ubuntu
進入 Ubuntu 環境。
安裝 Ollama
sh
# 安裝 Ollama
curl -fsSL https://ollama.com/install.sh | sh
# 下載語言模型 llama3
ollama pull llama3
此時 ollama 的 server 已在背景默默運行,為了能讓外部(Mac 主機)藉由某個網域連線到 ollama server,我們需要為 ollama service 進行設定,使用 sudo vim /etc/systemd/system/ollama.service
指令以編輯設定檔案:
plain
[Service]
Environment="OLLAMA_ORIGINS=http://subdomain.yourdomain.com"
Environment="OLLAMA_HOST=0.0.0.0"
在 [Service]
底下設定兩個環境變數:
OLLAMA_ORIGINS
ollama server 預設只允許本地調用,加入此設定才能之後出現 403 錯誤,請使用你確切擁有的網域, 通訊協定填http://
不用加s
。 目前只建立好單向設定,之後還會在 Cloudfalre 完成雙向設定。OLLAMA_HOST
設定成0.0.0.0
。
OLLAMA_ORIGINS
通訊協定為必填不可省略,網路上關於此設定的討論很多都只有寫 hostname,會引發 panic: bad origin: origins must contain '*' or include http://,https://,chrome-extension://,safari-extension://,moz-extension://,ms-browser-extension://
錯誤。
完成設定後,重新啟動 ollama service:
sh
sudo systemctl daemon-reload
sudo systemctl restart ollama.service
使用 curl
測試 ollama 是否能正確回應請求:
sh
# 看到 「Ollama is running」 表示成功
curl -i http://127.0.0.1:11434
# 如果此行失敗,表示 OLLAMA_ORIGINS 設定有誤
curl -i http://127.0.0.1:11434 -H "host: subdomain.yourdomain.com"
安裝 cloudflared CLI
sh
# 安裝 cloudflared
wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared-linux-amd64.deb
# 登入 Cloudflare 帳號
cloudflared tunnel login
前往 Cloudflare 後台介面,新增一個 Tunnel:
建立完成複製帶有 Token 的指令並執行:
於 Public Hostname
的分頁設定中新增一個 public hostname,subdomain
及 domain
必須與先前 OLLAMA_ORIGINS
的設定相同, Type
選擇 HTTP
,URL
填入 http://localhost:11434
:
最後確認 Tunnel 狀態為 Healthy
,如果不為 Healthy 可能是 sudo cloudflared service install <token>
的指令沒有運行成功:
到目前為止已經完成 ollama server 的安裝、語言模型的下載、cloudflare tunnel 從外往穿透到 Windows WSL Ubuntu 直到 ollama server 的設定。
驗證從外網調用 Ollama server
假設前面的所用到的網域設定為 subdomain.yourdomain.com
,使用 curl
來測試是否能從外部網路調用 ollama server(從哪台電腦測試都可以):
sh
curl -i https://subdomain.yourdomain.com # 應得到 Ollama is running 的回應
# 實際調用 ollama API,應得到語言模型的回應
curl -i https://subdomain.yourdomain.com/api/generate -d '{ "model": "llama3", "prompt": "Give me 100 sentences" }
防止 Ollama server 未經授權訪問
Cloudfalre Tunnel 要做權限控管一種方法是透過同樣在 Zero Trust 底下的 Access, 但我嘗試後覺得相當麻煩,需要先建立 Application,設定各種規則後再到 Tunnel 底下的 Public Hostname 產生與 Access 的關聯。 撇除這些麻煩的問題不說,Identity providers
似乎是必要開啟的。
也就是説如果要用 Access 來保護 Tunnel 服務, 使用者必須要經過 Identity providers 的認證,要麻是 One-time PIN(寄一封 pin 碼到你輸入的信箱) 或是其他 OAuth 認證,Cloudflare 都要先取得使用者的 Email 才能通過第一道關卡,如果情境是「讓使用者造訪的網頁」倒不是什麼問題,但 Ollama server 是要被當作 API server 調用的情境行不通。
一開始被困在 Zero Trust 的介面找不到解法,才想到其實可已跳脫出去用 Cloudflare WAF 來做權限控管,因為 Tunnel 服務所用的 domain 是經過 Cloudflare Proxy。
設定如下:
Hostname
equalssubdomain.yourdomain.com
IP Source Addresses
is not inYour IP addresses
- 行為設定成
Block
設定的結果為「當網域是 Ollama server 但訪問 IP 不是你所設定的條件時,就無法訪問」。
使用 Cloudflare WARP 來保護 Ollama server
在做本篇的研究時,因為頻繁接觸到 Cloudflare Zero Trust 介面下的玩意後,直覺告訴我平常只被我拿來當改善網路 VPN 的 Cloudflare WARP 真正強大的地方應該是跟 Zero Trust 底下的功能結合。
我假設一種可能「Ollama server 對外完不公開,只有當 Cloudflare WARP 在我的開發機上啟用的時候,能夠以內網的形式取用服務」,結果確實可以!
細説流程會超出本篇主題太多,所以僅說明大致的步驟,有興趣的讀者可以自行研究:
- 首次進入 Cloudflare Zero Trust 網頁介面時,會要求建立一個 Team domain
xxx.cloudflareaccess.com
,其中xxx
是你取的名稱。 - 在網頁介面
Settings -> WRAP Client -> Device enrollment permissions
新增一個 Policy 允許指定的 Email。 - 前往 1.1.1.1 下載 Cloudflare WARP,
Preferences -> Account -> Login to Cloudflare Zero Trust
,會要求你輸入 Team Name,輸入步驟 1 的xxx
, 然後使用步驟 2 的 Email 登入,登入成功後會從原本的 WARP 變成帥氣的 Zero Trust。 - 我的 WSL Ubuntu 內網 IP 為
172.27.21.6
, 因此在先前所建立的 Tunnel 底下新增一個 Private Network,我將 CIDR 設定為172.27.0.0/16
, 表示 WARP 啟用期間遇到此範圍的 IP 都轉發到內網。 - WARP 預設有一條 IP 規則
172.16.0.0/12
表示與此範圍相符的 IP 不會經過 WARP,這個範圍與上一步的範圍重疊, 因此需要將此規則刪除,這個設定藏在Settings -> WARP Client -> Device settings -> Profile(configure) -> Split Tunnels -> Manage
以上步驟先後完成了:使用 Cloudflare WARP 登入自己的組織、將 Tunnel 的內網開放、刪除與內網 IP 衝突的 Split Tunnel 規則。 此時在我的 Mac 開發機 WARP 啟用下,瀏覽 WSL 的內網 IP 網址 http://172.27.21.6:11434/
成功看到了 Ollama server 的回應 Ollama is running
。
這個方法仍有個缺點,必須以內網 IP 訪問,理想狀況當然是連上 WARP 後能夠以 hostname 方式訪問到服務,例如 http://ollama.local
,據 Adding private hostname in Cloudflared Tunnel --> Private Network issue 的討論,看起來目前還不支援類似的功能。
雖然本篇是以 Ollama 作為主角,但其實可替換成其他各種伺服器應用,起初只是想找個方法搭建私有 Ollama server,結果意外對 Cloudflare Zero Trust 有了更深入的了解,再次讚嘆 Cloudflare 的強大,但也不得不嘴一下 Cloudflare 很多設定都藏在讓人無法理解的地方,如果沒有找到,會讓人以為根本沒有那些功能。