SSD Nodes Learn Hosting plans →
คู่มือ Matt Connorโดย Matt Connor · อัปเดตเมื่อ 2026-09-13

วิธีรัน llama.cpp server บน VPS พร้อมตั้งค่า systemd

เรียนรู้วิธีติดตั้ง llama-server จาก tag ที่กำหนดเพื่อใช้งาน GGUF models ผ่าน OpenAI API พร้อมตั้งค่า bind localhost และจำกัด memory ด้วย systemd อย่างถูกต้อง

สิ่งที่คุณกำลังสร้าง

การรันเซิร์ฟเวอร์ llama.cpp บน VPS หมายถึงการใช้ไบนารีเพียงตัวเดียวคือ llama-server ซึ่งจะโหลดไฟล์โมเดล GGUF หนึ่งไฟล์และตอบกลับคำขอ HTTP ผ่าน API ที่เข้ากันได้กับ OpenAI คุณสามารถชี้ไคลเอนต์ OpenAI ใดๆ ไปที่ http://127.0.0.1:8080/v1 แล้วระบบจะทำงานได้ทันที การติดตั้งเป็นเพียงครึ่งแรกที่ทำได้ง่าย

งานที่เหลือคือการดูแลระบบ (Operations): การล็อกเวอร์ชัน, การจำกัดพอร์ตไว้ที่ localhost, การเขียน systemd unit และการตัดสินใจว่าจะเกิดอะไรขึ้นเมื่อหน่วยความจำของเครื่องเต็ม นี่คือสิ่งที่คู่มือนี้ครอบคลุม หากคุณยังไม่ได้ตัดสินใจระหว่างสองตัวเลือกที่ชัดเจน โปรดอ่าน ข้อดีข้อเสียระหว่าง Ollama และ llama.cpp ก่อน เพราะนี่คือวิธีปฏิบัติที่การเปรียบเทียบนั้นจงใจละไว้

เลือก release tag และจดบันทึกไว้

llama.cpp ทำการ tag release แทบทุกครั้งที่มีการ merge ดังนั้น tag จึงเป็นหมายเลข build โดย b10488 คือเวอร์ชันล่าสุด ณ วันที่ 18 สิงหาคม 2026 เนื่องจากไม่มี branch ที่เสถียรแบบ long-lived คำว่า "latest" จึงมีการเปลี่ยนแปลงอยู่ตลอดเวลา และเวอร์ชันที่คุณทดสอบจะเป็นเวอร์ชันเดียวที่คุณสามารถให้การสนับสนุนได้ ให้เลือก tag มาหนึ่งรายการ จดบันทึกไว้ และใช้สตริงเดียวกันนั้นในการ clone, ในชื่อไฟล์ binary และในบันทึกของคุณ

แต่ละ tag ยังมีการจัดส่งไฟล์ archive ที่ build ไว้ล่วงหน้า สำหรับ VPS สถาปัตยกรรม x86 ที่ใช้เฉพาะ CPU จะเป็น llama-b10488-bin-ubuntu-x64.tar.gz และจะมี archive สำหรับ arm64 อยู่ข้างกันหากคุณใช้งาน บน ARM VPS แทนที่จะเป็น x86

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

ให้แสดงรายการไฟล์ใน archive ก่อนทำการแตกไฟล์ เพื่อให้คุณทราบว่าไฟล์จะถูกวางไว้ที่ตำแหน่งใด ไฟล์ binary เหล่านี้ถูก link เข้ากับ C library ของ image ที่ใช้ build ดังนั้นหากใช้งานบน distribution รุ่นเก่า โปรแกรมจะล้มเหลวเมื่อเริ่มทำงานพร้อมข้อความแจ้งเตือนเกี่ยวกับเวอร์ชัน GLIBC_ ที่ไม่ได้ติดตั้งไว้ การ build จาก source ใช้เวลาเพียงไม่กี่นาทีบน VPS ขนาดเล็กและช่วยขจัดปัญหาประเภทนี้ทั้งหมด ดังนั้นจึงเป็นแนวทางที่แนะนำไว้ด้านล่างนี้

