วิธีรัน Ollama ด้วย rootless Podman บน VPS อย่างปลอดภัย
เรียนรู้วิธีติดตั้ง Ollama บน VPS ผ่าน rootless Podman โดยใช้ Quadlet เพื่อให้ระบบทำงานหลังรีบูต พร้อมตั้งค่า SELinux และ SSH tunnel เพื่อความปลอดภัยสูงสุดของข้อมูล
การรัน Ollama ใน rootless Podman บน VPS
การรัน Ollama ใน rootless Podman บนเซิร์ฟเวอร์จำเป็นต้องมีเงื่อนไข 5 ประการที่ขั้นตอนการติดตั้งบนเดสก์ท็อปทั่วไปมักข้ามไป ได้แก่ ผู้ใช้ที่ไม่มีสิทธิ์พิเศษ (unprivileged user) เป็นเจ้าของคอนเทนเนอร์, เปิดใช้งาน lingering สำหรับผู้ใช้รายนั้นเพื่อให้คอนเทนเนอร์ทำงานต่อได้หลังจากคุณออกจากระบบ, ใช้ไฟล์ Quadlet เพื่อส่งต่อการจัดการคอนเทนเนอร์ให้ systemd เพื่อให้ระบบเริ่มทำงานใหม่ได้เองหลังรีบูต, ไดเรกทอรีโมเดลต้องมี SELinux label ที่ถูกต้องในดิสทริบิวชันที่มีการบังคับใช้ และ API ต้องฟังเฉพาะบน loopback เท่านั้น โดยคุณจะเข้าถึงผ่าน SSH (secure shell) tunnel
Ollama เป็นเซิร์ฟเวอร์สำหรับโมเดลภาษาขนาดใหญ่ (LLM) โดยจะจัดเก็บน้ำหนักของโมเดลไว้ในดิสก์ โหลดเข้าสู่หน่วยความจำ และตอบสนองคำขอ HTTP บนพอร์ต 11434 เนื่องจากไม่มีระบบล็อกอิน ไม่มี API key และไม่มีบัญชีผู้ใช้ การควบคุมผ่านเครือข่ายจึงเป็นวิธีเดียวในการจัดการสิทธิ์การเข้าถึง Podman รันคอนเทนเนอร์โดยไม่มี daemon และไม่มีสิทธิ์ root ดังนั้นหากมีสิ่งใดหลุดรอดออกมาจากคอนเทนเนอร์ สิ่งนั้นจะเริ่มต้นด้วยสิทธิ์ของผู้ใช้ทั่วไปที่ไม่มีสิทธิ์พิเศษ หากคุณต้องการเปรียบเทียบรันไทม์ก่อน โปรดอ่าน ความแตกต่างระหว่าง Podman และ Docker บน VPS หากคุณต้องการหลีกเลี่ยงการใช้คอนเทนเนอร์โดยสิ้นเชิง การติดตั้ง Ollama โดยตรงบน VPS เป็นทางเลือกที่สั้นกว่า
SSD Nodes มี Fedora ให้เลือกใช้ในอิมเมจ ซึ่ง Fedora มาพร้อมกับ Podman และ SELinux (security-enhanced Linux) เป็นค่าเริ่มต้น คำสั่งทั้งหมดด้านล่างนี้สามารถรันได้บนทุกดิสทริบิวชันที่ใช้ Podman เวอร์ชัน 5 ขึ้นไป
เหตุผลที่เวอร์ชันสำหรับแล็ปท็อปต้องมีการปรับเปลี่ยนเมื่อนำมาใช้บนเซิร์ฟเวอร์
Fedora Magazine ได้เผยแพร่บทความแนะนำการใช้งาน stack นี้อย่างชัดเจนเมื่อวันที่ 5 สิงหาคม 2026 ในหัวข้อ Running Ollama Locally with Podman on Fedora Linux โดย Yazan Monshed ซึ่งเป็นจุดเริ่มต้นที่ดีในการทำความรู้จักกับเครื่องมือเหล่านี้ อย่างไรก็ตาม บทความดังกล่าวมุ่งเน้นไปที่การใช้งานบนแล็ปท็อป และมี 4 ประเด็นที่ส่งผลแตกต่างออกไปเมื่อนำไปใช้บนเครื่องที่มี Public IP address:
- การเริ่ม container ด้วยคำสั่ง
podman run -dแบบปกติ: container ที่เริ่มด้วยวิธีนี้จะไม่กลับมาทำงานใหม่หลังจาก reboot เพราะไม่มีการกำหนดค่าให้ระบบเริ่มทำงานอัตโนมัติ - การใช้ tag แบบเปลี่ยนแปลงได้
ollama/ollama: บนแล็ปท็อป คุณจะสังเกตเห็นทันทีเมื่อพฤติกรรมของโปรแกรมเปลี่ยนไป แต่บนเซิร์ฟเวอร์ สัญญาณแรกที่คุณจะพบคือสคริปต์ที่หยุดทำงานไปเองในชั่วข้ามคืน - การเผยแพร่บริการด้วย
-p 11434:11434: ซึ่งเป็นการผูกพอร์ตเข้ากับทุก interface หากอยู่หลัง home router บริการนี้จะเข้าถึงจากอินเทอร์เน็ตไม่ได้ แต่หากอยู่บน VPS นี่จะเป็นการเปิด API สำหรับ inference สู่สาธารณะโดยไม่มีการตั้งรหัสผ่านป้องกัน - การรันด้วยสิทธิ์ของผู้ใช้งานทั่วไป: บนเซิร์ฟเวอร์ บัญชีผู้ใช้ที่เป็นเจ้าของ container ไม่ควรมีสิทธิ์เข้าถึงข้อมูลอื่น เพื่อป้องกันกรณีที่หากเกิดการเจาะระบบ (break-out) ผู้บุกรุกจะพบเพียง home directory ที่ว่างเปล่าเท่านั้น
สิ่งที่กล่าวมาข้างต้นไม่ใช่เรื่องผิดสำหรับการใช้งานบนเครื่องที่บทความตั้งใจไว้ แต่ละประเด็นเป็นเพียงการตัดสินใจที่คุณต้องทบทวนใหม่เมื่อเครื่องเซิร์ฟเวอร์สามารถเข้าถึงได้จากทุกที่และไม่มีผู้ดูแลนั่งใช้งานอยู่หน้าเครื่องโดยตรง
สร้างผู้ใช้ที่ไม่มีสิทธิ์ (unprivileged user) และตรวจสอบ subuid
Rootless Podman จะแมป UID ภายในคอนเทนเนอร์เข้ากับช่วงของ ID ที่ไม่ได้ใช้งานบนโฮสต์ โดยช่วงดังกล่าวจะถูกประกาศไว้ใน /etc/subuid และ /etc/subgid หากไม่มีการตั้งค่านี้ คอนเทนเนอร์แบบ rootless จะไม่สามารถเริ่มทำงานได้เลย
sudo dnf install -y podman # or: sudo apt install -y podman
sudo useradd --create-home --shell /bin/bash --comment "Ollama container owner" ollama
sudo passwd --lock ollama
grep ollama /etc/subuid /etc/subgidคำสั่ง grep ควรแสดงผลลัพธ์สองบรรทัด โดยมาจากแต่ละไฟล์ และแต่ละบรรทัดต้องระบุช่วงของ ID จำนวน 65536 ค่า:
/etc/subuid:ollama:100000:65536
/etc/subgid:ollama:100000:65536ตัวเลขเริ่มต้นของคุณอาจแตกต่างกันไป ซึ่งถือเป็นเรื่องปกติ หาก grep ไม่แสดงผลลัพธ์ใดๆ แสดงว่า useradd ไม่ได้จัดสรรช่วง ID ไว้ และคำสั่ง podman แรกในฐานะผู้ใช้นั้นจะล้มเหลวในลักษณะนี้:
Error: cannot find UID/GID for user ollama: no subuid ranges found for user "ollama" in /etc/subuidให้กำหนดช่วง ID ที่ไม่มีผู้ใช้อื่นถือครองอยู่ จากนั้นแจ้งให้ Podman ทราบว่าการแมปเดิมนั้นล้าสมัยแล้ว:
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 ollama
sudo -iu ollama podman system migrateการล็อกรหัสผ่านหมายความว่าจะไม่มีใครสามารถล็อกอินในฐานะ ollama ได้โดยตรง คุณสามารถเข้าถึงบัญชีนี้ได้จากผู้ดูแลระบบของคุณด้วยคำสั่ง sudo -iu ollama
เปิดใช้งาน lingering เพื่อให้ service ทำงานต่อได้หลังออกจากระบบ
instance ของ systemd สำหรับผู้ใช้โดยปกติจะเริ่มทำงานเมื่อล็อกอินและหยุดทำงานเมื่อล็อกเอาต์ ซึ่ง /run/user/<uid> จะถูกลบออกไปพร้อมกัน ส่งผลให้ rootless container ทุกตัวที่ผู้ใช้เป็นเจ้าของหยุดทำงานทันที การเปิดใช้งาน lingering จะช่วยให้ instance ของผู้ใช้ยังคงทำงานอยู่แม้ไม่มี session เชื่อมต่ออยู่ก็ตาม
sudo loginctl enable-linger ollama
loginctl show-user ollama --property=Lingerคำสั่งดังกล่าวควรแสดงผลเป็น Linger=yes ให้เปิดใช้งานก่อนสร้าง unit เนื่องจากไดเรกทอรีที่ unit จำเป็นต้องใช้คือ /run/user/<uid> จะถูกสร้างขึ้นก็ต่อเมื่อเปิดใช้งาน lingering แล้วเท่านั้น
ยังมีอีกหนึ่งขั้นตอนที่มักถูกมองข้าม sudo -iu ollama จะให้ shell แก่คุณแต่ไม่ใช่ session bus ส่งผลให้ systemctl --user ล้มเหลวทันที:
Failed to connect to bus: $DBUS_SESSION_BUS_ADDRESS and $XDG_RUNTIME_DIR not definedsystemd จะค้นหา user bus ที่ $XDG_RUNTIME_DIR/bus แต่ sudo -i ไม่ได้ตั้งค่าตัวแปรดังกล่าวไว้ ให้ตั้งค่าด้วยตนเองในทุก admin shell ที่คุณใช้จัดการ service นี้:
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user statusตำแหน่งที่เก็บไฟล์โมเดลและพื้นที่ดิสก์ที่ต้องเตรียม
Ollama จะเขียนไฟล์น้ำหนัก (weights) ลงใน /root/.ollama/models ภายในคอนเทนเนอร์ หากคุณทำการ bind directory จากโฮมไดเรกทอรีของผู้ใช้ไปยัง path ดังกล่าว ไฟล์จะถูกเก็บไว้ในตำแหน่งที่คุณสามารถตรวจสอบขนาดได้คือ /home/ollama/ollama-data/models โดยไฟล์ blob จะถูกเก็บไว้ใน models/blobs ในรูปแบบไฟล์ที่อ้างอิงตามเนื้อหา (content-addressed) และ models/manifests จะเก็บดัชนีขนาดเล็กที่ใช้ระบุชื่อไฟล์เหล่านั้น หากคุณใช้ named volume ตามที่ระบุในบทความของ Fedora Magazine โครงสร้างไฟล์เดียวกันนี้จะอยู่ใน /home/ollama/.local/share/containers/storage/volumes/<volume>/_data ไม่ว่าจะใช้วิธีใด ทั้ง ollama pull และ ollama run ต่างก็เขียนไฟล์น้ำหนักลงในโครงสร้างเดียวกัน และสิ่งที่ แยกคำสั่งทั้งสองออกจากกัน มีเพียงแค่ว่าเซสชันการแชทจะเปิดขึ้นทันทีหลังจากดาวน์โหลดเสร็จสิ้นหรือไม่
ควรคำนวณขนาดดิสก์ก่อนเริ่มดาวน์โหลดโมเดลใดๆ โดยขนาดไฟล์ที่ประกาศไว้คือค่าขั้นต่ำที่คุณต้องเตรียม
The data behind this chart
[
{
"label": "gemma3:4b",
"download_gb": 3.3
},
{
"label": "mistral:7b",
"download_gb": 4.4
},
{
"label": "qwen3:8b",
"download_gb": 5.2
},
{
"label": "gemma3:12b",
"download_gb": 8.1
},
{
"label": "qwen3:14b",
"download_gb": 9.3
},
{
"label": "gemma3:27b",
"download_gb": 17
},
{
"label": "qwen3:30b",
"download_gb": 19
}
]ข้อมูลใน 7 แถวทั้งหมดเป็นตัวเลขที่เผยแพร่บน ollama.com/library ไม่ใช่ขนาดที่วัดจริงบนดิสก์ แท็กที่เล็กที่สุดในที่นี้คือ gemma3:4b ซึ่งมีขนาดดาวน์โหลด 3.3 GB ส่วนแท็กที่ใหญ่ที่สุดคือ qwen3:30b มีขนาดดาวน์โหลด 19 GB ตัวอิมเมจคอนเทนเนอร์เองจะถูกเก็บแยกต่างหากในพื้นที่จัดเก็บของ Podman ดังนั้นควรตรวจสอบตัวเลขทั้งสองส่วนร่วมกันด้วย podman system df และ df -h /home นอกจากนี้ โมเดลยังต้องการ RAM ในปริมาณที่ใกล้เคียงกับขนาดไฟล์ขณะที่โหลดใช้งาน บวกกับพื้นที่สำหรับ context window ดังนั้นโมเดลขนาด 19 GB จึงไม่สามารถรันบน VPS ที่มี RAM 16 GB ได้
ตรึงเวอร์ชันของ image tag และระบุชื่อ registry ให้ครบถ้วน
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
mkdir -p ~/ollama-data ~/.config/containers/systemd
podman pull docker.io/ollama/ollama:0.32.9ให้ใช้ tag ของเวอร์ชันที่ปล่อยออกมาแล้ว เช่น 0.32.9 ณ เดือนสิงหาคม 2026 และไม่ควรใช้ latest การตรึง tag ไว้จะช่วยให้มั่นใจได้ว่าเมื่อมีการรีสตาร์ทระบบในเวลา 04:00 น. คุณจะได้ binary ตัวเดิมที่คุณเคยทดสอบไว้ ดังนั้นหากพฤติกรรมของระบบเปลี่ยนไป นั่นหมายความว่าเกิดจากการเปลี่ยนแปลงที่คุณทำเอง Docker Hub ยังมีการเผยแพร่ tag -rc และ -rocm สำหรับเวอร์ชันเดียวกัน ให้เลือกใช้ tag แบบปกติเว้นแต่ว่าคุณจะใช้งาน AMD GPU
นอกจากนี้ให้ระบุชื่อ host ของ registry ด้วย บน Fedora หากใช้ชื่อแบบย่อใน systemd unit จะไม่มี terminal สำหรับแสดงข้อความแจ้งเตือน ทำให้ unit ล้มเหลวด้วยข้อความดังนี้:
Error: short-name "ollama/ollama" did not resolve to an alias and no unqualified-search registries are definedการดึง image ด้วยตนเองก่อนเป็นขั้นตอนที่ไม่บังคับ แต่มีประโยชน์เพราะช่วยแยกการดาวน์โหลดไฟล์ขนาดหลายกิกะไบต์ออกจากช่วงเวลา timeout ในการเริ่มทำงานของ unit
Quadlet unit ที่คงอยู่หลังการรีบูต
Quadlet คือตัวสร้าง systemd ของ Podman คุณเขียนไฟล์ .container แล้ว systemd จะเปลี่ยนไฟล์นั้นให้เป็น service ในขณะบูตเครื่อง ทำให้ไม่จำเป็นต้องใช้ podman generate systemd อีกต่อไป ให้บันทึกไฟล์นี้เป็น /home/ollama/.config/containers/systemd/ollama.container โดยกำหนดให้ผู้ใช้ ollama เป็นเจ้าของ
[Unit]
Description=Ollama API (rootless)
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/ollama/ollama:0.32.9
ContainerName=ollama
PublishPort=127.0.0.1:11434:11434
Volume=/home/ollama/ollama-data:/root/.ollama:Z
Environment=OLLAMA_KEEP_ALIVE=30m
Environment=OLLAMA_MAX_LOADED_MODELS=1
[Service]
Restart=always
TimeoutStartSec=900
[Install]
WantedBy=default.targetชื่อไฟล์จะเป็นตัวกำหนดชื่อของ service ดังนั้น ollama.container จะกลายเป็น ollama.service
systemctl --user daemon-reload
systemctl --user start ollama.service
systemctl --user status ollama.servicestatus ควรแสดงผลเป็น active (running) ห้ามรันคำสั่ง systemctl --user enable ollama.service เนื่องจาก unit นี้ไม่มีไฟล์อยู่บนดิสก์ systemd จึงปฏิเสธการทำงาน:
Failed to enable unit: Unit file /run/user/1001/systemd/generator/ollama.service is transient or generated.ส่วน [Install] ทำหน้าที่นั้นอยู่แล้ว Quadlet จะสร้างลิงก์สำหรับเริ่มทำงานตอนบูตด้วยตัวเองในระหว่างขั้นตอน daemon-reload ซึ่งเป็นเหตุผลว่าทำไมคำสั่งนั้นจึงไม่ใช่ทางเลือกเสริม TimeoutStartSec=900 ครอบคลุมถึงการเริ่มทำงานครั้งแรกที่ยังต้องดึง image มาใช้งาน เนื่องจากค่าเริ่มต้น 90 วินาทีไม่เพียงพอสำหรับการดาวน์โหลดไฟล์ขนาด 2 กิกะไบต์ และ systemd จะยุติการทำงานโดยระบุว่าล้มเหลว OLLAMA_KEEP_ALIVE=30m จะคงโมเดลไว้ในหน่วยความจำระหว่างการร้องขอ แทนที่จะยกเลิกการโหลดหลังจากผ่านไป 5 นาที โดยสามารถดูข้อดีข้อเสียได้ที่ การคงโมเดล Ollama ไว้ในหน่วยความจำ หากคำศัพท์ของ systemd ที่ใช้ในที่นี้เป็นเรื่องใหม่ คุณสามารถศึกษาเพิ่มเติมได้ที่ วิธีการทำงานของ systemd service และ timer บน VPS ซึ่งครอบคลุมถึงตัว unit ต่างๆ ไว้แล้ว
เหตุใดไดเรกทอรีโมเดลจึงแจ้งว่า permission denied ภายใต้ SELinux
บน Fedora, RHEL, Rocky และ AlmaLinux นั้น SELinux จะถูกเปิดใช้งาน (enforcing) เป็นค่าเริ่มต้น กระบวนการทำงานของคอนเทนเนอร์จะรันอยู่ในโดเมน container_t ในขณะที่ไดเรกทอรีในโฮมไดเรกทอรีของผู้ใช้จะถูกติดป้ายกำกับ (label) เป็น user_home_t นโยบายความปลอดภัยไม่อนุญาตให้ทั้งสองส่วนเข้าถึงกันได้ ส่งผลให้ Ollama ไม่สามารถสร้างโครงสร้างโมเดลและคอนเทนเนอร์หยุดทำงาน getenforce จะแสดงผล Enforcing บนระบบเหล่านี้ และการปฏิเสธการเข้าถึงจะถูกบันทึกไว้ดังนี้:
sudo ausearch -m avc -ts recentคุณจะพบข้อความที่ระบุชื่อโดเมนและป้ายกำกับเป้าหมาย:
avc: denied { write } for pid=1842 comm="ollama" name="models" dev="vda1" ino=131077 scontext=system_u:system_r:container_t:s0:c214,c827 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=dir permlisted=0การเติม :Z ไว้ที่ท้ายบรรทัด Volume= คือวิธีแก้ไข โดยจะเป็นการเปลี่ยนป้ายกำกับของไดเรกทอรีบนโฮสต์ให้เป็น container_file_t และประทับตราด้วยหมวดหมู่ MCS (multi-category security) ส่วนตัวที่เฉพาะคอนเทนเนอร์นี้เท่านั้นที่ถือครองอยู่ ส่วน :z ตัวพิมพ์เล็กจะใช้ป้ายกำกับแบบแชร์ ซึ่งเป็นสิ่งที่คุณต้องการเมื่อมีคอนเทนเนอร์สองตัวอ่านไดเรกทอรีเดียวกัน
ข้อควรระวังเกี่ยวกับ :Z คือมันเป็นการทำงานที่ทำลายข้อมูลเดิมและไม่มีการแจ้งเตือน การเปลี่ยนป้ายกำกับจะทำงานแบบวนซ้ำ (recursive) หากคุณชี้ไปที่ /home/ollama ไฟล์ทุกไฟล์ในโฮมไดเรกทอรีนั้นจะถูกเปลี่ยนป้ายกำกับทั้งหมด ซึ่งจะทำให้การเข้าถึงผ่าน SSH key ของผู้ใช้นั้นใช้งานไม่ได้ ควรระบุ :Z ให้เป็นไดเรกทอรีย่อยที่แยกออกมาโดยเฉพาะและไม่มีข้อมูลอื่นปะปน สำหรับ Named volumes ไม่จำเป็นต้องใช้ตัวเลือกนี้เนื่องจาก Podman จะติดป้ายกำกับให้อย่างถูกต้องเมื่อสร้างขึ้น หากคุณต้องการทำความเข้าใจในภาพรวม พื้นฐาน SELinux สำหรับเซิร์ฟเวอร์ จะอธิบายเกี่ยวกับบริบท (contexts) และค่าบูลีน (booleans) ไว้ สำหรับ Ubuntu และ Debian จะใช้ AppArmor แทน ซึ่ง :Z จะไม่มีผลใดๆ ในระบบเหล่านั้น และการคงไว้ใน unit file ก็ไม่ก่อให้เกิดอันตรายแต่อย่างใด
ปิดพอร์ต 11434 และเข้าถึง API ผ่าน SSH
PublishPort=127.0.0.1:11434:11434 จะผูกฝั่งโฮสต์เข้ากับ loopback ให้ตรวจสอบดังนี้:
ss -ltnp | grep 11434
curl http://127.0.0.1:11434ผลลัพธ์ของ ss ต้องแสดง 127.0.0.1:11434 หากเป็น 0.0.0.0:11434 หรือ *:11434 หมายความว่าพอร์ตเปิดรับการเชื่อมต่อจากอินเทอร์เน็ต และ curl จะต้องตอบกลับเป็น Ollama is running
โปรดระบุฝั่งที่ต้องการผูกให้ชัดเจน ที่อยู่ภายใน PublishPort คือที่อยู่ของโฮสต์ ภายในคอนเทนเนอร์ Ollama ต้องฟังการเชื่อมต่อบนทุกอินเทอร์เฟซตามค่าเริ่มต้นของอิมเมจ การตั้งค่า Environment=OLLAMA_HOST=127.0.0.1 จะเป็นการผูก Ollama เข้ากับ loopback ของคอนเทนเนอร์เอง และ Podman จะส่งต่อทราฟฟิกที่เผยแพร่ไปยังที่อยู่เครือข่ายของคอนเทนเนอร์แทน ส่งผลให้ทุกคำขอถูกปฏิเสธแม้จะมาจากโฮสต์ก็ตาม
การเปิดพอร์ต 11434 ทิ้งไว้สร้างความเสียหายสองทาง Ollama ไม่มีการตรวจสอบสิทธิ์ ดังนั้นใครก็ตามที่เข้าถึงพอร์ตนี้ได้สามารถแสดงรายการโมเดลของคุณผ่าน /api/tags, รันการอนุมาน (inference) โดยใช้ CPU และโควตาแบนด์วิดท์ของคุณผ่าน /api/generate, ดึงโมเดลใหม่ลงดิสก์ของคุณ และลบโมเดลที่คุณมีอยู่ได้ ประการที่สอง การใช้ HTTP แบบปกติไปยังพอร์ตระยะไกลจะส่ง prompt และผลลัพธ์ในรูปแบบข้อความธรรมดา (cleartext) ทำให้ทุกเครื่องที่อยู่ระหว่างทางสามารถอ่านข้อมูลได้ ปัญหาทั้งสองจะหมดไปหากพอร์ตไม่ถูกเปิดออกสู่ภายนอกเครื่อง
จากเวิร์กสเตชันของคุณ ให้ส่งต่อพอร์ตผ่าน SSH:
ssh -N -L 11434:127.0.0.1:11434 you@vps.example.comตอนนี้ http://127.0.0.1:11434 บนแล็ปท็อปของคุณคือ Ollama ของเซิร์ฟเวอร์ ซึ่งอยู่ภายใต้การเข้ารหัสของเซสชัน SSH หากแล็ปท็อปของคุณรัน Ollama อยู่แล้ว การผูกพอร์ตในเครื่องจะล้มเหลวด้วยข้อความ bind [127.0.0.1]:11434: Address already in use ให้ใช้ -L 11435:127.0.0.1:11434 แทนและชี้ไคลเอนต์ของคุณไปที่พอร์ต 11435
เมื่อไคลเอนต์เบราว์เซอร์จำเป็นต้องใช้งาน ให้ใช้ reverse proxy ที่มีการป้องกันด้วยรหัสผ่านวางไว้ด้านหน้าแทน บล็อกไซต์ของ Caddy มีความยาวเพียงสี่บรรทัด และ caddy hash-password จะพิมพ์ค่า bcrypt hash ที่ต้องการออกมา:
ollama.example.com {
basic_auth {
you $2a$14$replace_with_the_generated_hash
}
reverse_proxy 127.0.0.1:11434
}Caddy จะขอใบรับรองผ่าน TLS (transport layer security) โดยอัตโนมัติ ทำให้ทราฟฟิกถูกเข้ารหัส ทดสอบไคลเอนต์ของคุณก่อน: เครื่องมือจำนวนมากที่สื่อสารกับ Ollama ไม่มีช่องสำหรับใส่ header Authorization และจะล้มเหลวเมื่อเจอกับ basic auth ที่มีเพียง 401 Unauthorized เปล่าๆ อุโมงค์ SSH ไม่มีปัญหานี้ ซึ่งเป็นเหตุผลว่าทำไมจึงเป็นวิธีที่แนะนำเป็นค่าเริ่มต้นในที่นี้
ดึงโมเดลและตรวจสอบพาธทั้งหมด
podman exec -it ollama ollama pull gemma3:4b
curl -s http://127.0.0.1:11434/api/tags
curl -s http://127.0.0.1:11434/api/generate -d '{"model":"gemma3:4b","prompt":"Reply with the single word: ready","stream":false}'
du -sh ~/ollama-data/models/api/tags จะส่งคืนรายการ JSON ของ gemma3:4b ส่วน /api/generate จะส่งคืนออบเจกต์ JSON ที่มีฟิลด์ response หลังจากหยุดรอช่วงหนึ่งในขณะที่โหลดน้ำหนัก (weights) จากดิสก์ โดย du ควรรายงานตัวเลขที่ใกล้เคียงกับขนาดไฟล์ดาวน์โหลดที่ระบุไว้ จากนั้นให้พิสูจน์ส่วนที่เป็นหัวใจสำคัญของคู่มือฉบับนี้:
sudo reboot
# reconnect, then:
sudo -iu ollama
export XDG_RUNTIME_DIR=/run/user/$(id -u)
systemctl --user is-active ollama.serviceactive หมายถึงการคงอยู่ (lingering) ซึ่งแสดงว่าส่วน [Install] และ daemon-reload ทำงานตามหน้าที่เรียบร้อยแล้ว หากขึ้น inactive แสดงว่าหนึ่งในสามส่วนประกอบดังกล่าวขาดหายไป
รูปแบบความล้มเหลวและข้อความที่คุณจะพบ
คอนเทนเนอร์หายไปหลังจากรีบูต ให้ตรวจสอบ loginctl show-user ollama --property=Linger ก่อน เพราะหากไม่มี Linger=yes อินสแตนซ์ systemd ของผู้ใช้จะไม่เริ่มทำงานตอนบูต หากเปิดใช้งาน lingering แล้ว แต่ส่วน [Install] หายไปจากไฟล์ .container หรือคุณแก้ไขไฟล์แล้วแต่ไม่ได้รัน systemctl --user daemon-reload
Error: statfs /home/ollama/ollama-data: no such file or directory แหล่งที่มาของ bind mount ต้องมีอยู่จริงก่อนที่คอนเทนเนอร์จะเริ่มทำงาน Podman จะไม่สร้างไดเรกทอรีบนโฮสต์ให้คุณ ให้รัน mkdir -p ~/ollama-data ในฐานะผู้ใช้ ollama
การเริ่มทำงานล้มเหลวที่ 90 วินาที journalctl --user -u ollama.service แสดง Start operation timed out. Terminating. เนื่องจากกระบวนการดึงอิมเมจยังคงทำงานอยู่ ให้ดึงอิมเมจด้วยตนเอง หรือคงค่า TimeoutStartSec=900 ไว้
คอนเทนเนอร์เริ่มทำงานแล้วหยุดทันที podman logs ollama และ sudo ausearch -m avc -ts recent จะบอกคุณได้ว่าเกิดจาก SELinux label หรือไม่ หากพบ AVC ที่ระบุชื่อ container_t และ user_home_t แสดงว่า :Z หายไป
คำขอถูกปฏิเสธจากโฮสต์ curl: (7) Failed to connect to 127.0.0.1 port 11434: Connection refused พร้อมบริการ active มักหมายความว่า OLLAMA_HOST ถูกตั้งค่าเป็น loopback address ภายในคอนเทนเนอร์ ให้ลบบรรทัดนั้นออก
การสร้างข้อมูลช้ามาก หรือคอนเทนเนอร์ถูกสั่งปิด หากไม่มี GPU การประมวลผล inference จะทำงานบน CPU ซึ่งโมเดลขนาดใหญ่จะทำงานช้าโดยธรรมชาติ หากคอนเทนเนอร์หยุดทำงานระหว่างประมวลผลคำขอและพบ signal: killed ใน log แสดงว่า kernel สั่งปิดการทำงานเนื่องจากหน่วยความจำไม่เพียงพอ (OOM killer) ให้เลือก tag ที่มีขนาดเล็กลงจากตารางด้านบน
การอัปเดตอิมเมจที่ถูกตรึงเวอร์ชันไว้ (Pinned image)
การตรึงเวอร์ชันหมายความว่าการอัปเดตเป็นสิ่งที่คุณต้องดำเนินการเอง ไม่ใช่สิ่งที่เกิดขึ้นโดยอัตโนมัติ ให้แก้ไข Image= ใน ollama.container จากนั้นทำการโหลด config ใหม่และรีสตาร์ทบริการ:
systemctl --user daemon-reload
systemctl --user restart ollama.service
podman exec ollama ollama --versionโมเดลต่างๆ จะถูกเก็บไว้ใน bind mount ดังนั้นข้อมูลจะยังคงอยู่ครบถ้วนแม้จะเปลี่ยนอิมเมจไปแล้ว ส่วน AutoUpdate=registry ในส่วน [Container] นั้นมีไว้สำหรับผู้ที่ใช้งานแท็กแบบเปลี่ยนแปลงได้ (moving tag) ซึ่งจะไม่มีประโยชน์หากใช้คู่กับแท็กเวอร์ชันที่ระบุตายตัว เนื่องจากเนื้อหาของแท็กนั้นจะไม่เปลี่ยนแปลง ให้สำรองข้อมูล /home/ollama/ollama-data/models/manifests และไฟล์ .container ไว้ โดยไม่จำเป็นต้องสำรองข้อมูล blobs เนื่องจากมีขนาดใหญ่และ ollama pull จะดาวน์โหลดข้อมูลเหล่านั้นใหม่อีกครั้งเมื่อติดตั้งบนเครื่องใหม่
FAQ
ทำไมคอนเทนเนอร์ Podman แบบ rootless ของฉันถึงหยุดทำงานเมื่อฉันออกจากระบบ?
อินสแตนซ์ systemd ของผู้ใช้และไดเรกทอรี /run/user/<uid> จะถูกปิดการทำงานเมื่อเซสชันสุดท้ายของผู้ใช้สิ้นสุดลง ส่งผลให้คอนเทนเนอร์แบบ rootless ทั้งหมดหยุดทำงานตามไปด้วย ให้รันคำสั่ง sudo loginctl enable-linger ollama และตรวจสอบว่า loginctl show-user ollama --property=Linger แสดงผลลัพธ์เป็น Linger=yes ทั้งนี้คุณต้องเปิดใช้งาน lingering ก่อนที่จะสร้าง Quadlet unit เนื่องจากไดเรกทอรีรันไทม์ที่ unit จำเป็นต้องใช้จะถูกสร้างขึ้นก็ต่อเมื่อเปิดใช้งาน lingering แล้วเท่านั้น
ฉันจำเป็นต้องติดป้ายกำกับ SELinux บนไดเรกทอรีโมเดลของ Ollama หรือไม่?
สำหรับ Fedora, RHEL, Rocky และ AlmaLinux จำเป็นต้องทำหากคุณทำการ bind mount ไดเรกทอรีจากโฮสต์ คอนเทนเนอร์จะทำงานภายใต้โดเมน container_t ในขณะที่ไดเรกทอรีในโฮมโฟลเดอร์มักถูกติดป้ายกำกับเป็น user_home_t ทำให้การเขียนข้อมูลถูกปฏิเสธและ Ollama จะหยุดทำงาน ให้เพิ่ม :Z ต่อท้ายบรรทัด Volume= และกำหนดให้ใช้ไดเรกทอรีย่อยเฉพาะเจาะจง เนื่องจากกระบวนการเปลี่ยนป้ายกำกับจะทำงานแบบ recursive หากคุณชี้ :Z ไปยังโฮมไดเรกทอรีทั้งหมดจะทำให้การเข้าถึงผ่าน SSH key ของผู้ใช้นั้นใช้งานไม่ได้ สำหรับ Named volumes นั้น Podman จะจัดการป้ายกำกับให้ถูกต้องโดยอัตโนมัติและไม่จำเป็นต้องตั้งค่าเพิ่มเติม
โมเดลของ Ollama ต้องการพื้นที่ดิสก์เท่าใด?
ให้เริ่มพิจารณาจากขนาดไฟล์ดาวน์โหลดที่ระบุบน ollama.com/library ซึ่งมีตั้งแต่ 3.3 GB สำหรับ gemma3:4b ไปจนถึง 19 GB สำหรับ qwen3:30b จากนั้นให้บวกขนาดของ Podman image เพิ่มเข้าไป และเผื่อพื้นที่ว่างไว้ด้วยเนื่องจากการดาวน์โหลดโมเดลใหม่จะไม่ไปแทนที่โมเดลเดิมบนดิสก์ ให้ตรวจสอบพื้นที่ด้วย df -h /home ก่อนทำการ pull และ du -sh ~/ollama-data/models หลังจากนั้น สำหรับหน่วยความจำ RAM ให้วางแผนในลักษณะเดียวกัน โดยโมเดลต้องการพื้นที่ในหน่วยความจำประมาณเท่ากับขนาดไฟล์โมเดล บวกกับพื้นที่สำหรับ context window
การเปิดพอร์ต 11434 บน VPS ปลอดภัยหรือไม่?
ไม่ปลอดภัย Ollama ไม่มีการติดตั้งระบบยืนยันตัวตนใดๆ ดังนั้นใครก็ตามที่เข้าถึงพอร์ตนี้ได้จะสามารถดูรายการโมเดลของคุณ ลบโมเดล ดาวน์โหลดโมเดลใหม่ลงในดิสก์ของคุณ รวมถึงรัน inference โดยใช้ CPU และโควตาแบนด์วิดท์ของคุณ นอกจากนี้การส่งข้อมูลผ่าน HTTP ปกติบนอินเทอร์เน็ตยังทำให้ prompt และผลลัพธ์ทั้งหมดถูกส่งเป็นข้อความธรรมดา (cleartext) ให้ผูกพอร์ตฝั่งโฮสต์ไว้ที่ 127.0.0.1 ด้วย PublishPort=127.0.0.1:11434:11434 ตรวจสอบความถูกต้องด้วย ss -ltnp | grep 11434 และเข้าถึงผ่าน SSH tunnel หรือ reverse proxy ที่มีการป้องกันด้วยรหัสผ่านเท่านั้น