Docker
Docker เป็นวิธีติดตั้งแบบระบบใช้งานจริงที่ง่ายที่สุดสำหรับเซิร์ฟเวอร์เครื่องเดียว
สำหรับการติดตั้งบนเซิร์ฟเวอร์เดียวที่เข้าถึงจากอินเทอร์เน็ต ให้เริ่มจาก การติดตั้งส่วนตัวจากระยะไกล เทมเพลต Compose ของคู่มือนั้นไม่เปิดพอร์ตแอป ใช้ image main เป็นค่าเริ่มต้น และเพิ่มขอบเขต Cloudflare Access ชั้นนอก การควบคุมโฮสต์ การสำรองข้อมูล และขีดจำกัดคอนเทนเนอร์
ความพร้อมใช้งานของ Work
Work เปิดอยู่ตามค่าเริ่มต้นในไฟล์ Compose ของ repository image มี Docker CLI และ Compose จะ mount /var/run/docker.sock ทำให้คอนเทนเนอร์งาน Work เป็นคอนเทนเนอร์ ระดับเดียวกัน กับคอนเทนเนอร์ Libre WebUI และปรากฏใน docker ps บนโฮสต์
โปรเซสที่เข้าถึง socket นี้มีสิทธิ์ควบคุมโฮสต์ Docker เทียบเท่า root การเปิด Work ตามค่าเริ่มต้นเป็นการตัดสินใจโดยเจตนา เพราะ Work เป็นฟีเจอร์หลักและทำงานไม่ได้หากไม่เข้าถึง daemon ผลคือ ผู้ดูแลระบบ Libre WebUI ทุกคนมีสิทธิ์เทียบเท่าผู้ดูแลโฮสต์ จึงควรวางแผนดังนี้:
- ใช้ชุดระบบนี้บนโฮสต์ที่คุณเชื่อถือผู้ดูแลอยู่แล้ว
- อย่าเปิดพอร์ตที่เผยแพร่ต่อเครือข่ายที่ไม่น่าเชื่อถือ
- เอา mount
/var/run/docker.sockออกเมื่อไม่ต้องใช้ Work จากนั้นหน้า Work จะแสดง Runtime unavailable
บน Linux socket เป็นของกลุ่ม docker แทน root ผู้ใช้แอปที่ไม่ใช่ root จึงต้องมี group id นั้น ตั้งค่าหนึ่งครั้ง:
echo "DOCKER_GID=$(docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
alpine stat -c '%g' /var/run/docker.sock)" >> .env
ให้อ่านค่าผ่านคอนเทนเนอร์ตามตัวอย่าง โฮสต์ macOS รายงานค่าต่างจากที่คอนเทนเนอร์เห็น เพราะ Docker Desktop ส่งต่อ socket ผ่าน VM หากกลุ่มไม่ถูกต้อง หน้า Work จะระบุปัญหาแทนการล้มเหลวโดยไม่แจ้ง ดู Work: พื้นที่ทำงานที่แยกออกจากกัน
พรีวิวของ Work และ Work Computer จะ publish พอร์ตแบบสุ่มเฉพาะบนอินเทอร์เฟซส่วนตัวของโฮสต์เท่านั้น Docker Desktop ทำงานได้ด้วยค่าเริ่มต้นของ Compose คือ bind กับ loopback ของโฮสต์ และใช้ host.docker.internal สำหรับการเชื่อมต่อจากแบ็กเอนด์ ส่วน Docker Engine แบบเนทีฟไม่สามารถเข้าถึง listener บน loopback ของโฮสต์จากคอนเทนเนอร์พี่น้องได้ ให้ตั้ง bind เป็นเกตเวย์ของ Docker bridge ที่ไม่เปิดสาธารณะแทน:
echo "WORK_PREVIEW_BIND=$(docker network inspect bridge \
--format '{{(index .IPAM.Config 0).Gateway}}')" >> .env
echo "WORK_DOCKER_PUBLISHED_HOST=host.docker.internal" >> .env
docker compose up -d --force-recreate libre-webui
ไฟล์ Compose แมป host.docker.internal ผ่าน host-gateway อย่าใช้ WORK_PREVIEW_BIND=0.0.0.0 เด็ดขาด เพราะจะเป็นการ publish พอร์ตงานชั่วคราวที่ไม่มีการยืนยันตัวตนบนทุกอินเทอร์เฟซของโฮสต์ แทนที่จะเก็บไว้หลัง proxy ที่มีลายเซ็นของ Libre WebUI
Ollama ที่มาพร้อมระบบ
รัน Libre WebUI และ Ollama ในชุด Compose เดียว:
docker compose up -d
พอร์ต WebUI จะ bind กับ loopback ของโฮสต์ตามค่าเริ่มต้น ตั้ง WEBUI_BIND_ADDRESS=0.0.0.0 เฉพาะเมื่อ LAN ที่เชื่อถือได้หรือ reverse proxy บนโฮสต์ต้องเข้าถึง และจำกัดพอร์ตด้วย firewall ของโฮสต์
Ollama ยังคงเป็นส่วนตัวภายในเครือข่าย Compose หากต้องการให้แอปบนโฮสต์เข้าถึงผ่าน loopback ให้เพิ่ม override สำหรับโฮสต์โดยตรง:
docker compose -f docker-compose.yml -f docker-compose.ollama-host.yml up -d
ตั้ง OLLAMA_BIND_ADDRESS เฉพาะเมื่อเครื่องอื่นต้องเข้าถึง Ollama และปกป้องพอร์ตนั้นด้วย firewall และ proxy ที่รองรับการยืนยันตัวตน
NVIDIA GPU
ใช้ไฟล์ Compose สำหรับ GPU เมื่อ Docker เข้าถึง runtime ของ NVIDIA ได้:
docker compose -f docker-compose.gpu.yml up -d
หากโมเดลยังรันบน CPU ให้ยืนยันการเข้าถึง GPU จากคอนเทนเนอร์ Ollama
Ollama ภายนอก
ใช้วิธีนี้เมื่อ Ollama ทำงานอยู่บนโฮสต์หรือเซิร์ฟเวอร์อื่นแล้ว:
docker compose -f docker-compose.external-ollama.yml up -d
เปลี่ยน URL ของ Ollama หากจำเป็น:
OLLAMA_BASE_URL=http://192.168.1.10:11434 docker compose -f docker-compose.external-ollama.yml up -d
Work ที่แยก socket
ไฟล์ Compose มาตรฐานจะ mount Docker socket เข้าในคอนเทนเนอร์ Libre WebUI เพื่อให้ Work รันคอนเทนเนอร์งานได้ ซึ่งให้สิทธิ์ควบคุมโฮสต์ Docker เทียบเท่า root หากต้องการใช้ Work โดยไม่มอบ socket ให้เว็บแอป ให้ใช้รูปแบบ socket-proxy:
docker compose -f docker-compose.socket-proxy.yml up -d
socket proxy บนเครือข่ายภายในจะถือ /var/run/docker.sock และส่งต่อเฉพาะส่วน API ที่ Work ใช้ (containers, images, volumes, networks, exec, info) ส่วน endpoint สำหรับ Swarm, secrets, configs, build และ system จะถูก proxy ปฏิเสธ Libre WebUI เข้าถึงผ่าน DOCKER_HOST=tcp://docker-socket-proxy:2375 โดยไม่ต้อง mount socket และไม่ต้องใช้ DOCKER_GID; terminal แบบโต้ตอบและการวินิจฉัยระบบยังทำงานเหมือนเดิม ดูเอกสาร Workspaces เพื่อทำความเข้าใจว่าขอบเขตนี้ครอบคลุมและไม่ครอบคลุมอะไร
การเก็บข้อมูลถาวร
Libre WebUI เก็บข้อมูล backend ที่ /app/backend/data ภายในคอนเทนเนอร์ ไฟล์ Compose จะ mount เส้นทางนี้เป็น named volume
เมื่อเปิด image โดยตรงด้วย docker run ระบบก็ใช้เส้นทางนี้ตามค่าเริ่มต้น ส่วนพื้นที่ชั่วคราวสำหรับตรวจฐานข้อมูลก่อนเริ่มจะอยู่แยกที่ /app/backend/temp ให้ mount /app/backend/data ทุกครั้งที่อาจสร้างคอนเทนเนอร์ใหม่
สำหรับระบบใช้งานจริง ให้ตั้ง secret ที่คงที่:
JWT_SECRET=replace-with-a-long-random-secret
ENCRYPTION_KEY=replace-with-64-hex-characters
สำรอง volume ข้อมูลและคีย์เข้ารหัสพร้อมกัน
ก่อนลบคอนเทนเนอร์ที่เปิดโดยตรงจาก image รุ่นเก่า ให้ยืนยันว่า /app/backend/data/.encryption_key มีอยู่ หรือบันทึก ENCRYPTION_KEY ที่กำหนดไว้ image รุ่นเก่าอาจเขียนคีย์ที่สร้างอัตโนมัติไว้เฉพาะในชั้นคอนเทนเนอร์ การลบคอนเทนเนอร์นั้นจึงลบคีย์เพียงชุดเดียวที่ถอดรหัสฐานข้อมูลถาวรได้
หากคุณใช้ runtime ที่รองรับ Work แบบกำหนดเอง ไฟล์งานจะอยู่ใน Docker named volume แยกและไม่รวมอยู่ในการสำรอง /app/backend/data ปกติ
การเข้าถึงสาธารณะ
ไฟล์ Compose ใน repository จะ bind WebUI กับ loopback และตั้ง CORS_ORIGIN โดยตรง ค่าใน shell หรือไฟล์ .env ของคุณจะไม่แทนค่าคงที่นั้น ให้แก้รายการ libre-webui.environment หรือบันทึก override ที่ชัดเจนเป็น compose.origin.yml:
services:
libre-webui:
environment:
CORS_ORIGIN: https://your-domain.example
BASE_URL: https://your-domain.example
ใช้ override พร้อมกับไฟล์ Compose ของ repository ที่เลือก:
docker compose -f docker-compose.yml -f compose.origin.yml up -d
จากนั้นวาง Libre WebUI ไว้หลัง HTTPS ด้วย reverse proxy หรือ load balancer ของแพลตฟอร์ม ตั้ง WEBUI_BIND_ADDRESS เป็นอินเทอร์เฟซที่ proxy ต้องใช้โดยตรง อย่าเปิดพอร์ตบนทุกอินเทอร์เฟซ เว้นแต่ firewall จำเป็นต้องใช้
เซิร์ฟเวอร์ให้บริการ frontend ที่ build แล้วอย่างมีประสิทธิภาพอยู่แล้ว บันเดิลที่มี hash ใต้ /js/ และ /assets/ ถูกส่งแบบบีบอัด brotli หรือ gzip พร้อมอายุแคช immutable หนึ่งปี ขณะที่ index.html และ service worker ถูกกำกับเป็น no-cache เพื่อให้รับรุ่นใหม่ได้ในการโหลดครั้งถัดไป proxy จึงไม่จำเป็นต้องบีบอัดซ้ำหรือแคชเส้นทางเหล่านั้น ให้ส่งผ่าน Accept-Encoding ไปตามเดิม
คำสั่งที่มีประโยชน์
docker compose ps
docker compose logs -f libre-webui
docker compose logs -f ollama
docker compose pull
docker compose up -d