การสร้าง llama-server จาก tag ที่กำหนดไว้

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 จะทำการ checkout เฉพาะ tag นั้นเท่านั้น ทำให้การ build ไม่เกิดความคลาดเคลื่อนในระหว่างที่คุณกำลังทำงาน

libssl-dev มีความสำคัญเนื่องจากตัวเลือก LLAMA_OPENSSL ถูกเปิดใช้งานเป็นค่าเริ่มต้น ซึ่งเป็นสิ่งที่ช่วยให้ binary สามารถดาวน์โหลดโมเดลผ่าน HTTPS ได้ในภายหลัง หากไม่มี header เหล่านี้ ขั้นตอนการ configure จะล้มเหลว

-DBUILD_SHARED_LIBS=OFF จะทำให้คุณได้ binary แบบเบ็ดเสร็จในไฟล์เดียว การ build แบบปกติจะวาง shared library ไว้ข้างไฟล์ executable ทำให้การคัดลอกเฉพาะไฟล์ executable ไปยัง /usr/local/bin ล้มเหลวด้วยข้อผิดพลาด error while loading shared libraries: libllama.so

-t llama-server จะทำการ build เฉพาะเป้าหมายที่เป็น server เท่านั้น การ build แบบปกติจะคอมไพล์เครื่องมืออื่นๆ และการทดสอบทั้งหมดด้วย ซึ่งบน VPS ที่มี 2 core จะใช้เวลาเพิ่มขึ้นอีกหลายนาทีกับไฟล์ที่คุณไม่ได้ใช้งาน

-j 2 เป็นสิ่งที่ตั้งใจให้เป็นเช่นนั้น งานคอมไพล์แบบขนานแต่ละงานจะใช้หน่วยความจำของตัวเอง ดังนั้นการใช้ -j $(nproc) บนแผนบริการขนาดเล็กจะจบลงด้วย c++: fatal error: Killed signal terminated program cc1plus ซึ่งก็คือกลไก out-of-memory killer ของ kernel ที่เข้ามาหยุดการทำงานของคอมไพเลอร์ ให้ลดจำนวนงานลงหรือเพิ่ม swap สำหรับการ build

มี flag หนึ่งที่คุณอาจต้องการเปลี่ยน: GGML_NATIVE ถูกเปิดใช้งานเป็นค่าเริ่มต้น เพื่อให้คอมไพเลอร์กำหนดเป้าหมายไปที่ CPU เครื่องที่ทำการ build โดยเฉพาะ ซึ่งเป็นสิ่งที่คุณต้องการเมื่อ build บนเครื่องที่จะใช้งานจริง หากคุณ build เพียงครั้งเดียวแล้วคัดลอก binary ไปยังโฮสต์อื่น ให้เพิ่ม -DGGML_NATIVE=OFF เข้าไปด้วย เพราะ binary ที่ใช้ชุดคำสั่งซึ่ง 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 จะแสดงหมายเลข build และ commit ซึ่งต้องตรงกับ tag ที่คุณ checkout มา หากไม่ตรงกัน แสดงว่าคุณได้ build สิ่งอื่นไปแล้ว การเก็บหมายเลขไว้ในชื่อไฟล์และชี้ symlink ไปที่ไฟล์นั้นจะช่วยให้การอัปเกรดทำได้โดยใช้ ln -sfn หนึ่งครั้งและ restart หนึ่งครั้ง ส่วนการย้อนกลับ (rollback) ก็ใช้คำสั่งเดียวกันกับหมายเลขเวอร์ชันเก่า

รับโมเดล GGUF และตรวจสอบพื้นที่ดิสก์ก่อน

