วิธีติดตั้ง sandboxd บน VPS ของคุณเองแบบครบวงจร
เรียนรู้วิธีรัน sandboxd เครื่องมือสร้างแอปด้วย AI บน VPS ส่วนตัว ตั้งแต่การตั้งค่า Docker, Traefik v3, การจัดการ model keys ไปจนถึงการเคลียร์ sandbox ที่ค้างอยู่เพื่อประหยัดทรัพยากร
sandboxd คืออะไรและคุณจะได้อะไรจากการรันด้วยตนเอง
ในการ self-host sandboxd คุณต้องมีเซิร์ฟเวอร์ Linux หนึ่งเครื่องที่ติดตั้ง Docker และชื่อโดเมน เมื่อคุณส่ง prompt ตัว coding agent จะสร้างแอปพลิเคชันจริงขึ้นมาภายในคอนเทนเนอร์ที่แยกส่วน และแอปพลิเคชันนั้นจะปรากฏขึ้นที่ URL สำหรับดูตัวอย่าง (preview URL) ของตัวเอง เครื่องมือสร้างแอปจาก prompt เป็นหมวดหมู่บริการที่ได้รับความนิยมสูงสุดในปี 2026 และ sandboxd คือเครื่องมือที่คุณสามารถรันบน VPS ของคุณเองได้ภายใต้สัญญาอนุญาต MIT โดยที่โค้ดที่ถูกสร้างขึ้นจะถูกจัดเก็บไว้บนดิสก์ของคุณเอง
การออกแบบนี้มีขนาดเล็กโดยเจตนา โดยมี Go control plane ทำหน้าที่ควบคุม Docker, Traefik v3 ทำหน้าที่กำหนดเส้นทาง (route) ให้กับชื่อโฮสต์ของตัวอย่างแอปแต่ละรายการ, SQLite ทำหน้าที่เก็บสถานะ และแต่ละแอปจะรันอยู่ภายในหนึ่งคอนเทนเนอร์ ระบบนี้ไม่มี Kubernetes และไม่มีเซิร์ฟเวอร์ฐานข้อมูลแยกต่างหาก ซึ่งเป็นเหตุผลว่าทำไมเซิร์ฟเวอร์ขนาด 2 vCPU จึงสามารถรันระบบนี้ได้
โมเดลทั้งหมดขับเคลื่อนด้วยวัตถุ 4 ประเภท: app คือโปรเจกต์ที่คงอยู่ถาวร โดยเก็บชื่อ, ข้อมูล metadata ของ git และความลับ (secrets) ต่างๆ ไว้, sandbox คือคอนเทนเนอร์ Docker ที่แอปนั้นรันอยู่ โดยแอปหนึ่งตัวจะชี้ไปยัง sandbox ได้ทีละหนึ่งรายการ, workspace คือไฟล์ของแอปซึ่งอาศัยอยู่บนโฮสต์และยังคงอยู่แม้คอนเทนเนอร์จะหยุดทำงาน, และ task คือ prompt หนึ่งรายการที่ส่งให้กับ agent ภายใน sandbox การหยุด sandbox จะช่วยคืนหน่วยความจำแต่ยังคงเก็บไฟล์ไว้ ส่วนการทำลาย sandbox จะเป็นการลบคอนเทนเนอร์ทิ้ง ซึ่งแอปสามารถเริ่มการทำงานของคอนเทนเนอร์ใหม่ได้ในภายหลัง
sandboxd แตกต่างจาก Dify และ OpenHands อย่างไร
ทั้งสามโปรเจกต์นี้มักถูกเข้าใจผิดเนื่องจากต่างก็รัน LLM (large language model) บนเซิร์ฟเวอร์ของคุณ แต่ผลลัพธ์ที่ได้นั้นแตกต่างกัน Dify สร้างแอปพลิเคชัน LLM: เช่น อินเทอร์เฟซแชท, ไปป์ไลน์การดึงข้อมูล (retrieval pipelines) และเวิร์กโฟลว์ที่เรียกใช้โมเดลทุกครั้งที่มีการใช้งาน โดยตัวโมเดลจะเป็นส่วนหนึ่งของผลิตภัณฑ์สำเร็จรูปนั้น OpenHands ทำงานบน repository ที่คุณมีอยู่แล้ว: คุณระบุตำแหน่งโค้ดให้มัน จากนั้นมันจะอ่านไฟล์ รันคำสั่ง และเสนอการเปลี่ยนแปลง ส่วน sandboxd เริ่มต้นจากศูนย์ มันจะสร้างโครงร่างโปรเจกต์จากค่าที่ตั้งไว้ล่วงหน้า (preset) สร้างโปรเจกต์ในคอนเทนเนอร์ใหม่ และให้ URL เพื่อให้คุณเข้าชม ผลลัพธ์ที่ได้คือแอปพลิเคชัน React หรือ FastAPI ทั่วไปที่ไม่จำเป็นต้องใช้โมเดลในการรัน
ดังนั้น ให้เลือกตามสิ่งที่คุณต้องการในตอนท้าย sandboxd เหมาะสำหรับการเริ่มต้นจากประโยคคำสั่งและเก็บโค้ดไว้ใช้งานต่อ ส่วนอีกสองตัวเหมาะสำหรับกรณีที่มี repository หรือผลิตภัณฑ์ที่ขับเคลื่อนด้วยโมเดลอยู่แล้ว
ความแตกต่างอีกประการหนึ่งคืออายุของโปรเจกต์ ซึ่งเป็นสิ่งที่ควรพิจารณาก่อนที่จะสร้างสิ่งใดที่สำคัญบนโปรเจกต์นั้น
The data behind this chart
[
{
"tool": "sandboxd",
"github_stars": "875",
"forks": "50"
},
{
"tool": "OpenHands",
"github_stars": "83,091",
"forks": "10,711"
},
{
"tool": "Dify",
"github_stars": "151,320",
"forks": "23,886"
}
]sandboxd มีคะแนน 875 stars เทียบกับ 83,091 สำหรับ OpenHands และ 151,320 สำหรับ Dify ตัว repository ถูกสร้างขึ้นเมื่อวันที่ 3 มิถุนายน 2026 จึงมีอายุเพียงสองเดือน ณ เดือนสิงหาคม 2026 ในขณะที่ OpenHands เริ่มต้นตั้งแต่เดือนมีนาคม 2024 และ Dify ตั้งแต่เดือนเมษายน 2023 โดยรุ่น v0.1.0 ปล่อยออกมาเมื่อวันที่ 6 มิถุนายน 2026 และ v0.3.6 เมื่อวันที่ 1 สิงหาคม 2026 โปรเจกต์นี้ระบุสถานะว่าเป็นเบต้าและแจ้งว่ารุ่น 0.x อาจมีการเปลี่ยนแปลงที่ส่งผลต่อความเข้ากันได้ (compatibility) ให้มองตัวเลขเหล่านี้เป็นความเสี่ยงด้าน dependency มากกว่าการตัดสินคุณภาพ เพราะโปรเจกต์ที่มีอายุสองเดือนย่อมผ่านการตรวจสอบบั๊กจากผู้อื่นมาเพียงสองเดือนเท่านั้น
สิ่งที่เซิร์ฟเวอร์ต้องการและสิ่งที่พังเมื่อทรัพยากรไม่เพียงพอ
โปรเจกต์ระบุว่า 2 vCPU และ 4 GB RAM เพียงพอสำหรับการเริ่มต้น ซึ่งถูกต้องสำหรับ control plane และ sandbox ขนาดเล็กหนึ่งรายการ แต่ไม่เพียงพอสำหรับผู้ใช้งานสองคนที่กำลังพัฒนาพร้อมกัน ให้จัดสรรหน่วยความจำโดยแบ่งเป็นส่วนๆ Traefik และ Go control plane ใช้ทรัพยากรน้อย แต่ละ sandbox ที่ทำงานอยู่จะบรรจุ Node หรือ Python toolchain ฉบับเต็มไว้ โดยจุดที่ใช้ทรัพยากรสูงสุดคือ npm install ตามด้วยการ build เพื่อใช้งานจริง ควรวางแผนใช้ 8 GB สำหรับเครื่องที่จะรันแอปพลิเคชันไว้หลายตัว และให้มองว่า swap เป็นเพียงตาข่ายรองรับความปลอดภัย ไม่ใช่ความจุหลัก เพราะการ build ที่ต้องใช้ swap จะใช้เวลาหลายนาทีแทนที่จะเป็นไม่กี่วินาที
เมื่อหน่วยความจำหมด คุณจะพบความล้มเหลวสองรูปแบบที่แตกต่างกันโดยสิ้นเชิง ภายใน sandbox คอนเทนเนอร์จะถึงเพดาน --memory ที่ sandboxd กำหนดไว้ และ kernel จะสั่งยุติกระบวนการที่ใช้หน่วยความจำมากที่สุด ทำให้การ build ล้มเหลวโดยไม่มีข้อความแจ้งเตือนที่เป็นประโยชน์จาก agent docker ps -a จะแสดง exit code 137 สำหรับคอนเทนเนอร์นั้น และ docker inspect จะรายงานสถานะเป็น "OOMKilled": true การ build ด้วย Node ที่ล้มเหลวในลักษณะนี้มักจะแสดงข้อความ JavaScript heap out of memory ออกมาก่อน
ความล้มเหลวรูปแบบที่สองเกิดขึ้นที่ระดับ host โดย sandboxd จะรัน pressure reaper เพื่อหยุดการทำงานของ sandbox เมื่อหน่วยความจำของ host เหลือน้อย ดังนั้นบนเครื่องขนาดเล็ก sandbox อาจหายไปในขณะที่คุณกำลังดู preview ของมัน ไฟล์ข้อมูลยังคงปลอดภัยและคำขอถัดไปที่ส่งไปยัง URL ของ preview จะปลุกให้มันกลับมาทำงานอีกครั้ง แต่ทว่างานที่กำลังประมวลผลอยู่ในขณะที่คอนเทนเนอร์หยุดทำงานจะไม่กลับมาดำเนินการต่อ
Disk เป็นปัญหาที่เงียบกว่า ทุกแอปพลิเคชันจะเก็บ workspace ของตนเองไว้บน host และโปรเจกต์ JavaScript จะมีโครงสร้าง node_modules ขนาดหลายร้อยเมกะไบต์ แอปพลิเคชัน 10 รายการอาจใช้พื้นที่หลายกิกะไบต์สำหรับ dependencies ก่อนจะนับรวมไฟล์ image เริ่มต้นที่ 40 GB และคอยตรวจสอบด้วยคำสั่งนี้:
docker system df
sudo du -sh /var/lib/sandboxed/workspacesไดเรกทอรีข้อมูลเริ่มต้นคือ /var/lib/sandboxed ซึ่งสะกดโดยมี e เพิ่มเข้ามา การพิมพ์ /var/lib/sandboxd จะทำให้คุณพบกับไดเรกทอรีที่ว่างเปล่าและเสียเวลาไปห้านาทีโดยไม่เข้าใจสาเหตุ
การติดตั้ง sandboxd เวอร์ชันที่ระบุไว้
ต้องติดตั้ง Docker Engine พร้อมกับปลั๊กอิน Compose และ git ลงบนเซิร์ฟเวอร์ก่อน การติดตั้ง Docker บน VPS ครอบคลุมขั้นตอนดังกล่าวไว้แล้ว
docker compose version
git --versionทั้งสองคำสั่งต้องแสดงเวอร์ชันออกมา หากพบ docker: 'compose' is not a docker command แสดงว่าคุณยังใช้ไบนารี docker-compose แบบแยกส่วนรุ่นเก่าอยู่ แต่ตัวติดตั้งต้องการปลั๊กอิน v2
ตัวติดตั้งเป็นเชลล์สคริปต์ที่ดึงข้อมูลผ่านเครือข่าย ดังนั้นควรตรวจสอบเนื้อหาก่อนเรียกใช้งาน และระบุเวอร์ชันที่ต้องการให้ชัดเจน
curl -fsSL https://raw.githubusercontent.com/tastyeffectco/sandboxd/v0.3.6/install.sh -o install-sandboxd.sh
less install-sandboxd.sh
SANDBOXD_REF=v0.3.6 bash install-sandboxd.shSANDBOXD_REF คือ git ref ที่ตัวติดตั้งจะทำการ checkout ลงใน $HOME/.sandboxd/src โดยค่าเริ่มต้นคือ main การปล่อยให้ค่านี้ว่างไว้หมายความว่าการติดตั้งของคุณจะเป็นเวอร์ชันล่าสุดที่ถูกรวมเข้ามาในเช้าวันนั้น ซึ่งเป็นเรื่องสำคัญสำหรับโปรเจกต์ที่มีการปล่อยถึง 6 เวอร์ชันในเดือนกรกฎาคม 2026 เพียงเดือนเดียว ควรระบุเวอร์ชันให้ชัดเจน แล้วค่อยอัปเกรดด้วยความตั้งใจหลังจากอ่านบันทึกการเปลี่ยนแปลง (changelog) แล้ว
สคริปต์จะทำการ clone ซอร์สโค้ด, build อิมเมจ, เริ่มการทำงานของ stack ด้วย docker compose up -d และแสดง URL ของคอนโซลพร้อม API token ในตอนท้าย ให้บันทึก token นั้นไว้ในที่ปลอดภัย เพราะเป็นข้อมูลรับรองสำหรับ API ที่ใช้ควบคุม Docker ในฐานะ root
curl http://127.0.0.1:9090/healthzคำสั่งดังกล่าวจะแสดง ok เมื่อ control plane พร้อมใช้งาน หากไม่แสดงผลใดๆ แสดงว่า stack ไม่ได้เริ่มทำงาน ให้รัน docker compose ps จาก ~/.sandboxd/src เพื่อดูว่าบริการใดหยุดทำงาน จากนั้นใช้ docker compose logs sandboxd เพื่อตรวจสอบสาเหตุ
การเข้าถึงคอนโซลบนเครื่องระยะไกล
คอนโซลจะถูกให้บริการผ่าน Traefik บน HTTP_PORT ซึ่งโดยปกติคือพอร์ต 80 ที่ชื่อโฮสต์ http://console.localhost เนื่องจาก Traefik ทำการกำหนดเส้นทางตามชื่อโฮสต์ การระบุ IP address ของเซิร์ฟเวอร์ในเบราว์เซอร์จึงไม่ตรงกับกฎใดๆ และจะส่งผลให้เกิดข้อผิดพลาด 404 จนกว่าคุณจะตั้งค่าโดเมนจริง ให้ทำการ forward พอร์ตและคงชื่อโฮสต์ไว้ดังนี้:
ssh -L 8080:127.0.0.1:80 you@your-vpsจากนั้นเปิด http://console.localhost:8080 บนแล็ปท็อปของคุณ บน Linux และ macOS ชื่อใดก็ตามที่ลงท้ายด้วย .localhost จะถูกแปลงเป็น 127.0.0.1 ดังนั้นคำขอจะถูกส่งผ่านอุโมงค์ (tunnel) ไปพร้อมกับส่วนหัว Host ที่ถูกต้อง ให้ตั้งรหัสผ่านสำหรับคอนโซลในการเข้าใช้งานครั้งแรก
กำหนดโมเดลให้กับเอเจนต์
อิมเมจพื้นฐานมาพร้อมกับเอเจนต์เขียนโค้ด 2 ตัว ได้แก่ OpenCode และ Claude Code โดย SANDBOXD_DEFAULT_AGENT จะเป็นตัวตัดสินใจเลือกเอเจนต์สำหรับงานที่ไม่ได้ระบุชื่อไว้ และค่าเริ่มต้นคือ opencode หากยังไม่ได้เชื่อมต่อคีย์ใดๆ งานจะรันบนโมเดลฟรีแบบไม่ใช้คีย์ของ OpenCode Zen ดังนั้นการบิลด์ครั้งแรกของคุณจะไม่มีค่าใช้จ่าย และคุณสามารถทดสอบกระบวนการทำงานทั้งหมดได้ก่อนที่จะเริ่มเสียค่าใช้จ่ายใดๆ
เชื่อมต่อคีย์ของคุณเองเมื่อต้องการใช้โมเดลที่มีประสิทธิภาพสูงขึ้น คีย์จะถูกส่งไปยัง control plane และไม่เคยถูกส่งเข้าไปใน sandbox โดยคีย์จะถูกจัดเก็บแบบเข้ารหัสไว้ภายใต้ data directory และถูกส่งผ่านเครือข่ายโดย credential proxy ดังนั้นทั้งตัวเอเจนต์และโค้ดที่เอเจนต์เขียนขึ้นจะไม่สามารถอ่านคีย์เหล่านี้ได้
export API=http://127.0.0.1:9090
export SANDBOXD_TOKEN=sk_... # printed by the installer
export AUTH="Authorization: Bearer $SANDBOXD_TOKEN"
curl -s -XPOST $API/v1/agents/claude-code/api-key -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"api_key":"sk-ant-..."}'คุณสามารถดำเนินการแบบเดียวกันได้ผ่านคอนโซลในเมนู Settings แล้วเลือก AI Agents ซึ่งรวมถึงขั้นตอนการทำ OAuth แบบมีคำแนะนำ หากคุณต้องการใช้การสมัครสมาชิก Claude แทนการใช้ API key โดยโมเดลเริ่มต้นของแต่ละเอเจนต์จะอยู่ในแผงควบคุมเดียวกัน และคุณสามารถกำหนดโมเดลใหม่สำหรับงานเฉพาะเจาะจงได้ในขณะสั่งงาน
สร้างแอปขนาดเล็กแบบครบวงจร
สร้างแอปพลิเคชัน เริ่มการทำงานของ sandbox จากนั้นส่งคำสั่ง (prompt) ระบบจะส่งคืนค่า id ในรูปแบบ JSON และคู่มือเริ่มต้นใช้งานจะดึงค่าเหล่านั้นออกมาด้วย sed ดังนั้นคุณจึงไม่จำเป็นต้องติดตั้ง jq
APP=$(curl -s -XPOST $API/v1/apps -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"name":"todo","runtime_preset":"react-vite"}' \
| sed -E 's/.*"id":"([^"]+)".*/\1/')
SB=$(curl -s -XPOST $API/v1/apps/$APP/sandbox -H "$AUTH" \
-H 'content-type: application/json' -d '{"ports":[3000]}' \
| sed -E 's/.*"id":"([^"]+)".*/\1/')
echo "app=$APP sandbox=$SB"ตัวแปรทั้งสองต้องมีค่า id หาก $SB ว่างเปล่า หมายความว่า sandbox ไม่ได้เริ่มทำงาน ซึ่งสาเหตุทั่วไปคือ base image ยังคงอยู่ในระหว่างการสร้าง หรือโฮสต์มีหน่วยความจำไม่เพียงพอ หากพบ 401 แทนที่จะเป็น id แสดงว่า bearer token ไม่ถูกต้อง
curl -s -XPOST $API/v1/sandboxes/$SB/tasks -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"prompt":"Add a todo list with a text input, an add button, and a delete button on each row. Keep the list in localStorage.","agent":"opencode"}'การตอบกลับจะมี task id อยู่ด้วย GET /v1/sandboxes/$SB/tasks/<task id> จะส่งคืนผลลัพธ์ของงานนั้น และ path /events บน task เดียวกันจะเป็นสตรีม SSE (server sent events) แบบสดที่แสดงการทำงานของ agent คอนโซลจะแสดงสตรีมเดียวกันนี้ในรูปแบบแชท
จากนั้นแอปจะอยู่ที่ http://s-<sandbox id>-3000.preview.localhost โดยที่ 3000 คือพอร์ตที่คุณระบุไว้ หาก sandbox อยู่ในสถานะพัก คำขอแรกจะถูกส่งไปยัง catch-all ของ Traefik จากนั้น sandboxd จะเริ่มคอนเทนเนอร์ รอจนกว่าพอร์ตจะตอบสนอง และแสดงหน้า warming page สั้นๆ ซึ่งจะรีเฟรชเข้าสู่แอปของคุณโดยอัตโนมัติ หากหน้าตัวอย่างค้างอยู่ที่หน้านั้นตลอดเวลา แสดงว่ากระบวนการภายในไม่ได้ฟัง (listen) บนพอร์ตที่ประกาศไว้ใน sandbox.yaml ของแอป
การนำพรีวิวไปใช้งานบนโดเมนจริงด้วย HTTPS
Sandbox แต่ละรายการจะมี hostname เป็นของตนเอง ดังนั้น record DNS แบบ wildcard เพียงรายการเดียวจึงครอบคลุมทั้งหมด ให้ชี้ *.preview.yourdomain.com ไปยัง IP address ของเซิร์ฟเวอร์ด้วย A record จากนั้นกำหนดค่าตัวแปรพรีวิวใน .env ภายในไฟล์ ~/.sandboxd/src:
PREVIEW_DOMAIN=yourdomain.com
PREVIEW_ENTRYPOINT=websecure
PREVIEW_TLS=true
SANDBOXD_API_AUTH_DISABLED=falseTraefik จำเป็นต้องมีส่วนประกอบที่สอดคล้องกัน: ให้เปิดใช้งาน entrypoint websecure ใน traefik/traefik.yml และเพิ่ม certificate resolver โดยให้ใช้การท้าทายแบบ DNS-01 เนื่องจาก certificate แบบ wildcard เพียงใบเดียวจะครอบคลุม hostname ของพรีวิวทั้งหมด หากใช้ HTTP-01 ตัว sandbox ใหม่แต่ละรายการจะต้องมีการออก certificate ใหม่ ซึ่งหากมีการสร้าง sandbox จำนวนมากในช่วงเวลาสั้นๆ จะทำให้ติดข้อจำกัดด้านอัตรา (rate limits) ของ Let's Encrypt ได้ เนื้อหาใน การใช้ Wildcard certificates ผ่านการท้าทายแบบ DNS-01 จะอธิบายรายละเอียดในส่วนของ DNS
cd ~/.sandboxd/src
docker compose up -dURL ของพรีวิวจะเป็น https://s-<id>-3000.preview.yourdomain.com ให้เปิดพอร์ต 80 และ 443 บนไฟร์วอลล์ และปิดพอร์ต 9090 ไม่ให้เข้าถึงจากภายนอก: ดูรายละเอียดเพิ่มเติมที่ กฎพื้นฐานของ ufw firewall โปรดจำไว้ว่าใครก็ตามที่สามารถเดา hostname ของพรีวิวได้จะสามารถโหลดแอปพลิเคชันนั้นได้ ดังนั้นให้ถือว่าพรีวิวเป็นบริการสาธารณะ
โค้ดที่สร้างขึ้นจะไปอยู่ที่ไหน และสามารถส่งออกได้หรือไม่
บนโฮสต์ โค้ดจะอยู่ในไดเรกทอรีข้อมูล แต่ละ workspace คือไดเรกทอรีปกติที่ /var/lib/sandboxed/workspaces/<id>/ ซึ่งถูก bind mount เข้าไปในคอนเทนเนอร์ และไฟล์ของแอปจะอยู่ที่ /home/sandbox/workspace/app ภายใน sandbox สถานะของ control plane จะเป็นไฟล์ SQLite ไฟล์เดียวที่ state/sandboxd.db และข้อมูลรับรองของ agent ที่เข้ารหัสไว้จะอยู่ที่ agent-auth/ ไม่มีสิ่งใดถูกซ่อนไว้ภายในเลเยอร์ของคอนเทนเนอร์ ดังนั้นการสำรองข้อมูลจึงทำได้โดยการคัดลอกไดเรกทอรีรวมถึงไฟล์ฐานข้อมูลดังกล่าว การสำรองข้อมูลด้วย restic บน VPS สามารถจัดการทั้งสองส่วนนี้ได้
sudo ls /var/lib/sandboxed/workspaces
sudo du -sh /var/lib/sandboxed/workspaces/*การส่งออกผ่าน Git เป็นฟีเจอร์ที่มีมาในตัว ไม่ใช่ส่วนเสริม API จะเปิดเผยสถานะและ diff สำหรับการอ่าน จากนั้นจึงทำการ commit และ push:
curl -s $API/v1/apps/$APP/git/status -H "$AUTH"
curl -s -XPOST $API/v1/apps/$APP/git/commit -H "$AUTH" \
-H 'content-type: application/json' \
-d '{"message":"todo list, first pass"}'
curl -s -XPOST $API/v1/apps/$APP/git/push -H "$AUTH" \
-H 'content-type: application/json' -d '{"branch":"main"}'remote ส่วนตัวจำเป็นต้องใช้ personal access token ซึ่งตั้งค่าเพียงครั้งเดียวในคอนโซลภายใต้ Settings, Git credentials ข้อมูลนี้จะถูกจัดเก็บแบบเข้ารหัสและอยู่นอก sandbox ดังนั้น agent จึงไม่สามารถอ่านหรือ push ข้อมูลโดยที่คุณไม่ทราบได้ ควรทำการ push ให้บ่อยและรวดเร็ว เพราะจนกว่าคุณจะทำเช่นนั้น ไดเรกทอรี workspace จะเป็นสำเนาเดียวของโค้ด และ DELETE /v1/apps/<id> จะลบข้อมูลดังกล่าวทิ้งโดยไม่มีการเตือนซ้ำสอง
การสร้างโปรเจกต์มีค่าใช้จ่ายเป็นโทเค็นของโมเดลเท่าใด
sandboxd ไม่ได้วัดปริมาณการใช้งานของคุณ ดังนั้นตัวเลขที่สำคัญจึงอยู่ในคอนโซลของผู้ให้บริการโมเดลของคุณ โมเดล OpenCode Zen แบบฟรีไม่มีค่าใช้จ่าย แต่จะทำงานช้าและมีประสิทธิภาพต่ำกว่าโมเดลแบบเสียค่าใช้จ่าย ซึ่งจะส่งผลให้ต้องมีการแก้ไขหลายรอบมากขึ้นในโปรเจกต์ที่ซับซ้อนกว่าแอปพลิเคชันทดลอง
รูปแบบของค่าใช้จ่ายจะขึ้นอยู่กับการทำงานของ agent loop ในแต่ละรอบการทำงาน ระบบจะส่งบริบทที่จำเป็นกลับไปใหม่เสมอ ดังนั้นค่าใช้จ่ายจึงขึ้นอยู่กับจำนวนรอบการทำงาน ไม่ใช่จำนวนแอปพลิเคชัน การส่ง prompt เพียงครั้งเดียวแล้วสำเร็จจะมีราคาถูก แต่การแก้ไข 15 รอบในหัวข้อ "แก้ไขระยะห่าง" สำหรับโปรเจกต์ที่มีไฟล์ 50 ไฟล์จะมีราคาสูง เนื่องจากเนื้อหาของไฟล์ทั้งหมดจะถูกส่งไปด้วยทุกครั้ง Input และ output tokens มีราคาที่แตกต่างกัน และ ค่าใช้จ่ายของ coding agent ต่อเซสชัน จะแสดงช่วงราคาที่เกิดขึ้นจริง คุณควรตั้งค่าจำกัดการใช้จ่ายสูงสุดไว้ที่ฝั่งผู้ให้บริการก่อนที่จะปล่อยให้ loop ทำงานโดยไม่มีการดูแล
การล้าง sandbox ที่ค้างอยู่
idle reaper จะหยุดการทำงานของ sandbox ใดก็ตามที่ไม่มีการใช้งานเกินกว่า SANDBOXD_IDLE_THRESHOLD_SECONDS ซึ่งค่าเริ่มต้นคือ 2100 วินาที หรือ 35 นาที การดำเนินการนี้จะคืนหน่วยความจำ RAM แต่ยังคงเก็บไฟล์ไว้ และเมื่อมีการร้องขอไปยัง preview URL อีกครั้ง คอนเทนเนอร์จะถูกปลุกขึ้นมาใหม่ หากคุณใช้เซิร์ฟเวอร์ขนาดเล็กควรลดค่านี้ลง เนื่องจากคอนเทนเนอร์ที่ไม่ได้ใช้งานนาน 35 นาที หมายถึงหน่วยความจำที่คุณไม่สามารถนำไปใช้ประโยชน์ได้นานถึง 35 นาที
การหยุดการทำงานไม่ใช่การลบ และนี่คือสาเหตุที่ทำให้ดิสก์เต็มโดยไม่รู้ตัว sandbox ที่ถูกหยุดการทำงานยังคงครอบครอง workspace และคอนเทนเนอร์ของตนเองอยู่ การลบ sandbox แต่ยังคงเก็บแอปไว้คือการทำ DELETE บน sandbox ซึ่งจะเป็นการลบทั้งคอนเทนเนอร์และ workspace ออกไปพร้อมกัน แต่หากลบแอปทิ้งจะเป็นการลบทุกอย่างออกอย่างถาวร
curl -s -XPOST $API/v1/sandboxes/$SB/stop -H "$AUTH" # frees RAM, keeps files
curl -s -XDELETE $API/v1/sandboxes/$SB -H "$AUTH" # container and workspace gone
curl -s -XDELETE $API/v1/apps/$APP -H "$AUTH" # app and everything under itหลังจากผ่านการทดลองไปสองสามสัปดาห์ docker system df จะแสดงพื้นที่ของ image ที่สามารถเรียกคืนได้มากกว่าที่คุณคาดไว้ เนื่องจากทุกแอปที่ดึง toolchain ของตัวเองมาใช้งานจะทิ้ง layer ต่างๆ ไว้เบื้องหลัง docker image prune จะทำการล้าง layer ที่ค้างอยู่เหล่านี้ออกไป ให้ตรวจสอบ GET /v1/apps ก่อนเสมอ เนื่องจาก image ที่ยังถูกอ้างอิงโดย sandbox ที่อยู่ในสถานะ sleeping จะไม่ถือว่าเป็นขยะ
ขอบเขตของคอนเทนเนอร์ให้อะไรและไม่ให้อะไรกับคุณ
Sandbox แต่ละตัวจะรันในฐานะผู้ใช้ที่ไม่มีสิทธิ์ (unprivileged user) โดยมีระบบไฟล์ root แบบอ่านอย่างเดียว (read-only root filesystem) พร้อมทั้งตัด Linux capabilities ทั้งหมดออก มีการตั้งค่า no-new-privileges รวมถึงจำกัดเพดานหน่วยความจำและจำนวนโพรเซส โครงการนี้มีความโปร่งใสเกี่ยวกับข้อจำกัดดังกล่าว: คอนเทนเนอร์ Linux ที่ใช้เคอร์เนลร่วมกันนั้นเป็นขอบเขตการแยกส่วนที่แข็งแกร่ง แต่เป็นขอบเขตความปลอดภัยที่อ่อนแอ หากเกิดบั๊กในเคอร์เนลจะส่งผลให้โฮสต์ถูกบุกรุกได้
ข้อเท็จจริงสองประการที่ต้องดำเนินการ: การเชื่อมต่อเครือข่ายขาออก (network egress) จาก sandbox ในรุ่น self-hosted นั้นเปิดกว้าง ทำให้โค้ดที่สร้างขึ้นสามารถเข้าถึงอินเทอร์เน็ต เครือข่ายภายในของคุณ และจุดเชื่อมต่อ metadata ของคลาวด์ได้ ระบบย่อย nftables สำหรับควบคุมขาออกมีอยู่ในซอร์สโค้ดแต่ถูกปิดไว้ในการคอมไพล์รุ่น Docker Compose แบบพกพา ซึ่งหมายความว่าข้อจำกัดต่างๆ ต้องถูกจัดการโดยไฟร์วอลล์ของโฮสต์คุณ นอกจากนี้ API ของ control plane ยังมีสิทธิ์เทียบเท่า root ของโฮสต์ เนื่องจากมันควบคุม Docker socket โดยค่าเริ่มต้นมันจะผูกกับ 127.0.0.1:9090 ซึ่ง SANDBOXD_API_AUTH_DISABLED จะต้องคงค่าเป็น false ไว้เสมอ และไม่ควรเปิดเผย API นี้สู่สาธารณะบนอินเทอร์เน็ตโดยเด็ดขาด
หากคุณวางแผนที่จะให้ผู้อื่นส่งคำสั่ง (prompts) มายังเครื่องของคุณ โมเดลนี้เพียงอย่างเดียวถือว่าอ่อนแอเกินไป โครงการแนะนำให้ใช้ gVisor ร่วมกับ SANDBOXD_RUNTIME=runsc ซึ่งจะเพิ่มเคอร์เนลในระดับ userspace เข้าไประหว่าง sandbox กับโฮสต์ โดยแลกกับประสิทธิภาพที่ช้าลงประมาณ 1.7 ถึง 4 เท่าในงานที่ต้องเรียกใช้ syscall จำนวนมาก คำตอบที่แข็งแกร่งกว่าคือการใช้เครื่องแยกต่อผู้ใช้งานหนึ่งราย (one machine per tenant) ซึ่งเป็นเหตุผลเดียวกับที่ระบุไว้ใน การรัน coding agents ใน VM แบบใช้แล้วทิ้ง
คุณควรสร้างโปรเจกต์บนซอฟต์แวร์ที่มีอายุเพียงสองเดือนหรือไม่
สำหรับเครื่อง build ส่วนตัว คำตอบคือได้ โดยต้องมีข้อควรระวังที่ชัดเจน: ให้ตรึงเวอร์ชันด้วย SANDBOXD_REF, สำรองข้อมูล /var/lib/sandboxed และ push แอปพลิเคชันทุกตัวที่คุณให้ความสำคัญไปยัง git remote สำหรับงานใดก็ตามที่ลูกค้าต้องใช้งาน ให้รอจนกว่าจะเป็นเวอร์ชัน 1.0 หรือเตรียมงบประมาณไว้สำหรับกรณีที่ระบบเสียหาย เพราะผู้ดูแลโปรเจกต์ระบุไว้อย่างชัดเจนว่าเวอร์ชัน 0.x อาจมีการเปลี่ยนแปลงได้ตลอดเวลา นอกจากนี้ ผู้ดูแลยังมีบริการติดตั้งแบบจัดการให้ในราคา 79 ดอลลาร์ต่อเดือน ณ เดือนสิงหาคม 2026 ซึ่งเป็นข้อมูลที่ควรทราบเมื่อคุณประเมินว่าโปรเจกต์นั้นมีเหตุผลเพียงพอที่จะดำเนินการต่อไปหรือไม่
เหตุผลที่ความเสี่ยงนี้อยู่ในระดับที่ยอมรับได้คือผลลัพธ์ที่ได้ sandboxd จะสร้างแอปพลิเคชันทั่วไปใน repository ของ git ตามปกติ ดังนั้นหากโปรเจกต์หยุดชะงัก คุณยังคงเก็บโค้ดไว้ได้และสูญเสียเพียงแค่ตัว wrapper เท่านั้น ซึ่งเป็นสถานะที่ดีกว่าการใช้บริการ build แบบ hosted ที่เป็นเจ้าของโปรเจกต์ของคุณ สำหรับมุมมองที่กว้างขึ้นว่ามีอะไรที่ควรค่าแก่การ self-host บนเซิร์ฟเวอร์ของคุณในปีนี้ โปรดดู สิ่งที่ควรค่าแก่การ self-host ในปี 2026
FAQ
สเปกเซิร์ฟเวอร์ขั้นต่ำสำหรับ sandboxd คือเท่าใด
โครงการระบุว่า 2 vCPU และ RAM 4 GB เพียงพอสำหรับการเริ่มต้น ซึ่งครอบคลุมถึง control plane, Traefik และ sandbox ขนาดเล็กหนึ่งรายการ ให้ใช้ RAM 8 GB และพื้นที่ดิสก์ 40 GB หากคุณต้องการให้แอปหลายรายการทำงานพร้อมกัน เนื่องจาก sandbox แต่ละรายการที่ทำงานอยู่จะเก็บ toolchain ของ Node หรือ Python ไว้ทั้งหมด และ workspace แต่ละแห่งจะเก็บ dependency tree ของตนเองไว้บนดิสก์ เมื่อโฮสต์มีทรัพยากรไม่เพียงพอ ตัว pressure reaper ของ sandboxd จะหยุดการทำงานของ sandbox เพื่อคืนหน่วยความจำ และการ build ที่ใช้หน่วยความจำเกินขีดจำกัดของ container จะถูก kernel สั่งยุติการทำงาน โดย docker ps -a จะแสดง exit code 137 สำหรับกรณีดังกล่าว
sandboxd แตกต่างจาก Dify หรือ OpenHands อย่างไร
เครื่องมือเหล่านี้สร้างผลลัพธ์ที่แตกต่างกัน Dify สร้างแอปพลิเคชันที่เรียกใช้โมเดลในขณะรันไทม์ เช่น อินเทอร์เฟซแชทและไปป์ไลน์การดึงข้อมูล OpenHands แก้ไข repository ที่คุณมีอยู่แล้ว โดยการรันคำสั่งและเสนอการเปลี่ยนแปลงโค้ดที่มีอยู่ ส่วน sandboxd จะสร้างโครงร่างโครงการใหม่ทั้งหมดจาก prompt, build ภายใน container ของตนเอง และให้บริการผ่าน preview URL ซึ่งผลลัพธ์ที่ได้จะเป็นเว็บแอปพลิเคชันทั่วไปที่ไม่จำเป็นต้องใช้โมเดลในการรัน
โค้ดที่เอเจนต์เขียนขึ้นถูกจัดเก็บไว้ที่ใด
จัดเก็บไว้บนระบบไฟล์ของโฮสต์ ไม่ใช่ภายใน container image แอปแต่ละรายการจะมีไดเรกทอรีอยู่ที่ /var/lib/sandboxed/workspaces/<id>/ ซึ่งถูก bind mount เข้าไปใน sandbox และไฟล์จะปรากฏที่ /home/sandbox/workspace/app ภายในนั้น สถานะของ control plane จะเป็นไฟล์ SQLite ไฟล์เดียวภายใต้ state/ ในไดเรกทอรีข้อมูลเดียวกัน คุณสามารถ commit และ push ไปยัง git remote ได้จากแท็บ Git ของคอนโซล หรือผ่าน endpoint /v1/apps/<id>/git/commit และ /git/push โดย token สำหรับ private remote จะถูกจัดเก็บแบบเข้ารหัสโดย control plane แทนที่จะส่งมอบให้กับ sandbox
การเปิดใช้งาน sandboxd บนอินเทอร์เน็ตมีความปลอดภัยหรือไม่
ให้เปิดใช้งานเฉพาะ preview URL และคอนโซลเท่านั้น ห้ามเปิดใช้งาน API ของ control plane โดยเด็ดขาด เนื่องจาก API ดังกล่าวควบคุม Docker บนโฮสต์ ซึ่งเทียบเท่ากับการมีสิทธิ์ root และด้วยเหตุนี้จึงผูกไว้กับ 127.0.0.1:9090 ตามค่าเริ่มต้น นอกจากนี้ sandbox ยังมีการเปิด network egress ในเวอร์ชัน self-hosted ซึ่งหมายความว่าโค้ดที่เอเจนต์เขียนขึ้นสามารถเข้าถึงเครือข่ายภายในและ endpoint ของ cloud metadata ของคุณได้ ดังนั้นควรเพิ่มกฎ firewall ของโฮสต์หากเครื่องดังกล่าวมีอุปกรณ์อื่นที่ต้องป้องกัน สำหรับการรับ prompt จากบุคคลที่คุณไม่ไว้วางใจ ให้รันโฮสต์แยกต่อหนึ่งผู้ใช้งาน (tenant) แทนการพึ่งพาขอบเขตของ container เพียงอย่างเดียว