如何在 VPS 上執行 llama.cpp server
從固定 release tag 建置 llama-server,提供 GGUF 模型的 OpenAI 相容 API,繫結 localhost,並以 systemd 與記憶體限制穩定執行。
正在建置的內容
在 VPS 上執行 llama.cpp server,只需要一個二進位檔 llama-server。該程式會載入單一 GGUF 模型檔案,並透過相容於 OpenAI 的 API 回應 HTTP 請求。將任何 OpenAI client 指向 http://127.0.0.1:8080/v1 即可運作。安裝只是較簡單的部分。
其餘工作屬於營運管理:固定版本、讓連接埠只繫結至 localhost、建立 systemd unit,並決定主機記憶體耗盡時的處理方式。本指南涵蓋這些內容。如果你尚未在兩個明顯選項之間做出決定,請先閱讀 Ollama 與 llama.cpp 的取捨,因為該比較刻意省略了本操作指南涵蓋的實作細節。
選擇 release tag 並記錄
llama.cpp 幾乎每次合併都會標記一個 release,因此這些 tag 就是建置編號。截至 18 August 2026,b10488 是最新版本。llama.cpp 沒有長期維護的 stable branch,因此「latest」會持續變動;你測試過的版本就是唯一能支援的版本。請選擇一個 tag 並記錄下來,然後在 clone、二進位檔名稱與筆記中使用相同的字串。
每個 tag 也會提供預先建置的封存檔。僅使用 CPU 的 x86 VPS 應選擇 llama-b10488-bin-ubuntu-x64.tar.gz;如果使用的是 ARM VPS 而非 x86,旁邊也會有 arm64 封存檔。
curl -LO https://github.com/ggml-org/llama.cpp/releases/download/b10488/llama-b10488-bin-ubuntu-x64.tar.gz
tar tf llama-b10488-bin-ubuntu-x64.tar.gz | head解壓縮前先列出封存檔內容,確認檔案會放在哪裡。這些二進位檔是以建置映像檔中的 C library 連結,因此在較舊的發行版上啟動時,會因缺少 GLIBC_ 版本而失敗。小型 VPS 從原始碼建置只需幾分鐘,並可避免整類問題,因此以下採用這種方式。
從固定 tag 建置 llama-server
sudo apt update
sudo apt install -y build-essential cmake git libssl-dev
git clone --depth 1 --branch b10488 https://github.com/ggml-org/llama.cpp
cd llama.cpp
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF
cmake --build build --config Release -t llama-server -j 2--branch b10488 會在 --depth 1 clone 上簽出該 tag,且不包含其他內容,因此建置期間不會發生版本漂移。
libssl-dev 很重要,因為 LLAMA_OPENSSL 選項預設為啟用。這會讓二進位檔稍後能透過 HTTPS 下載模型。若缺少標頭檔,configure 步驟會失敗。
-DBUILD_SHARED_LIBS=OFF 會產生單一、自包含的二進位檔。預設建置會將 shared libraries 放在可執行檔旁邊,因此只將可執行檔複製到 /usr/local/bin 會因 error while loading shared libraries: libllama.so 而失敗。
-t llama-server 只建置 server target。預設建置也會編譯其他工具與測試;在雙核心 VPS 上,這會額外耗費數分鐘處理你不會執行的檔案。
-j 2 是刻意設定的。每個平行編譯工作都會保留自己的工作集,因此在小型方案上,-j $(nproc) 最後會導致 c++: fatal error: Killed signal terminated program cc1plus,也就是 kernel 的 out-of-memory killer 停止編譯器。請降低工作數,或在建置期間增加 swap。
你可能會想變更一個 flag:GGML_NATIVE 預設為啟用,因此編譯器會針對執行建置的實際 CPU。若你是在將執行該程式的機器上建置,這就是所需設定。若只建置一次,再將二進位檔複製到其他主機,請加入 -DGGML_NATIVE=OFF,因為若二進位檔使用另一顆 CPU 不支援的指令,第一次推論時就會因 Illegal instruction (core dumped) 而終止。
請以包含 tag 的名稱安裝。
./build/bin/llama-server --version
sudo install -m 755 build/bin/llama-server /usr/local/bin/llama-server-b10488
sudo ln -sfn /usr/local/bin/llama-server-b10488 /usr/local/bin/llama-server--version 會顯示建置編號與 commit。它們必須符合你簽出的 tag。若不符合,表示你建置了其他內容。將編號保留在檔名中,並讓 symlink 指向該檔案,升級時只需執行一次 ln -sfn 並重新啟動;回復舊版本時,使用相同指令搭配舊編號即可。
取得 GGUF 模型,並先檢查磁碟空間
GGUF 是 llama.cpp 載入的單一檔案格式。單一檔案包含權重、tokeniser 和中繼資料,因此不需要安裝其他內容。檔名副檔名表示量化格式,也就是儲存權重時使用的精度:Q4_K_M 是 4-bit 混合格式,Q8_0 是 8-bit,而 f16 是未量化的 half-precision 檔案。
在下載任何內容前,先建立服務帳號和模型目錄。
sudo useradd --system --home /srv/llama --create-home --shell /usr/sbin/nologin llama
sudo install -d -o llama -g llama /srv/models
df -h /srv伺服器可透過 -hf 自行取得模型。這是最快確認建置可正常運作的方法。
sudo -u llama env LLAMA_CACHE=/srv/models /usr/local/bin/llama-server \
-hf ggml-org/gemma-3-1b-it-GGUF:Q4_K_M --host 127.0.0.1 --port 8080LLAMA_CACHE 設定下載目錄。若未設定,檔案會放在執行命令的帳號之 ~/.cache/llama.cpp 下。這不適合即將限制其家目錄存取權限的服務。之後執行 ls -lh /srv/models,因為快取檔名是根據 repository 名稱產生,而不是根據一般檔名產生。
服務使用的模型應下載到指定路徑,讓 unit file 有穩定的目標可供指向。
sudo -u llama curl -L --output-dir /srv/models -O \
https://huggingface.co/ggml-org/gemma-3-1b-it-GGUF/resolve/main/gemma-3-1b-it-Q4_K_M.gguf磁碟空間是最先遇到的限制。以下是兩個模型在 18 August 2026 查核時公布的檔案大小。
The data behind this chart
[
{
"label": "gemma-3-1b-it Q4_K_M",
"size_gb": 0.81
},
{
"label": "gemma-3-1b-it Q8_0",
"size_gb": 1.07
},
{
"label": "gemma-3-1b-it f16",
"size_gb": 2.01
},
{
"label": "gpt-oss-20b MXFP4",
"size_gb": 12.11
}
]1B 模型的 4-bit 檔案大小為 0.81 GB。同一模型未經量化時為 2.01 GB,因此格式選擇會讓檔案大小增加超過兩倍。MXFP4 格式的 20B 模型為 12.11 GB,許多入門方案的磁碟無法容納,之後仍須將檔案讀入記憶體。如果你正在評估特定模型系列,GLM 的相同大小估算可顯示大型模型如何迅速超出 VPS 的價格與資源範圍,而較小的同系列模型仍可容納。
每次下載前都要檢查 df -h。root filesystem 若在傳輸 12 GB 時填滿,所有需要寫入的元件都會受影響,包括 journal。
手動執行一次,並檢查結果
sudo -u llama /usr/local/bin/llama-server \
--model /srv/models/gemma-3-1b-it-Q4_K_M.gguf \
--host 127.0.0.1 --port 8080 \
--ctx-size 4096 --parallel 1 --threads 2 --no-webui在第二個工作階段中,向伺服器確認是否已就緒。
curl -s http://127.0.0.1:8080/health檔案載入期間,您會收到 HTTP 503,回應本文如下:
{"error":{"code":503,"message":"Loading model","type":"unavailable_error"}}就緒後,回應本文為 {"status": "ok" }。接著傳送實際請求。
curl -s http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"local","messages":[{"role":"user","content":"Say hello in five words."}]}'包含 choices 陣列的 JSON 物件表示伺服器已正常運作。model 欄位存在的原因,是 OpenAI 用戶端一律會傳送該欄位。此伺服器只載入單一模型,因此不會使用這個值來選取模型。
OpenAI 相容 API,以及該連接埠上的其他內容
POST /v1/chat/completions、POST /v1/completions 和 POST /v1/embeddings 是 OpenAI 相容路由,GET /v1/models 會回報目前載入的模型。GET /health 是前述的就緒檢查,GET /props 會回傳伺服器目前的設定,而使用 --metrics 啟動時,GET /metrics 會公開 Prometheus 計數器。
設定基底 URL 為 http://127.0.0.1:8080/v1,並傳入非空白的 API 金鑰字串後,任何 OpenAI SDK 都能使用。除非你自行設定 --api-key,否則系統不會檢查該金鑰。
不要把他人宣稱的吞吐量當成自己規劃時的數值。CPU 推論速度取決於核心數量、記憶體頻寬,以及與你共用主機的其他租戶。因此,請在自己的主機上測量每秒產生的 token 數量,並以該結果為準。吵雜的共用租戶搶走的 CPU 時間會在這裡表現為生成速度隨時段變化。
保持在 127.0.0.1,並在前方加入代理
--host 預設已綁定 127.0.0.1,因此在變更設定前,伺服器無法從外部存取。請維持此設定。llama-server 沒有使用者模型、速率限制或實用的稽核日誌,唯一內建的控制項是 --api-key,只能比對一個字串。公開的推論埠會讓找到它的人免費使用運算資源;對 Ollama 犯下相同錯誤時,情況也一樣:鎖定自行代管的模型 API 的做法可逐項套用在這裡。
在 nginx 終止 TLS (transport layer security),再將請求代理到 loopback 埠。
server {
listen 443 ssl;
server_name llm.example.com;
location /v1/ {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_read_timeout 600s;
}
}串流需要 proxy_buffering off。啟用緩衝時,nginx 會持續保留 server-sent events (SSE),直到回應完成,因此用戶端會一直等待,最後一次收到完整答案。proxy_read_timeout 600s 可涵蓋較長的生成作業,因為預設的 60 秒會將緩慢的回答變成 504 Gateway Time-out。請使用 在 nginx 上設定 Certbot 和 Let's Encrypt 取得憑證。
systemd 單元
寫入 /etc/systemd/system/llama-server.service。
[Unit]
Description=llama.cpp server
After=network-online.target
Wants=network-online.target
[Service]
User=llama
Group=llama
Environment=LLAMA_ARG_MODEL=/srv/models/gemma-3-1b-it-Q4_K_M.gguf
Environment=LLAMA_ARG_HOST=127.0.0.1
Environment=LLAMA_ARG_PORT=8080
Environment=LLAMA_ARG_CTX_SIZE=4096
Environment=LLAMA_ARG_N_PARALLEL=1
Environment=LLAMA_ARG_THREADS=2
ExecStart=/usr/local/bin/llama-server --no-webui
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
MemoryHigh=3G
MemoryMax=3500M
OOMPolicy=stop
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
[Install]
WantedBy=multi-user.target設定值位於 Environment= 行,因為 llama-server 會針對大多數旗標讀取 LLAMA_ARG_* 變數,而命令列引數會覆寫相符的變數。這樣只需在一個位置變更 context 大小,也能讓 ExecStart 保持簡短,方便快速查看。
ProtectSystem=strict 會讓此單元使用的整個檔案系統變成唯讀。由於伺服器只會讀取模型,這樣的設定沒有問題。如果希望服務本身透過 -hf 下載模型,請加入 ReadWritePaths=/srv/models。ProtectHome=yes 會隱藏 /home 與 /root。這也是將模型放在 /srv 的第二個原因:啟用 ProtectHome 後,預設的 ~/.cache/llama.cpp 路徑完全不會呈現給處理程序。
sudo systemctl daemon-reload
sudo systemctl enable --now llama-server
systemctl status llama-server
curl -s http://127.0.0.1:8080/health
journalctl -u llama-server -n 50 --no-pagerenable --now 是許多人略過的部分。沒有 enable,伺服器會在下一次重新開機後消失。如果要為服務安排定期工作,例如每晚檢查是否有新版本,請使用 systemd 服務搭配 timer。
在 OOM 發生前決定處理方式
記憶體使用量分成兩部分,受到限制時的行為不同。模型檔案預設會以 memory-mapped 方式載入,因此其頁面由檔案支援:核心可以釋放這些頁面,之後再從磁碟讀回。KV cache 則是伺服器為每個作用中的對話保留的逐 token 狀態,屬於匿名記憶體。這些記憶體無法釋放,因此程序會因為它而遭到終止。
因此,unit 中的兩項限制用途不同。MemoryHigh=3G 是軟限制:超過此限制時,核心會對 cgroup 施加回收壓力,因此 memory-mapped 的模型頁面會被逐出,下一個 token 到來時再從磁碟讀回。服務仍會繼續運作,但速度會變慢。MemoryMax=3500M 是硬限制:超過此限制時,程序會遭到終止,journal 也會明確記錄這個結果。
llama-server.service: A process of this unit has been killed by the OOM killer.請自行設定 --ctx-size。預設值是 0,代表模型訓練時使用的 context 大小;在現代長 context 模型上,啟動時會配置非常大的 KV cache。服務可能在處理任何請求前就結束。--parallel 會以相同方式增加記憶體成本,因為每個 slot 都會保留自己的對話狀態,因此在確認需要並行處理前,請維持為 1。
設定 Restart=on-failure 後,被終止的服務會重新啟動。如果服務每次啟動都遭到終止,systemd 會放棄重試,而 systemctl status 會輸出 start request repeated too quickly。這是正確行為:每五秒重新讀取 12 GB 檔案的重啟迴圈,比服務中斷更糟。請修正限制或 context 大小,然後使用 sudo systemctl reset-failed llama-server 清除狀態。
在請求執行期間使用 systemctl show llama-server -p MemoryCurrent 監看實際數值。使用 systemd 限制程序的記憶體與 CPU 詳細說明這些指示詞。
避免讓此工作負載使用 swap。模型被換出後,每個 token 都會轉換成隨機位移的磁碟讀取。以 memory mapping 載入模型檔案也能達到相同效果,且危害較小,因為核心會直接從檔案讀取所需頁面。
Ollama 是較佳選擇的情況
這是兩條不同的路徑。若您需要由旗標設定、版本固定,並指定所選檔案的單一程序,且不希望有其他程序在背景變更內容,請選擇 llama-server。
若您需要模型管理功能,例如依名稱拉取模型、在磁碟上保留多個模型、卸載閒置模型,以及透過單一命令升級而不必重新建置,請選擇 Ollama。這些都是原本需要自行撰寫腳本處理的實際工作。在 VPS 上執行 Ollama 就是相同的工作,但取捨方向相反。兩者都提供與 OpenAI 相容的 API,因此無論往哪個方向切換,客戶端程式碼都能繼續使用。
升級已鎖定的建置版本
將 bNNNNN 替換為要升級到的標籤。
cd llama.cpp
git fetch --tags
git checkout bNNNNN
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_EXAMPLES=OFF
cmake --build build --config Release -t llama-server -j 2
sudo install -m 755 build/bin/llama-server /usr/local/bin/llama-server-bNNNNN
sudo ln -sfn /usr/local/bin/llama-server-bNNNNN /usr/local/bin/llama-server
sudo systemctl restart llama-server舊版二進位檔仍會保留在磁碟上,因此回復只需將一個 ln -sfn 改回 llama-server-b10488,再重新啟動即可。升級前請先閱讀版本資訊。GGUF 檔案有版本區分,舊版檔案仍可載入,但旗標可能會重新命名:--mlock 和 --no-mmap 已淘汰,應改用 --load-mode;如果 unit file 傳入已移除的旗標,服務會在啟動時失敗,並顯示未辨識引數的訊息。
失敗情況與您會看到的字串
error while loading shared libraries: libllama.so 出現在您將二進位檔複製到其他位置後。預設建置會在二進位檔旁產生共享函式庫。使用 -DBUILD_SHARED_LIBS=OFF 重新建置,或複製整個 build/bin 目錄。
Illegal instruction (core dumped) 出現在啟動時或第一次請求時。二進位檔啟用了 GGML_NATIVE 編譯,但目標 CPU 與目前執行它的 CPU 不同。在這台機器上重新建置,或使用 -DGGML_NATIVE=OFF 設定。
c++: fatal error: Killed signal terminated program cc1plus 出現在建置期間。編譯器因使用過多記憶體而被終止。降低 -j,或為建置增加 swap,完成後再移除。
curl: (7) Failed to connect ... Connection refused 出現在您的筆電上。這是正常情況:伺服器會在 VPS 的 loopback 位址上監聽。在 VPS 本機測試,或使用 ssh -L 8080:127.0.0.1:8080 user@your-vps 建立通道,再於本機使用 http://127.0.0.1:8080。
HTTP 503 搭配 "message":"Loading model" 出現在重新啟動後的前幾秒或幾分鐘。讀取數 GB 的檔案需要時間,而 systemd 會在程序啟動時立即將 unit 報告為 active,這遠早於模型載入記憶體。
請求會掛起,最後傳回 504 Gateway Time-out。 代理伺服器在模型完成前就放棄等待。提高 proxy_read_timeout,並關閉 proxy_buffering,讓 token 在產生時即傳送給用戶端。
unit 不斷重新啟動,最後停止,並顯示 start request repeated too quickly。每次啟動時都有某個元件將它終止。檢查 journalctl -u llama-server 是否包含 OOM killer 訊息,然後降低 --ctx-size、降低 --parallel,或提高 MemoryMax。
FAQ
我應該在 VPS 上執行 llama.cpp 的 server,還是 Ollama?
如果您需要固定確切的 build、傳入確切的 flags,並讓單一模型存放在不會被背景更新的單一檔案中,請執行 llama-server。如果您需要模型管理與單一指令升級,請使用 Ollama,因為依名稱拉取模型、在磁碟上保留多個模型,以及卸載閒置模型,否則都必須自行撰寫 script。兩者都提供與 OpenAI 相容的 API,因此日後切換時不需要修改 client code。
我應該固定哪個 llama.cpp 版本?
請使用您確實 build 並測試過的任何 tag。llama.cpp 幾乎每次 merge 都會建立 tag,名稱通常是 b10488 這類 build number;截至 18 August 2026,該版本是最新版本。llama.cpp 沒有獨立的 stable branch,因此「current」每天會變動數次。使用 --branch <tag> clone,將 binary 安裝為包含該 tag 的檔名,再讓 symlink 指向它。如此一來,升級與 rollback 各只需一個指令。
llama-server 需要多少 RAM?
先以 GGUF 檔案大小為基準,再加上 KV cache。KV cache 會隨 --ctx-size 與 --parallel slot 的數量增加。公開發布的數據不能取代對您自身環境的測量,因為總量取決於模型、quantisation 以及您允許的 context 大小。在有 request 執行期間執行 systemctl show llama-server -p MemoryCurrent,並使用顯示的數值。
為什麼 /health 會以「Loading model」回傳 503?
程序已啟動,但模型檔案尚未載入記憶體,因此 server 會回傳 {"error":{"code":503,"message":"Loading model","type":"unavailable_error"}}。每次重新啟動後都會出現這種情況,持續時間取決於讀取檔案所需的時間。只有當 client 或 proxy 將第一次 503 視為硬性失敗時,才會成為問題。輪詢 /health,直到它回傳 {"status": "ok" }。
我可以直接將 llama-server 暴露到網際網路嗎?
請勿將它 bind 到 0.0.0.0,也不要開放該埠。它沒有帳號、rate limiting,也沒有值得稽核的 request log;唯一內建的檢查是 --api-key,只會比對單一字串。維持預設的 127.0.0.1 bind,在前方設定使用 TLS 的 nginx,並同時設定 --api-key,如此一來,即使 proxy 設定出錯,也不會讓所有人都能存取模型。