GGUF คือรูปแบบไฟล์เดี่ยวที่ llama.cpp ใช้โหลด ข้อมูลน้ำหนัก (weights), ตัวตัดคำ (tokenizer) และข้อมูลเมตา (metadata) ทั้งหมดถูกรวมไว้ในไฟล์เดียว จึงไม่มีส่วนประกอบอื่นที่ต้องติดตั้งเพิ่มเติม ส่วนต่อท้ายของชื่อไฟล์คือระดับการทำ quantisation ซึ่งเป็นความละเอียดที่ใช้จัดเก็บน้ำหนัก โดย Q4_K_M คือการผสมแบบ 4-bit, Q8_0 คือ 8-bit และ f16 คือไฟล์ความละเอียดครึ่งหนึ่ง (half-precision) ที่ไม่ได้ทำ quantisation

สร้างบัญชีผู้ใช้สำหรับรัน service และไดเรกทอรีสำหรับเก็บโมเดลก่อนเริ่มดาวน์โหลดสิ่งใดๆ

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 ซึ่งเป็นวิธีที่เร็วที่สุดในการทดสอบว่า build ของคุณทำงานได้ถูกต้อง

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 8080

LLAMA_CACHE ใช้สำหรับกำหนดไดเรกทอรีปลายทางในการดาวน์โหลด หากไม่กำหนด ไฟล์จะถูกบันทึกลงใน ~/.cache/llama.cpp ภายใต้บัญชีผู้ใช้ที่รันคำสั่ง ซึ่งไม่ใช่ตำแหน่งที่เหมาะสมสำหรับ service ที่คุณกำลังจะตั้งค่า home directory ให้ไม่สามารถอ่านได้ ให้รัน ls -lh /srv/models หลังจากนั้น เนื่องจากชื่อไฟล์ที่แคชไว้จะถูกสร้างจากชื่อ repository ไม่ใช่ชื่อไฟล์ต้นฉบับ

สำหรับ service ให้ดาวน์โหลดไปยังพาธที่คุณเลือก เพื่อให้ 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 สิงหาคม 2026

ChartGGUF file size on disk, published figures, 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
  }
]

ไฟล์ 4-bit สำหรับโมเดลขนาด 1B มีขนาด 0.81 GB ส่วนโมเดลเดียวกันที่ไม่มีการทำ quantisation มีขนาด 2.01 GB ดังนั้นการเลือกรูปแบบไฟล์จึงส่งผลต่อขนาดมากกว่าสองเท่า โมเดลขนาด 20B ที่ MXFP4 มีขนาด 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."}]}'

ออบเจกต์ JSON ที่มีอาร์เรย์ choices แสดงว่าเซิร์ฟเวอร์ทำงานได้ตามปกติ ฟิลด์ model ปรากฏอยู่เนื่องจากไคลเอนต์ของ OpenAI จะส่งฟิลด์นี้มาเสมอ เซิร์ฟเวอร์นี้โหลดโมเดลไว้เพียงตัวเดียว ค่าดังกล่าวจึงไม่ได้ถูกนำไปใช้เพื่อเลือกสิ่งใด

API ที่รองรับ OpenAI และสิ่งที่อยู่บนพอร์ตเดียวกัน

POST /v1/chat/completions, POST /v1/completions และ POST /v1/embeddings คือเส้นทาง (route) ที่รองรับ OpenAI ส่วน GET /v1/models จะรายงานโมเดลที่โหลดอยู่ GET /health คือการตรวจสอบความพร้อมที่กล่าวถึงข้างต้น GET /props จะส่งคืนการตั้งค่าปัจจุบันของเซิร์ฟเวอร์ และ GET /metrics จะแสดง Prometheus counters เมื่อคุณเริ่มต้นใช้งานด้วย --metrics

SDK ของ OpenAI ทุกตัวสามารถใช้งานได้ทันทีเมื่อคุณตั้งค่า base URL เป็น http://127.0.0.1:8080/v1 และระบุสตริง API key ที่ไม่เป็นค่าว่าง ทั้งนี้จะไม่มีการตรวจสอบคีย์ดังกล่าวจนกว่าคุณจะตั้งค่า --api-key ด้วยตนเอง

