VPS 安全架設 Ollama,自架 LLM API
7B 模型約需 8 GB RAM,CPU 每秒可產生 4 到 10 個 token。用 VPS 架設 Ollama,透過 127.0.0.1:11434/v1 呼叫,並保持 port 11434 關閉。
建置目標
在自有伺服器上執行單一開放權重語言模型,透過 HTTP API 提供回應;如果需要,也可在瀏覽器中使用聊天頁面。Ollama 負責下載模型、將模型載入記憶體,並在 http://127.0.0.1:11434 上提供請求服務。安裝只需執行一個命令。真正需要處理的部分在其他地方:選擇 VPS 實際能載入 RAM 的模型,以及避免將未經驗證的推論伺服器意外公開到整個網際網路。
先說明兩點。僅使用 CPU 的 VPS 執行小型模型時速度很慢,而 API 完全沒有內建驗證機制。下文會詳細說明這兩點,因為問題通常就出在這裡。
用實際數字檢查硬體規模
模型的記憶體占用量大致等於模型檔案大小,加上約 1 GB 的執行階段額外用量,再加上 context window 所需的空間。多數熱門 Ollama 模型的預設 tag,包括 llama3.2:3b、llama3.1:8b 與 mistral:7b,都是 4-bit 量化(標示為 Q4_K_M);每 1 billion 個參數約需 0.5 GB RAM。並非所有預設值都是 Q4:smollm2:135m 等小型模型以 16-bit 發布,因此計算前,請先查看模型 library 頁面上的量化資訊。計算方式很簡單,而且會決定所有結果。最後一項由你自行設定:將 num_ctx 調高至超過 Ollama 的小型預設值可容納較長的提示,但也會增加 RAM 中的 KV cache,因此請先決定 context length,再判斷模型是否能裝下。
llama3.2:3b 這類 3B 模型下載大小約為 2 GB,執行時約需 4 GB 可用 RAM。mistral:7b 或 llama3.1:8b 這類 7B 或 8B 模型在磁碟上約占 5 GB,約需 8 GB RAM;若要順暢使用,建議準備 16 GB。13B 或 14B 模型約需 16 GB。30B 至 70B 範圍內的模型需要大容量 RAM 的主機,或實際上應使用 GPU;在 CPU VPS 上不是無法容納,就是回應慢到失去實用性。
接著談速度,這是最容易被低估的部分。CPU 推論受記憶體頻寬限制,而非時脈速度;共享 vCPU VPS 的記憶體頻寬通常不高。預期速度約為每秒個位數至低兩位數的 tokens:7-8B Q4 模型可能達到每秒 4 至 10 個 tokens,3B 模型則約為每秒 10 至 25 個 tokens。GPU 大約快一個數量級。這些數字刻意只提供粗略估計;正確做法是測量自己的主機,以下的執行步驟會說明如何進行。請相信你的 eval rate,不要相信任何文章中的數字,包括本文。
實際結論是:如果能接受這樣的速度,CPU 上的小型量化模型確實適合用於草擬、摘要與分類。若需要更大型或更快速的模型,請將 GPU instance 的費用納入預算。若想查看在單一特定模型上完整執行這些計算的範例,在 VPS 上執行 Nemotron 3.5 Lightning會說明應拉取哪個 tag、實際需要多少 RAM,以及僅使用 CPU 是否能維持足夠速度。
若要評估特定模型是否適合特定主機,請在此估算其記憶體占用量:
安裝 Ollama
有兩種正確的方式。在純 VPS 上,官方 script 最簡單:
curl -fsSL https://ollama.com/install.sh | sh這會建立名為 ollama 的 system user,將 binary 安裝至 /usr/local/bin/ollama,並註冊名為 ollama.service 的 systemd service。該 service 會在開機時啟動,並繫結至 127.0.0.1:11434。確認服務已啟動:
systemctl status ollama
ollama --version如果已經使用 Docker,也可以改用 container:
docker run -d --name ollama \
-p 127.0.0.1:11434:11434 \
-v ollama:/root/.ollama \
--restart always \
ollama/ollama請注意連接埠映射中的 127.0.0.1: 前綴。這會將連接埠僅繫結至 localhost。若改寫為 -p 11434:11434,則會在所有介面上公開連接埠,這正是安全性章節警告的錯誤設定。請選擇其中一種安裝方式。不要同時執行 script 和 container,否則兩個程序會爭用同一個連接埠。
拉取並執行第一個模型
ollama pull llama3.2:3b
ollama run llama3.2:3bpull 會將模型層下載到磁碟(此模型約 2 GB)。run 會將這些模型層載入記憶體,並顯示 >>> 提示字元。輸入問題。載入權重並從磁碟讀入 RAM 時,產生第一個 token 可能需要數秒,之後答案會以串流方式輸出。輸入 /bye 離開聊天;Ollama 會繼續在背景執行。
查看已載入的內容,以及其配置方式:
ollama psPROCESSOR 欄會顯示實際狀態。100% CPU 表示未使用 GPU,速度緩慢的原因就在這裡。使用 verbose flag 測量實際速度:
ollama run --verbose llama3.2:3b "Write two sentences about Linux."最後列出的 eval rate 行,就是這台硬體每秒可處理的 token 數量。後續規劃應以此數值為基準。
模型存放位置與磁碟容量規劃
由腳本安裝並以服務方式執行時,模型會存放在 ollama 使用者的家目錄中:
sudo du -sh /usr/share/ollama/.ollama/models以自己的使用者身分互動式執行時,模型會存放在 ~/.ollama/models。在容器中,模型會存放於名為 ollama 的 volume。這點很重要,因為量化權重很快就會累積:3B 約為 2 GB,7-8B 約為 5 GB,14B 約為 9 GB。拉取 4 個模型進行比較後,可能在不知不覺間就占用 20 GB。請依預計保留的模型規劃磁碟容量,並使用 ollama rm <model> 刪除其餘模型。如果同一台 VPS 已執行自身也需要大量空間的服務,例如 存放相片庫的 PhotoPrism 或 Immich,請先從可用空間中扣除該服務所需的容量,再將剩餘空間視為實際的模型容量預算。
以你能控制的服務方式執行
安裝指令碼已註冊 ollama.service,因此開機時會自動重新啟動,無須進一步設定。值得調整的設定是模型保持常駐的時間,以及部分環境中的繫結位址。這兩項設定都放在 systemd drop-in 中,因此 Ollama 升級時不會覆寫:
sudo systemctl edit ollama.service在編輯器顯示的 [Service] 標頭下方加入以下內容:
[Service]
Environment="OLLAMA_KEEP_ALIVE=30m"OLLAMA_KEEP_ALIVE 是模型在最後一次請求後繼續保留在記憶體中的時間(預設為 5 分鐘)。如果整天都會查詢同一台主機,請提高此值,以免每次都重新載入權重;如果主機的記憶體有限,請將其設為 0,讓請求完成後立即釋放 RAM。若要讓模型永久常駐,而不是只在固定時間窗內保留,請參閱讓 Ollama 模型永久保持載入,其中說明每次請求的 keep_alive 欄位,以及如何在重新開機後重新預熱權重,而不是等到第一次緩慢的請求才載入。systemctl edit 會替你重新載入 unit 檔案,因此請重新啟動服務以套用變更:
sudo systemctl restart ollama最重要的安全事項
Ollama 預設繫結至 127.0.0.1:11434,因此只有 VPS 本機上的程序可以連線。這個預設值是正確的,請保留不變。
API 沒有任何驗證機制。完全沒有。沒有 API key、登入機制或速率限制。它唯一提供的允許清單 OLLAMA_ORIGINS,只會控制哪些瀏覽器來源可以呼叫 API(CORS);無法阻止其他電腦上的 curl 或指令碼。任何能連線至 11434 埠的使用者,都可以執行你已下載的任何模型、下載新模型、刪除模型,並讓 CPU 或 GPU 長時間維持滿載。Shodan 等掃描器會將數以千計的公開 Ollama 執行個體編入索引,公開的執行個體通常會在數小時內遭到發現並濫用。
因此,絕對不要犯以下錯誤:不要設定 OLLAMA_HOST=0.0.0.0,也不要在防火牆中開放 11434 埠。這會將未經驗證的推論伺服器公開至整個網際網路。無論如何設定,直接在 0.0.0.0 上開放 11434 都不安全,因為 Ollama 的文件化設定沒有任何一項能為本機 API 加入驗證,而來源允許清單也不是登入機制。這項規則只針對本服務,並不表示永遠不能開放連接埠:自架的 RustDesk 遠端桌面中繼伺服器 必須接受公開流量才能運作,而它之所以適合這樣做,是因為內建以金鑰為基礎的驗證機制,並使用一組精簡且有文件說明的連接埠;Ollama 完全沒有這些條件。
從其他位置安全存取模型有 3 種方式:
- 保持本機存取。如果唯一的呼叫端是同一台 VPS 上的其他程式、cron 指令碼、bot,或是將工具連接至模型的 MCP 伺服器,請將繫結保留在
127.0.0.1,並讓該程式呼叫http://127.0.0.1:11434。不會公開任何服務,也不需要其他設定。 - 透過私有通道存取。將 VPS 加入你自行架設的 WireGuard VPN,把
OLLAMA_HOST設定為通道位址(例如10.8.0.1,而不是0.0.0.0),如此只有 VPN 對等端可以連線。公開網際網路仍然無法看到 11434 埠。 - 在前方放置具備驗證功能的反向代理。在 nginx、Traefik 或 Caddy 上終止 TLS,並要求密碼或 token,然後將請求代理至
127.0.0.1:11434。Ollama 繼續繫結至 localhost,只有代理程式監聽公開連接埠。這與在任何本機服務前方的 nginx 上設定 Let's Encrypt 憑證 是相同的架構。
接下來的聊天 UI 會採用反向代理方式,並附加真正的登入機制。
使用 Open WebUI 新增聊天介面,並置於 TLS 後方
Open WebUI 是自架的聊天介面。請在 Docker 中執行,並將其指向本機 Ollama:
docker run -d \
--name open-webui \
--network=host \
-e OLLAMA_BASE_URL=http://127.0.0.1:11434 \
-v open-webui:/app/backend/data \
--restart always \
ghcr.io/open-webui/open-webui:main在 Linux VPS 上,--network=host 旗標是關鍵。它會讓容器使用主機的 network namespace,因此容器內的 127.0.0.1 就是主機自己的 loopback,容器可透過 127.0.0.1:11434 連線到 Ollama,而不必讓 Ollama 監聽其他介面。其他地方會看到的 bridge network 設定方式,--add-host=host.docker.internal:host-gateway 搭配 OLLAMA_BASE_URL=http://host.docker.internal:11434,在此無法運作:該名稱會解析為 Docker bridge gateway,而主機上繫結至 127.0.0.1 的服務無法透過 bridge 連線,因此 Open WebUI 只會持續顯示無法連線到 Ollama。
使用 host networking 的代價是,Open WebUI 現在會在主機的 8080 上監聽所有介面;任何 -p 對應都會被捨棄,Docker 也會顯示警告。請在主機與供應商防火牆上同時封鎖 8080,並讓 TLS reverse proxy 成為唯一的公開入口。首次造訪時,Open WebUI 會要求建立管理員帳號。該帳號就是驗證層,因此請設定強密碼。
若要從筆記型電腦透過 HTTPS 開啟聊天介面,請在 127.0.0.1:8080 前方配置 TLS reverse proxy。如果這台主機上已經透過路由提供多個 Docker 應用程式,使用自動 TLS 的 Traefik,適用於多個應用程式 是最合適的選擇:只需一個 label 區塊,就能簽發憑證並將 chat.example.com 路由至 Open WebUI。同樣的每個應用程式各自設定 label 的路由方式,也適用於主機上的其他瀏覽器前端,不論是狀態儀表板,或是較具趣味性的 Halcyon,它會將 Jellyfin 媒體庫呈現為 90 年代的出租店;每個服務都使用獨立的主機名稱,並置於各自的登入機制後方。安全性章節中的規則仍然適用:公開連接埠與登入機制由 proxy 管理,Ollama 則維持在 localhost,而 Open WebUI 自身的 8080 仍由防火牆封鎖。
從程式碼使用 OpenAI 相容端點
Ollama 在 /v1 提供 OpenAI chat API 的子集,因此大多數 OpenAI 用戶端函式庫只需修改兩項設定即可使用:基礎 URL 和臨時金鑰。
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="llama3.2:3b",
messages=[{"role": "user", "content": "Name three Linux distributions."}],
)
print(resp.choices[0].message.content)用戶端函式庫要求提供 api_key,但 Ollama 會忽略它,因此可使用任何字串。model 必須是已經拉取的模型名稱;未知名稱會回傳包含 model 'x' not found 的 404 錯誤。直接使用 curl 的方式相同:
curl http://127.0.0.1:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"llama3.2:3b","messages":[{"role":"user","content":"Hello"}]}'將模型整合至代理程式和編輯器工具時,也採用相同方式。如果你已在這台主機上進行開發,本機模型可以和 在 VPS 的 tmux 中執行 Claude Code 一起支援指令碼與外掛程式,讓低成本且私密的草稿工作不必使用付費 API,而將複雜推理交給代管模型。
失敗情況,以及實際看到的完整字串
處理程序在產生內容途中顯示「Killed」。 啟動大型模型後,終端機會顯示 Killed,或伺服器日誌(journalctl -u ollama)會出現以 llama-server process has terminated 開頭的行。這是 Ollama 0.40.7 的訊息,已於 21 October 2026 核對;較舊版本會顯示 llama runner process has terminated: signal: killed。Linux OOM killer 會終止處理程序,因為模型所需的 RAM 超過伺服器可提供的容量。使用 sudo dmesg | grep -i oom 確認原因,輸出中會看到類似 Out of memory: Killed process ... 的行。解決方式是改用較小或量化程度更高的模型,例如使用 llama3.2:3b,而不是 13B;也可以加入 swap,讓只稍微超過實體 RAM 的負載改以緩慢執行完成,而不是直接終止。Swap 會把立即當機變成緩慢回應,但無法讓 70B 模型在 4 GB 上實際運作。除非當時正好監看終端機,否則這種終止不會主動通知你。因此,若你是從其他位置查詢伺服器,可將會將通知發送至 自行架設的 ntfy 伺服器以推送警示 的 OnFailure= unit 附加至 ollama.service,在處理程序終止時立即得知,而不是等到下一次請求才發現。
Ollama 拒絕載入模型。 請求會立即失敗並顯示錯誤,不會使處理程序當機;伺服器日誌會記錄 model is too large for system memory(Ollama 0.40.7,已於 21 October 2026 核對)。較舊版本會直接在提示字元顯示 Error: model requires more system memory (X GiB) than is available (Y GiB)。這是上述當機情況較平順的版本:Ollama 先計算所需資源後停止,而不是交由 OOM killer 終止。選擇需求低於可用 RAM 的模型(使用 free -h 檢查)、縮短 context length,或改用更大型的 VPS。沒有任何 flag 能讓模型塞進不足的記憶體,因為記憶體需求是真實存在的。
第一個 token 等很久,之後就正常。 冷啟動的模型會在 5 到 30 秒內沒有輸出,接著正常串流回應。這段暫停時間是模型權重首次從磁碟載入 RAM;儲存裝置較慢時,等待時間會更長。載入後,模型會在 OLLAMA_KEEP_ALIVE 的期間持續留在記憶體中,因此第二次提示會立即得到回應。若首次載入時間超過請求路徑中某處的 timeout,最後會收到錯誤,而不是取得緩慢回應;釐清哪一層回報 context deadline exceeded,即可判斷是 client、proxy 或載入程序耗盡等待時間。若間隔時間造成困擾,請提高該值,並使用 ollama ps 查看目前是否已有模型載入。
所有操作都很慢。 每秒只能產生 10 個 token 或更少,但完全沒有錯誤。這表示 CPU inference 正在以 CPU inference 的正常方式運作。ollama ps 會顯示 100% CPU,代表沒有 GPU。這不是錯誤,也沒有任何設定能將 CPU 變成 GPU,因為主要限制是記憶體頻寬。不過,在 VM 上值得測試一項設定:Ollama 會依據偵測到的實體核心數選擇 thread count,而 hypervisor 可能會錯誤回報核心數。在 ollama run --verbose 工作階段中,嘗試 /set parameter num_thread 4(或你的 vCPU 數量),重新執行相同提示,並保留能提供最佳 eval rate 的值。除此之外,請改用較小的模型、接受目前速度,或改用 GPU instance;在判定系統故障前,先使用 --verbose 測量實際速率。如果等待時間是由回應長度而非產生速率造成,使用 num_predict 限制回應 可避免偏好冗長回答的模型花費數分鐘產生你根本不會閱讀的 token。
從其他機器連線時遭到拒絕。 從筆記型電腦執行目前版本的 curl(8.23.0,已於 21 October 2026 核對)時,會顯示 curl: (7) Failed to connect to <ip>:11434 after <n> ms: Could not connect to server;Ubuntu 24.04 隨附的 curl 8.5.0 則會顯示 curl: (7) Failed to connect to <ip> port 11434 after <n> ms: Couldn't connect to server。只有加入 -v,並在輸出中出現 connect to <ip> port 11434 from ... failed: Connection refused 的行時,才會看到「Connection refused」這些文字。這是預期行為:Ollama 只繫結 localhost。不要將 0.0.0.0 視為「修正」方式,因為這正是前文所述的暴露錯誤。請透過 VPN,或經由具備驗證功能的 proxy 連線至模型。
你已將 11434 暴露至網際網路。 如果你設定了 OLLAMA_HOST=0.0.0.0、開放防火牆,現在卻看到自己未啟動的模型下載,或 CPU 被不明 client 占用至 100%,表示服務已被發現並遭到使用。這是最需要注意的錯誤,不是罕見例外。重新繫結至 127.0.0.1 或 VPN 位址,在防火牆封鎖 11434,並在前方加入驗證機制。假設該位址開放期間,任何能連線的內容都已被陌生人查詢。
備份與升級
需要保留的狀態不多。模型可以重新下載,因此值得備份的項目只有 Open WebUI 的資料 volume、帳戶、聊天記錄、設定,以及你建立的任何 systemd drop-in。使用一次性容器備份 volume:
docker run --rm -v open-webui:/data -v "$PWD":/backup alpine \
tar czf /backup/open-webui.tgz -C /data .重新執行安裝腳本即可升級 Ollama;使用 docker pull ghcr.io/open-webui/open-webui:main 升級 Open WebUI,然後重新建立容器。關於 0.40 系列,請注意磁碟空間:Ollama 0.40.2 開始在背景升級較早版本下載的模型,並保留原始副本作為備份。因此,在刪除這些副本前,會額外占用磁碟空間;0.40.3(11 October 2026)則暫停了這項背景升級。升級後檢查 df -h,並閱讀 release notes,取得刪除這些備份的命令。不要長期固定任何版本:模型品質與 runtime 的變化都很快,因此應閱讀 release notes,並在自己的主機上重新執行基準測試,不要依賴上一季的數據。
FAQ
我真的可以在只有 CPU 的 VPS 上執行 LLM 嗎?
可以,但有其限制。3B 到 8B 範圍內的小型量化模型可在 CPU 上執行,適合用於草稿、摘要與分類,但速度較慢。在共用 vCPU 上,每秒通常只有個位數到十位數的 token。13B 以上的模型會非常慢,或完全無法放入 RAM。若需要更快的速度或更大型的模型,就需要 GPU instance。
每個模型需要多少 RAM?
大多數熱門模型預設使用 4-bit(Q4)標籤,可採用以下粗略估算:權重每 1B 個參數約需 0.5 GB RAM,另加約 1 GB 的額外負載,以及供 context 使用的少量空間。因此,3B 模型約需 4 GB 可用記憶體,7-8B 模型約需 8 GB,14B 模型約需 16 GB。使用 free -h 檢查剩餘空間,並為作業系統及主機上的其他程式保留足夠資源。
Ollama API 有驗證機制嗎?
沒有。Ollama 沒有內建驗證、API key 或速率限制。任何能連線到 port 11434 的人都能完全控制它。OLLAMA_ORIGINS 設定只會限制可呼叫它的瀏覽器來源,不會限制哪些人可以連線。這正是它預設繫結至 127.0.0.1 的原因,也是絕對不能將 0.0.0.0 上的 11434 暴露到網際網路的原因。請在本機、透過私有 VPN,或透過會加上登入機制的反向代理存取它。
如何加入網頁聊天介面?
使用 --network=host 在 Docker 中執行 Open WebUI,讓它共用主機的 loopback,並連線至 http://127.0.0.1:11434 上的原生 Ollama。接著在其 port 8080 前方設定 TLS 反向代理,供筆記型電腦存取。請在防火牆上封鎖 8080,讓反向代理成為唯一的公開入口。Open WebUI 自己的管理員帳號會提供登入機制,並在首次啟動時設定密碼。
如何從自己的應用程式呼叫它?
使用 http://127.0.0.1:11434/v1 上相容於 OpenAI 的 endpoint。將任何 OpenAI SDK 指向該 base URL,API key 可填入任意字串,因為系統會忽略它,並將 model 設為已下載的模型名稱。現有的 OpenAI 程式碼通常無須修改即可執行,只需變更 base URL 和 key。