Skip to content

使用 WSL 運行 Ollama server,並透過 Cloudflare Tunnel 對外公開

之前寫了一篇 使用遠端 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:

Cloudflare Tunnel 建立畫面

建立完成複製帶有 Token 的指令並執行:

Cloudflare Tunnel 建立完成

於 Public Hostname 的分頁設定中新增一個 public hostname,subdomain 及 domain 必須與先前 OLLAMA_ORIGINS 的設定相同, Type 選擇 HTTP,URL 填入 http://localhost:11434:

Cloudflare Tunnel 建立 ollama public hostname

最後確認 Tunnel 狀態為 Healthy,如果不為 Healthy 可能是 sudo cloudflared service install <token> 的指令沒有運行成功:

Cloudflare Tunnel 狀態為 healthy

到目前為止已經完成 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。

設定如下:

Cloudflare WAF 控管 Cloudflare Tunnel 的應用
  • Hostname equals subdomain.yourdomain.com
  • IP Source Addresses is not in Your IP addresses
  • 行為設定成 Block

設定的結果為「當網域是 Ollama server 但訪問 IP 不是你所設定的條件時,就無法訪問」。

使用 Cloudflare WARP 來保護 Ollama server ​

在做本篇的研究時,因為頻繁接觸到 Cloudflare Zero Trust 介面下的玩意後,直覺告訴我平常只被我拿來當改善網路 VPN 的 Cloudflare WARP 真正強大的地方應該是跟 Zero Trust 底下的功能結合。

我假設一種可能「Ollama server 對外完不公開,只有當 Cloudflare WARP 在我的開發機上啟用的時候,能夠以內網的形式取用服務」,結果確實可以!

細説流程會超出本篇主題太多,所以僅說明大致的步驟,有興趣的讀者可以自行研究:

  1. 首次進入 Cloudflare Zero Trust 網頁介面時,會要求建立一個 Team domain xxx.cloudflareaccess.com,其中 xxx 是你取的名稱。
  2. 在網頁介面 Settings -> WRAP Client -> Device enrollment permissions 新增一個 Policy 允許指定的 Email。
  3. 前往 1.1.1.1 下載 Cloudflare WARP, Preferences -> Account -> Login to Cloudflare Zero Trust,會要求你輸入 Team Name,輸入步驟 1 的 xxx, 然後使用步驟 2 的 Email 登入,登入成功後會從原本的 WARP 變成帥氣的 Zero Trust。
    Cloudflare WARP 變成 Zero Trust
  4. 我的 WSL Ubuntu 內網 IP 為 172.27.21.6, 因此在先前所建立的 Tunnel 底下新增一個 Private Network,我將 CIDR 設定為 172.27.0.0/16, 表示 WARP 啟用期間遇到此範圍的 IP 都轉發到內網。
  5. WARP 預設有一條 IP 規則 172.16.0.0/12 表示與此範圍相符的 IP 不會經過 WARP,這個範圍與上一步的範圍重疊, 因此需要將此規則刪除,這個設定藏在 Settings -> WARP Client -> Device settings -> Profile(configure) -> Split Tunnels -> Manage
    WARP Split Tunnel 設定

以上步驟先後完成了:使用 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 很多設定都藏在讓人無法理解的地方,如果沒有找到,會讓人以為根本沒有那些功能。

Written By
YI FENG XIE
YI FENG XIE

Creative Problem Solver