อย่าใช้ตัวเลขการประมวลผลที่ผู้อื่นอ้างอิงมาเป็นเกณฑ์สำหรับแผนงานของคุณ ความเร็วในการทำ inference บน CPU ขึ้นอยู่กับจำนวนคอร์, แบนด์วิดท์ของหน่วยความจำ และเพื่อนบ้านที่คุณใช้งานโฮสต์ร่วมด้วย ดังนั้นให้ วัดจำนวนโทเค็นต่อวินาทีบนเครื่องของคุณเอง และยึดผลลัพธ์นั้นเป็นความจริง Steal time จากเพื่อนบ้านที่ใช้งานหนัก (noisy neighbour) จะปรากฏให้เห็นในรูปแบบของความเร็วในการสร้างข้อความที่เปลี่ยนแปลงไปในแต่ละชั่วโมง

คงไว้ที่ 127.0.0.1 และวาง proxy ไว้ด้านหน้า

--host มีค่าเริ่มต้นเป็น 127.0.0.1 อยู่แล้ว ดังนั้นเซิร์ฟเวอร์จึงไม่สามารถเข้าถึงได้จากภายนอกจนกว่าคุณจะเปลี่ยนค่านี้ ให้คงค่าเดิมไว้ เนื่องจาก llama-server ไม่มีโมเดลผู้ใช้ ไม่มีอัตราจำกัด (rate limit) และไม่มี log สำหรับตรวจสอบที่มีประโยชน์ อีกทั้งการควบคุมเพียงอย่างเดียวที่มีมาให้คือ --api-key ซึ่งเป็นการเปรียบเทียบสตริงเพียงค่าเดียว การเปิดพอร์ต inference ทิ้งไว้เท่ากับเป็นการเปิดให้ใครก็ตามที่พบพอร์ตนี้เข้ามาใช้ทรัพยากรประมวลผลของคุณได้ฟรี ซึ่งเป็นความผิดพลาดในลักษณะเดียวกับที่เกิดขึ้นกับ Ollama โดยสามารถดูแนวทางแก้ไขได้ที่ การจำกัดสิทธิ์การเข้าถึง API ของโมเดลที่โฮสต์เอง ซึ่งสามารถนำมาประยุกต์ใช้ได้ในทุกขั้นตอน

ให้ทำ TLS (transport layer security) termination ที่ nginx แล้วทำ proxy ไปยังพอร์ต 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 เป็นสิ่งจำเป็นสำหรับการสตรีมข้อมูล หากเปิดการทำ buffering ไว้ nginx จะกักเก็บ server-sent events (SSE) ไว้จนกว่าการตอบสนองจะเสร็จสิ้น ส่งผลให้ไคลเอนต์ต้องรอโดยไม่มีการตอบสนองใดๆ แล้วจึงได้รับคำตอบทั้งหมดในคราวเดียว ส่วน proxy_read_timeout 600s จะช่วยจัดการกับการสร้างคำตอบที่ใช้เวลานาน เนื่องจากค่าเริ่มต้นที่ 60 วินาทีจะทำให้คำตอบที่ช้ากลายเป็น 504 Gateway Time-out สำหรับการขอใบรับรอง ให้ดำเนินการตามขั้นตอนใน Certbot และ Let's Encrypt บน nginx

Systemd unit

เขียน /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_* สำหรับ flag ส่วนใหญ่ และอาร์กิวเมนต์ในบรรทัดคำสั่งจะเขียนทับตัวแปรที่ตรงกัน วิธีนี้ช่วยให้คุณมีจุดเดียวในการปรับเปลี่ยนขนาด context และทำให้ ExecStart สั้นพอที่จะอ่านได้ในทันที

ProtectSystem=strict จะทำให้ระบบไฟล์ทั้งหมดเป็นแบบอ่านได้อย่างเดียว (read-only) สำหรับ unit นี้ ซึ่งเหมาะสมเนื่องจากเซิร์ฟเวอร์ทำหน้าที่เพียงอ่านโมเดลเท่านั้น ให้เพิ่ม ReadWritePaths=/srv/models หากคุณต้องการให้ตัวบริการดาวน์โหลดโมเดลด้วยตนเองโดยใช้ -hf ส่วน ProtectHome=yes จะซ่อน /home และ /root ซึ่งเป็นเหตุผลข้อที่สองที่ควรเก็บโมเดลไว้ใน /srv เพราะเมื่อเปิดใช้งาน ProtectHome แล้ว พาธ ~/.cache/llama.cpp เริ่มต้นจะไม่ถูกมองเห็นโดย process เลย

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-pager

enable --now คือส่วนที่คนมักมองข้าม หากไม่มี enable เซิร์ฟเวอร์จะหายไปหลังจากรีบูตครั้งถัดไป หากคุณต้องการให้มีงานที่กำหนดเวลาไว้รอบตัวบริการ เช่น การตรวจสอบเวอร์ชันใหม่ทุกคืน systemd service ร่วมกับ timer คือกลไกที่ใช้สำหรับงานนี้

ตัดสินใจว่าจะเกิดอะไรขึ้นเมื่อเกิดสภาวะ OOM ก่อนที่ปัญหาจะเกิดขึ้นจริง

การใช้งานหน่วยความจำมีสองส่วนและมีพฤติกรรมที่แตกต่างกันภายใต้ข้อจำกัด ไฟล์โมเดลจะถูกทำ memory-mapped โดยค่าเริ่มต้น ดังนั้นหน้าหน่วยความจำ (pages) จึงเป็นแบบ file-backed ซึ่งเคอร์เนลสามารถทิ้งและอ่านกลับมาจากดิสก์ได้ ส่วน KV cache ซึ่งเป็นสถานะต่อโทเค็นที่เซิร์ฟเวอร์เก็บไว้สำหรับการสนทนาแต่ละรายการนั้นเป็นหน่วยความจำแบบ anonymous ซึ่งไม่สามารถทิ้งได้ จึงเป็นสาเหตุที่ทำให้กระบวนการทำงานถูกสั่งยุติ (killed)

นั่นคือเหตุผลที่ข้อจำกัดทั้งสองรายการใน unit ทำหน้าที่ต่างกัน MemoryHigh=3G เป็น soft limit: เมื่อเกินค่านี้ เคอร์เนลจะกดดันให้ cgroup คืนหน่วยความจำ ทำให้หน้าหน่วยความจำของโมเดลที่ถูกแมปไว้ถูกนำออกและอ่านกลับจากดิสก์ในโทเค็นถัดไป บริการจะยังคงทำงานต่อไปได้แต่จะช้าลง ส่วน MemoryMax=3500M เป็น hard limit: หากเกินค่านี้ กระบวนการทำงานจะถูกสั่งยุติ และบันทึกใน journal จะระบุสาเหตุไว้อย่างชัดเจน

llama-server.service: A process of this unit has been killed by the OOM killer.

กำหนดค่า --ctx-size ด้วยตัวคุณเอง ค่าเริ่มต้นคือ 0 ซึ่งหมายถึงบริบทที่โมเดลถูกฝึกมา และสำหรับโมเดลสมัยใหม่ที่รองรับบริบทขนาดยาว (long-context) จะมีการจอง KV cache ขนาดใหญ่มากตั้งแต่เริ่มทำงาน ส่งผลให้บริการหยุดทำงานก่อนที่จะตอบสนองคำขอแรกเสียอีก ส่วน --parallel จะคูณต้นทุนดังกล่าวเพิ่มขึ้น เนื่องจากแต่ละ slot จะเก็บสถานะการสนทนาของตนเอง ดังนั้นควรคงค่าไว้ที่ 1 จนกว่าคุณจะทราบแน่ชัดว่าต้องการการทำงานแบบขนาน (concurrency)

ด้วย Restart=on-failure บริการที่ถูกสั่งยุติจะกลับมาทำงานใหม่ หากบริการถูกสั่งยุติทุกครั้งที่เริ่มทำงาน systemd จะยอมแพ้และ systemctl status จะแสดงข้อความ start request repeated too quickly ซึ่งเป็นพฤติกรรมที่ถูกต้องแล้ว เพราะการวนซ้ำเพื่อเริ่มทำงานใหม่โดยอ่านไฟล์ขนาด 12 GB ทุกๆ ห้าวินาทีนั้นสร้างความเสียหายมากกว่าการที่บริการหยุดทำงาน ให้แก้ไขข้อจำกัดหรือขนาดบริบท จากนั้นจึงล้างสถานะด้วย sudo systemctl reset-failed llama-server

ตรวจสอบตัวเลขจริงด้วย systemctl show llama-server -p MemoryCurrent ในขณะที่คำขอกำลังทำงาน การจำกัดหน่วยความจำและ CPU ของกระบวนการด้วย systemd ครอบคลุมคำสั่งเหล่านี้ในรายละเอียดเพิ่มเติม

หลีกเลี่ยงการใช้ swap สำหรับภาระงานนี้ การสลับโมเดลออกไปยัง swap จะเปลี่ยนทุกโทเค็นให้กลายเป็นการอ่านดิสก์แบบสุ่ม การทำ memory mapping ไฟล์โมเดลจะให้ผลลัพธ์แบบเดียวกันโดยสร้างความเสียหายน้อยกว่า เนื่องจากเคอร์เนลจะอ่านหน้าหน่วยความจำที่ต้องการโดยตรงจากไฟล์นั้นๆ

กรณีที่ Ollama เป็นทางเลือกที่ดีกว่า

นี่คือจุดตัดสินใจ คุณควรเลือก llama-server เมื่อต้องการกระบวนการทำงานเดียวที่ควบคุมด้วย flag ที่คุณกำหนดเอง มี build ที่ระบุเวอร์ชันไว้ชัดเจน และใช้ไฟล์ที่คุณเลือก โดยที่ไม่มีการเปลี่ยนแปลงใดๆ เกิดขึ้นภายใต้การทำงานนั้นเนื่องจากไม่มีกระบวนการอื่นรันอยู่

เลือก Ollama เมื่อคุณต้องการระบบจัดการโมเดล เช่น การดึงโมเดลตามชื่อ การเก็บโมเดลหลายตัวไว้ในดิสก์ การยกเลิกการโหลดโมเดลที่ไม่ได้ใช้งาน และการอัปเกรดด้วยคำสั่งเดียวแทนการต้อง build ใหม่ ซึ่งเป็นงานจริงที่คุณจะต้องเขียนสคริปต์จัดการเองหากไม่ใช้เครื่องมือนี้ การรัน Ollama บน VPS คือการทำงานในลักษณะเดียวกันแต่เป็นการแลกเปลี่ยนข้อดีข้อเสียในมุมที่ต่างออกไป ทั้งสองทางเลือกให้บริการ API ที่เข้ากันได้กับ OpenAI ดังนั้นโค้ดของไคลเอนต์จึงสามารถใช้งานได้ต่อเนื่องไม่ว่าจะสลับไปใช้ทางเลือกใดก็ตาม

การอัปเกรดบิลด์ที่ถูกตรึงเวอร์ชันไว้

แทนที่ 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 แล้วทำการรีสตาร์ทหนึ่งครั้ง โปรดอ่านบันทึกประจำรุ่น (release notes) ก่อนดำเนินการ ไฟล์ GGUF มีการระบุเวอร์ชันและไฟล์รุ่นเก่าจะยังคงโหลดได้ตามปกติ แต่แฟล็กบางตัวอาจมีการเปลี่ยนชื่อ เช่น --mlock และ --no-mmap ถูกเลิกใช้งานแล้วเพื่อเปลี่ยนไปใช้ --load-mode แทน และไฟล์ unit ที่มีการส่งแฟล็กที่ถูกถอดออกไปแล้วจะทำให้การเริ่มต้นล้มเหลวพร้อมข้อความแจ้งเตือนว่าไม่รู้จักอาร์กิวเมนต์ดังกล่าว

รูปแบบความล้มเหลวและข้อความที่คุณจะพบ

error while loading shared libraries: libllama.so หลังจากที่คุณคัดลอกไฟล์ binary ไปยังตำแหน่งอื่น การ build แบบปกติจะสร้าง shared libraries ควบคู่ไปด้วย ให้ทำการ build ใหม่ด้วย -DBUILD_SHARED_LIBS=OFF หรือคัดลอกทั้งไดเรกทอรี build/bin ไปด้วย

Illegal instruction (core dumped) ในระหว่างการเริ่มต้นระบบหรือเมื่อมีการร้องขอครั้งแรก ไฟล์ binary ถูกคอมไพล์โดยเปิดใช้งาน GGML_NATIVE สำหรับ CPU รุ่นที่ต่างจากเครื่องที่กำลังรันอยู่ ให้ทำการ build ใหม่บนเครื่องนี้ หรือกำหนดค่าด้วย -DGGML_NATIVE=OFF

c++: fatal error: Killed signal terminated program cc1plus ในระหว่างการ build คอมไพเลอร์ถูกสั่งยุติการทำงานเนื่องจากใช้หน่วยความจำมากเกินไป ให้ลดค่า -j หรือเพิ่ม swap สำหรับการ build แล้วค่อยลบออกในภายหลัง

curl: (7) Failed to connect ... Connection refused จากแล็ปท็อปของคุณ นี่เป็นสถานะที่ถูกต้องแล้ว เนื่องจากเซิร์ฟเวอร์ฟังคำสั่งบน loopback address ของ VPS ให้ทดสอบบนตัว VPS เอง หรือเปิด tunnel ด้วย ssh -L 8080:127.0.0.1:8080 user@your-vps แล้วใช้งาน http://127.0.0.1:8080 ในเครื่องของคุณ

HTTP 503 พร้อมด้วย "message":"Loading model" ในช่วงวินาทีหรือนาทีแรกหลังจากรีสตาร์ท การอ่านไฟล์ขนาดหลายกิกะไบต์ต้องใช้เวลา และ systemd จะรายงานสถานะ unit ว่า active ทันทีที่ process เริ่มทำงาน ซึ่งเกิดขึ้นก่อนที่โมเดลจะถูกโหลดเข้าสู่หน่วยความจำ

การร้องขอค้างแล้วส่งคืน 504 Gateway Time-out พร็อกซีหยุดรอการตอบกลับก่อนที่โมเดลจะประมวลผลเสร็จสิ้น ให้เพิ่มค่า proxy_read_timeout และปิดการใช้งาน proxy_buffering เพื่อให้โทเค็นถูกส่งไปยังไคลเอนต์ทันทีที่สร้างเสร็จ

Unit มีสถานะไม่คงที่ (flapping) แล้วหยุดทำงาน พร้อมด้วย start request repeated too quickly มีบางอย่างสั่งยุติการทำงานของมันในทุกครั้งที่เริ่ม ให้ตรวจสอบ journalctl -u llama-server เพื่อดูบรรทัดที่เกี่ยวข้องกับ OOM killer จากนั้นให้ลดค่า --ctx-size, ลดค่า --parallel หรือเพิ่มค่า MemoryMax

FAQ

ฉันควรใช้ llama.cpp server หรือ Ollama บน VPS ของฉัน?

ให้ใช้ llama-server เมื่อคุณต้องการล็อกเวอร์ชันของ build ที่แน่นอน ต้องการส่ง flag เฉพาะเจาะจง และต้องการเก็บโมเดลไว้ในไฟล์เดียวโดยไม่มีการอัปเดตใดๆ โดยที่คุณไม่ทราบ ให้ใช้ Ollama เมื่อคุณต้องการระบบจัดการโมเดลและการอัปเกรดด้วยคำสั่งเดียว เพราะการดึงโมเดลด้วยชื่อ การเก็บโมเดลหลายตัวไว้ในดิสก์ และการยกเลิกการโหลดโมเดลที่ไม่ได้ใช้งาน เป็นงานที่คุณต้องเขียนสคริปต์จัดการเองหากไม่ใช้เครื่องมือนี้ ทั้งสองตัวให้บริการ API ที่เข้ากันได้กับ OpenAI ดังนั้นโค้ดฝั่งไคลเอนต์จึงไม่ต้องแก้ไขหากคุณเปลี่ยนไปใช้ตัวอื่นในภายหลัง

ฉันควรล็อกเวอร์ชัน llama.cpp ไว้ที่เวอร์ชันใด?

ให้ใช้ tag ใดก็ได้ที่คุณได้ build และทดสอบการใช้งานจริงแล้ว llama.cpp จะสร้าง tag แทบทุกครั้งที่มีการ merge และชื่อจะเป็นหมายเลข build เช่น b10488 ซึ่งเป็นเวอร์ชันล่าสุด ณ วันที่ 18 สิงหาคม 2026 ไม่มี branch stable แยกต่างหาก ดังนั้นคำว่า "ปัจจุบัน" จึงมีการเปลี่ยนแปลงหลายครั้งต่อวัน ให้ clone ด้วย --branch <tag> ติดตั้ง binary โดยใช้ชื่อไฟล์ที่มี tag นั้นกำกับไว้ และสร้าง symlink ชี้ไปที่ไฟล์ดังกล่าว เพื่อให้การอัปเกรดและการย้อนกลับทำได้ด้วยคำสั่งเดียว

llama-server ต้องการ RAM เท่าไหร่?

ให้เริ่มคำนวณจากขนาดของไฟล์ GGUF แล้วบวกด้วย KV cache ซึ่งจะเพิ่มขึ้นตาม --ctx-size และจำนวนของ --parallel slots ตัวเลขที่เผยแพร่ทั่วไปไม่สามารถใช้แทนการวัดค่าจากระบบของคุณเองได้ เพราะปริมาณการใช้ RAM ทั้งหมดขึ้นอยู่กับโมเดล, การทำ quantisation และ context ที่คุณกำหนด ให้รัน systemctl show llama-server -p MemoryCurrent ในขณะที่มีการส่ง request และใช้ตัวเลขที่คุณเห็นเป็นเกณฑ์

ทำไม /health ถึงคืนค่า 503 พร้อมข้อความ "Loading model"?

กระบวนการทำงานได้เริ่มขึ้นแล้วแต่ไฟล์โมเดลยังโหลดไม่เสร็จในหน่วยความจำ เซิร์ฟเวอร์จึงตอบกลับด้วย {"error":{"code":503,"message":"Loading model","type":"unavailable_error"}} นี่เป็นเรื่องปกติหลังจากรีสตาร์ททุกครั้ง และจะใช้เวลาเท่ากับระยะเวลาที่ใช้ในการอ่านไฟล์โมเดล ปัญหานี้จะเกิดขึ้นก็ต่อเมื่อไคลเอนต์หรือพร็อกซีมองว่าค่า 503 แรกนั้นคือความล้มเหลวของระบบ ให้ทำ polling ที่ /health จนกว่าจะได้รับค่าตอบกลับเป็น {"status": "ok" }

ฉันสามารถเปิดใช้งาน llama-server สู่สาธารณะโดยตรงได้หรือไม่?

ห้าม bind ไปที่ 0.0.0.0 แล้วเปิดพอร์ตโดยตรง เพราะระบบไม่มีการจัดการบัญชีผู้ใช้, ไม่มี rate limiting และไม่มี log ของ request ที่เพียงพอต่อการตรวจสอบ อีกทั้งการตรวจสอบความปลอดภัยในตัวมีเพียง --api-key ซึ่งเป็นการเปรียบเทียบข้อความสตริงเพียงชุดเดียวเท่านั้น ให้คงค่า default ที่ 127.0.0.1 ไว้ แล้วใช้ nginx วางไว้ด้านหน้าพร้อม TLS และตั้งค่า --api-key ไว้ด้วย เพื่อป้องกันไม่ให้ความผิดพลาดในการตั้งค่าพร็อกซีทำให้โมเดลของคุณถูกเปิดเผยต่อสาธารณะโดยไม่ตั้งใจ