SSD Nodes Learn Hosting plans →
راهنماها Matt Connorتوسط Matt Connor · به‌روزرسانی شده 2026-08-13

آموزش نصب و میزبانی شخصی sandboxd روی VPS

با راهنمای گام‌به‌گام ما sandboxd را روی سرور شخصی خود اجرا کنید. تنظیمات دقیق Docker، پیکربندی Traefik v3، مدیریت کلیدهای مدل و پاکسازی کانتینرهای قدیمی را برای اجرای بهینه یاد بگیرید.

sandboxd چیست و اجرای شخصی آن چه مزایایی دارد

برای میزبانی شخصی sandboxd به یک سرور لینوکس با Docker و یک نام دامنه نیاز دارید. شما یک پرامپت ارسال می‌کنید، یک عامل کدنویسی (coding agent) یک برنامه واقعی را درون یک کانتینر ایزوله می‌سازد و آن برنامه در URL پیش‌نمایش اختصاصی خود بالا می‌آید. ابزارهای تبدیل پرامپت به برنامه (Prompt-to-app)، پرطرفدارترین دسته از سرویس‌های میزبانی‌شده در سال 2026 هستند و sandboxd تنها گزینه‌ای است که تحت مجوز MIT روی VPS شما اجرا می‌شود و کد تولیدشده را روی دیسک خودتان ذخیره می‌کند.

طراحی این ابزار به‌عمد کوچک نگه داشته شده است. یک کنترل‌پلن به زبان Go، داکر را مدیریت می‌کند، Traefik v3 هر نام میزبان پیش‌نمایش را مسیریابی می‌کند، SQLite وضعیت را نگه می‌دارد و هر برنامه درون یک کانتینر مجزا اجرا می‌شود. در اینجا خبری از Kubernetes یا سرور دیتابیس جداگانه نیست؛ به همین دلیل است که یک سرور با 2 هسته vCPU به‌راحتی از پس اجرای آن برمی‌آید.

چهار شیء، کل مدل را تشکیل می‌دهند. یک app همان پروژه پایدار است که نام، متادیتای git و secrets مربوط به خود را نگه می‌دارد. یک sandbox همان کانتینر داکری است که برنامه در آن اجرا می‌شود و هر برنامه در هر لحظه به یک sandbox اشاره دارد. یک workspace شامل فایل‌های برنامه است که روی میزبان (host) قرار دارند و با حذف کانتینر از بین نمی‌روند. یک task همان پرامپتی است که به عامل درون sandbox تحویل داده می‌شود. متوقف کردن یک sandbox حافظه را آزاد می‌کند اما فایل‌ها را حفظ می‌کند. نابود کردن آن، کانتینر را حذف می‌کند و برنامه می‌تواند یک کانتینر جدید را بالا بیاورد.

تفاوت sandboxd با Dify و OpenHands چیست؟

این سه ابزار اغلب با هم اشتباه گرفته می‌شوند، زیرا هر سه یک LLM (مدل زبانی بزرگ) را روی سرور شما اجرا می‌کنند، اما خروجی آن‌ها متفاوت است. Dify برنامه‌های مبتنی بر LLM می‌سازد: رابط‌های چت، خط‌لوله‌های بازیابی (retrieval pipelines) و گردش‌کارهایی که هر بار با استفادهٔ کاربر، یک مدل را فراخوانی می‌کنند. مدل در اینجا بخشی از محصول نهایی است. OpenHands روی مخزنی که از قبل دارید کار می‌کند: شما آن را به سمت کد خود هدایت می‌کنید و ابزار فایل‌ها را می‌خواند، دستورات را اجرا می‌کند و تغییرات را پیشنهاد می‌دهد. اما sandboxd از صفر شروع می‌کند. این ابزار یک پروژه را از روی یک قالب (preset) داربست‌بندی کرده، آن را در یک کانتینر تازه می‌سازد و یک URL برای مشاهده به شما می‌دهد. خروجی کار، یک برنامهٔ معمولی React یا FastAPI است که برای اجرا به هیچ مدلی نیاز ندارد.

بنابراین، انتخاب خود را بر اساس خروجی نهایی مورد نظرتان انجام دهید. sandboxd برای شروع از یک جمله و حفظ کد پس از آن است. دو ابزار دیگر برای زمانی هستند که مخزن کد یا محصول مبتنی بر مدل از قبل وجود دارد.

تفاوت دیگر در قدمت آن‌هاست؛ این نکته‌ای است که پیش از ساخت هر پروژهٔ جدی روی این ابزارها باید در نظر بگیرید.

ChartGitHub stars and forks, read from the GitHub API on 4 August 2026
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 ستاره است، در حالی که OpenHands 83,091 و Dify 151,320 ستاره دارند. این مخزن در تاریخ 3 June 2026 ایجاد شده است، بنابراین تا آگوست 2026 تنها دو ماه قدمت دارد؛ در حالی که OpenHands از مارس 2024 و Dify از آوریل 2023 فعال هستند. نسخه v0.1.0 در تاریخ 6 June 2026 و نسخه v0.3.6 در تاریخ 1 August 2026 منتشر شد. این پروژه خود را در مرحله بتا می‌داند و اعلام کرده که نسخه‌های 0.x ممکن است سازگاری را از بین ببرند. این اعداد را به عنوان ریسک وابستگی در نظر بگیرید، نه به عنوان قضاوت در مورد کیفیت؛ پروژه‌ای که دو ماه از عمر آن می‌گذرد، تنها دو ماه فرصت داشته تا باگ‌هایش توسط دیگران شناسایی شود.

نیازهای سرور و پیامدهای کمبود منابع

مستندات پروژه اعلام می‌کنند که 2 هسته vCPU و 4 گیگابایت رم برای شروع کافی است. این مقدار برای کنترل پلین (control plane) و یک محیط sandbox کوچک دقیق است، اما برای دو نفر که هم‌زمان در حال توسعه هستند، کفایت نمی‌کند. حافظه را به‌صورت بخش‌بندی‌شده در نظر بگیرید. Traefik و کنترل پلین Go سبک هستند. هر sandbox در حال اجرا، یک toolchain کامل Node یا Python را در خود جای می‌دهد و نقطه اوج مصرف منابع، یک npm install و به دنبال آن یک build نهایی (production build) است. برای سروری که قرار است چند برنامه را فعال نگه دارد، 8 گیگابایت رم در نظر بگیرید و swap را به‌عنوان یک شبکه ایمنی (safety net) ببینید، نه به‌عنوان ظرفیت اصلی؛ زیرا buildای که از swap استفاده می‌کند، به‌جای چند ثانیه، چند دقیقه زمان می‌برد.

هنگامی که حافظه تمام می‌شود، با دو نوع شکست متفاوت مواجه می‌شوید که هیچ شباهتی به هم ندارند. در داخل یک sandbox، کانتینر به سقف سخت --memory که توسط sandboxd تعیین شده می‌رسد و کرنل بزرگ‌ترین پردازش را می‌کشد؛ در نتیجه build بدون هیچ پیام مفیدی از سمت agent متوقف می‌شود. دستور docker ps -a کد خروج 137 را برای آن کانتینر نشان می‌دهد و docker inspect روی آن، وضعیت "OOMKilled": true را گزارش می‌کند. یک build مبتنی بر Node که به این شکل متوقف می‌شود، اغلب ابتدا پیام JavaScript heap out of memory را چاپ می‌کند.

شکست دوم در سطح میزبان (host) رخ می‌دهد. sandboxd یک مکانیزم pressure reaper دارد که وقتی حافظه میزبان کم می‌شود، sandboxها را متوقف می‌کند؛ بنابراین در یک سرور کوچک، ممکن است sandbox درست زمانی که در حال مشاهده پیش‌نمایش آن هستید، ناپدید شود. فایل‌ها ایمن هستند و درخواست بعدی به URL پیش‌نمایش، آن را بیدار می‌کند، اما وظیفه‌ای (task) که هنگام توقف کانتینر در حال اجرا بود، از سر گرفته نمی‌شود.

دیسک، مشکل بی‌سروصداتری است. هر برنامه فضای کاری (workspace) مخصوص به خود را روی میزبان نگه می‌دارد و یک پروژه JavaScript درختی از نوع node_modules به حجم صدها مگابایت به همراه دارد. ده برنامه، پیش از آنکه تصاویر (images) را محاسبه کنید، چندین گیگابایت وابستگی (dependencies) ایجاد می‌کنند. با 40 گیگابایت شروع کنید و آن را زیر نظر داشته باشید:

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 نیاز دارد.

نصب‌کننده یک اسکریپت shell است که از شبکه دریافت می‌شود؛ بنابراین پیش از اجرا آن را مطالعه کنید و نسخه را پین کنید.

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.sh

SANDBOXD_REF همان git ref است که نصب‌کننده آن را در $HOME/.sandboxd/src بررسی (checkout) می‌کند و مقدار پیش‌فرض آن main است. اگر این متغیر را تنظیم نکنید، نصب شما شامل آخرین تغییرات ادغام‌شده در همان روز خواهد بود؛ این موضوع در پروژه‌ای که تنها در ژوئیه 2026 شش نسخه منتشر کرده، اهمیت زیادی دارد. آن را پین کنید و پس از مطالعه changelog، به‌صورت دستی و آگاهانه ارتقا دهید.

این اسکریپت سورس را کلون کرده، ایمیج‌ها را می‌سازد، استک را با docker compose up -d بالا می‌آورد و در پایان، URL کنسول و یک توکن API را نمایش می‌دهد. آن توکن را در جای امنی ذخیره کنید. این توکن، اعتبارنامه‌ای برای API است که Docker را با دسترسی root کنترل می‌کند.

curl http://127.0.0.1:9090/healthz

این دستور در صورت بالا بودن control plane، عبارت ok را چاپ می‌کند. اگر خروجی خالی بود، یعنی استک اجرا نشده است: دستور docker compose ps را از مسیر ~/.sandboxd/src اجرا کنید تا ببینید کدام سرویس متوقف شده است، سپس از docker compose logs sandboxd برای یافتن علت آن استفاده کنید.

دسترسی به کنسول در یک سرور راه دور

کنسول از طریق Traefik روی HTTP_PORT ارائه می‌شود که به‌صورت پیش‌فرض 80 است و در نام میزبان http://console.localhost در دسترس قرار دارد. Traefik درخواست‌ها را بر اساس نام میزبان مسیریابی می‌کند؛ بنابراین وارد کردن آدرس IP سرور در مرورگر با هیچ قانونی مطابقت ندارد و خطای 404 برمی‌گرداند. تا زمانی که یک دامنه واقعی تنظیم نکرده‌اید، پورت را فوروارد کنید و نام میزبان را حفظ نمایید:

ssh -L 8080:127.0.0.1:80 you@your-vps

سپس http://console.localhost:8080 را در لپ‌تاپ خود باز کنید. در Linux و macOS، هر نامی که به .localhost ختم شود به 127.0.0.1 ترجمه می‌شود، بنابراین درخواست با هدر Host صحیح از طریق تونل ارسال می‌گردد. در اولین بازدید، رمز عبور کنسول را تنظیم کنید.

اختصاص مدل به عامل

دو عامل برنامه‌نویسی در image پایه عرضه می‌شوند: OpenCode و Claude Code. بخش SANDBOXD_DEFAULT_AGENT تصمیم می‌گیرد کدام‌یک وظیفه‌ای را که نامی از عامل نبرده است اجرا کند و به‌صورت پیش‌فرض از opencode استفاده می‌کند. بدون اتصال هیچ کلیدی، وظایف روی مدل‌های رایگان و بدون نیاز به کلید OpenCode Zen اجرا می‌شوند؛ بنابراین اولین build شما هزینه‌ای ندارد و می‌توانید پیش از صرف هرگونه هزینه، کل چرخه را تست کنید.

هنگامی که به مدلی قدرتمندتر نیاز دارید، کلید خود را متصل کنید. کلیدها به control plane ارسال می‌شوند و هرگز وارد sandbox نمی‌شوند: آن‌ها به‌صورت رمزنگاری‌شده در دایرکتوری داده ذخیره شده و توسط یک 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 است. مدل پیش‌فرض برای هر عامل در همان پنل قرار دارد و یک وظیفهٔ واحد می‌تواند آن را بازنویسی (override) کند.

ساخت یک برنامه کوچک از ابتدا تا انتها

برنامه را ایجاد کنید، sandbox آن را راه‌اندازی کنید و سپس یک prompt ارسال کنید. شناسه‌ها به‌صورت JSON بازگردانده می‌شوند و quickstart آن‌ها را با 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"

هر دو متغیر باید حاوی یک شناسه باشند. مقدار خالی در $SB به این معنی است که sandbox هرگز راه‌اندازی نشده است؛ دلیل معمول این اتفاق، در حال ساخت بودن base image یا کمبود حافظه در میزبان است. وجود 401 به‌جای شناسه به این معنی است که 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> نتیجه را بازمی‌گرداند و مسیر /events روی همان task، یک stream زنده از نوع SSE (رویدادهای ارسالی سرور) است که فعالیت‌های agent را نشان می‌دهد. کنسول همان stream را به‌صورت یک چت نمایش می‌دهد.

برنامه سپس در http://s-<sandbox id>-3000.preview.localhost در دسترس است، که در آن 3000 پورتی است که درخواست کرده‌اید. اگر sandbox در حالت خواب (asleep) باشد، اولین درخواست به catch-all در Traefik می‌رسد، sandboxd کانتینر را شروع می‌کند، منتظر پاسخ‌دهی پورت می‌ماند و یک صفحه انتظار کوتاه نمایش می‌دهد که پس از آن به برنامه شما ریدایرکت می‌شود. اگر پیش‌نمایش هرگز از آن صفحه عبور نکرد، به این معنی است که پردازش داخل کانتینر روی پورتی که در sandbox.yaml برنامه اعلام شده، گوش نمی‌دهد.

قرار دادن پیش‌نمایش‌ها روی یک دامنه واقعی با HTTPS

هر محیط sandbox نام میزبان (hostname) اختصاصی خود را دارد، بنابراین یک رکورد DNS از نوع wildcard تمامی آن‌ها را پوشش می‌دهد. رکورد *.preview.yourdomain.com را با یک رکورد A به آدرس IP سرور اشاره دهید. سپس متغیرهای پیش‌نمایش را در .env واقع در ~/.sandboxd/src تنظیم کنید:

PREVIEW_DOMAIN=yourdomain.com
PREVIEW_ENTRYPOINT=websecure
PREVIEW_TLS=true
SANDBOXD_API_AUTH_DISABLED=false

Traefik به نیمه دیگر این پیکربندی نیاز دارد: entrypoint مربوط به websecure را در traefik/traefik.yml فعال کنید و یک certificate resolver اضافه نمایید. از چالش DNS-01 استفاده کنید، زیرا یک گواهی wildcard تمامی نام‌های میزبان پیش‌نمایش را پوشش می‌دهد. با استفاده از HTTP-01، هر sandbox جدید به صدور گواهی جداگانه نیاز خواهد داشت و در یک بعدازظهر پرکار، به‌سرعت با محدودیت‌های نرخ (rate limits) Let's Encrypt مواجه خواهید شد. گواهی‌های Wildcard از طریق چالش DNS-01 بخش DNS این فرآیند را پوشش می‌دهد.

cd ~/.sandboxd/src
docker compose up -d

آدرس‌های URL پیش‌نمایش به فرمت https://s-<id>-3000.preview.yourdomain.com در می‌آیند. پورت‌های 80 و 443 را روی فایروال باز کنید و پورت 9090 را برای دسترسی عمومی بسته نگه دارید: به قوانین پایه فایروال ufw مراجعه کنید. به یاد داشته باشید هر کسی که بتواند نام میزبان پیش‌نمایش را حدس بزند، قادر به بارگذاری برنامه خواهد بود؛ بنابراین با پیش‌نمایش‌ها مانند محتوای عمومی رفتار کنید.

کد تولیدشده در کجا قرار می‌گیرد و آیا امکان خروجی گرفتن از آن وجود دارد؟

روی میزبان، این کد در دایرکتوری داده قرار دارد. هر فضای کاری یک دایرکتوری ساده در /var/lib/sandboxed/workspaces/<id>/ است که به صورت bind mount درون کانتینر قرار می‌گیرد و فایل‌های برنامه در مسیر /home/sandbox/workspace/app داخل sandbox جای دارند. وضعیت صفحه کنترل (control plane) در یک فایل SQLite واحد در state/sandboxd.db ذخیره می‌شود و اعتبارنامه‌های رمزنگاری‌شدهٔ agent در agent-auth/ قرار دارند. هیچ‌چیز درون لایه‌های کانتینر پنهان نیست، بنابراین پشتیبان‌گیری شامل کپی کردن دایرکتوری به همراه آن فایل دیتابیس است. ابزار restic backups on a 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"}'

یک ریموت خصوصی به یک توکن دسترسی شخصی (personal access token) نیاز دارد که یک‌بار در کنسول و در بخش Settings, Git credentials تنظیم می‌شود. این توکن به صورت رمزنگاری‌شده ذخیره شده و خارج از sandbox باقی می‌ماند، بنابراین agent نمی‌تواند آن را بخواند یا بدون اطلاع شما از آن برای push استفاده کند. کد را زود و مکرر push کنید. تا زمانی که این کار را انجام ندهید، دایرکتوری فضای کاری تنها نسخهٔ موجود از کد است و DELETE /v1/apps/<id> آن را بدون امکان بازیابی حذف می‌کند.

هزینه ساخت یک پروژه بر اساس توکن‌های مدل چقدر است؟

سرویس sandboxd هزینه‌های شما را اندازه‌گیری نمی‌کند، بنابراین عددی که اهمیت دارد در کنسول ارائه‌دهنده سرویس شما قابل مشاهده است. مدل‌های رایگان OpenCode Zen هزینه‌ای ندارند، اما نسبت به مدل‌های پولی کندتر و ضعیف‌تر هستند؛ این موضوع باعث می‌شود در هر پروژه‌ای فراتر از یک برنامه ساده، به دفعات بیشتری برای اصلاح نیاز داشته باشید.

شکل صورت‌حساب از نحوه عملکرد حلقه عامل (agent loop) پیروی می‌کند. هر نوبت، محتوای متنی (context) مورد نیاز را مجدداً ارسال می‌کند، بنابراین هزینه بر اساس تعداد نوبت‌ها محاسبه می‌شود، نه تعداد برنامه‌ها. یک پرامپت که به نتیجه می‌رسد ارزان است. اما 15 دور دستور «حالا فاصله‌گذاری را اصلاح کن» برای پروژه‌ای با 50 فایل، هزینه بالایی دارد، زیرا محتوای فایل‌ها هر بار همراه با پرامپت ارسال می‌شود. توکن‌های ورودی و خروجی قیمت‌گذاری متفاوتی دارند و هزینه یک عامل برنامه‌نویسی در هر نشست محدوده واقع‌بینانه هزینه‌ها را نشان می‌دهد. پیش از آنکه کنترل یک حلقه خودکار را به دست عامل بسپارید، حتماً یک سقف هزینه (hard spend limit) در پنل ارائه‌دهنده تنظیم کنید.

پاک‌سازی محیط‌های sandbox قدیمی

قابلیت idle reaper هر sandbox که بیش از SANDBOXD_IDLE_THRESHOLD_SECONDS غیرفعال بوده باشد را متوقف می‌کند؛ مقدار پیش‌فرض این بازه 2100 ثانیه یا 35 دقیقه است. این کار حافظه RAM را آزاد کرده و فایل‌ها را حفظ می‌کند؛ درخواست بعدی به URL پیش‌نمایش، container را دوباره بیدار می‌کند. در سرورهای کوچک این مقدار را کاهش دهید، زیرا 35 دقیقه بیکاری containerها به معنای 35 دقیقه اشغال حافظه‌ای است که نمی‌توانید از آن استفاده کنید.

متوقف کردن به معنای حذف کردن نیست و این همان جایی است که دیسک‌ها به‌آرامی پر می‌شوند. یک sandbox متوقف‌شده همچنان مالک workspace و container خود باقی می‌ماند. حذف sandbox در حالی که برنامه حفظ شود، یک DELETE روی sandbox است که container و 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 فضای قابل‌بازیافت بیشتری از آنچه انتظار دارید نشان خواهد داد، زیرا هر برنامه‌ای که toolchain اختصاصی خود را دریافت کرده، لایه‌هایی از خود بر جای گذاشته است. دستور docker image prune لایه‌های معلق (dangling) را پاک می‌کند. ابتدا GET /v1/apps را بررسی کنید، زیرا تصویری که هنوز توسط یک sandbox در حال خواب ارجاع داده می‌شود، زباله (garbage) محسوب نمی‌شود.

مرز کانتینر چه چیزی را تأمین می‌کند و چه چیزی را تأمین نمی‌کند

هر sandbox با یک کاربر بدون امتیاز (unprivileged)، سیستم‌فایل root فقط‌خواندنی، حذف تمامی قابلیت‌های Linux و تنظیم no-new-privileges، سقف حافظه و محدودیت تعداد پردازش اجرا می‌شود. این پروژه در مورد محدودیت‌های خود صادق است: کانتینر لینوکسی که از هسته (kernel) مشترک استفاده می‌کند، یک مرز جداسازی قوی اما یک مرز امنیتی ضعیف است. یک باگ در هسته به معنای نفوذ به میزبان (host) است.

دو واقعیت نیازمند اقدام هستند. خروجی شبکه (egress) از یک sandbox در نسخه self-hosted باز است، بنابراین کد تولیدشده می‌تواند به اینترنت، شبکه محلی شما و نقاط پایانی متادیتای ابری دسترسی پیدا کند. یک زیرسیستم خروجی nftables در سورس‌کد وجود دارد اما در نسخه قابل حمل Docker Compose غیرفعال شده است؛ این یعنی محدودیت‌ها باید توسط فایروال میزبان شما اعمال شوند. همچنین، API کنترل‌پلن عملاً دارای دسترسی root میزبان است، زیرا Docker socket را مدیریت می‌کند. این API به‌طور پیش‌فرض روی 127.0.0.1:9090 گوش می‌دهد، SANDBOXD_API_AUTH_DISABLED باید حتماً false باقی بماند و هرگز نباید در اینترنت منتشر شود.

اگر قصد دارید به افراد دیگر اجازه دهید تا درخواست‌های خود را به سیستم شما ارسال کنند، این مدل به‌تنهایی بسیار ضعیف است. این پروژه استفاده از gVisor با SANDBOXD_RUNTIME=runsc را پیشنهاد می‌دهد که یک هسته در فضای کاربری (userspace kernel) بین sandbox و میزبان قرار می‌دهد و در پردازش‌های سنگین syscall، حدود 1.7 تا 4 برابر کندتر عمل می‌کند. پاسخ قوی‌تر، اختصاص یک ماشین به هر کاربر است که همان استدلال مطرح‌شده در اجرای عامل‌های برنامه‌نویسی در یک VM یک‌بارمصرف است.

آیا باید پروژه‌ای با قدمت دو ماه را مبنای کار قرار داد؟

برای یک سیستم شخصی، بله، با رعایت احتیاط‌های بدیهی: نسخه SANDBOXD_REF را ثابت (pin) کنید، از /var/lib/sandboxed نسخه پشتیبان تهیه کنید و هر برنامه‌ای که برایتان اهمیت دارد را به یک مخزن git راه دور push کنید. برای هر چیزی که مشتری با آن سروکار دارد، تا انتشار نسخه 1.0 صبر کنید یا بودجه‌ای برای خرابی‌های احتمالی در نظر بگیرید، زیرا توسعه‌دهندگان به‌صراحت اعلام کرده‌اند که نسخه‌های 0.x ممکن است بدون اطلاع قبلی تغییر کنند. همچنین توسعه‌دهندگان از آگوست 2026 یک سرویس نصب مدیریت‌شده با قیمت 79 دلار در ماه ارائه می‌دهند که دانستن آن هنگام ارزیابی دلایل بقای پروژه مفید است.

دلیل قابل‌قبول بودن این ریسک، خروجی کار است. sandboxd یک اپلیکیشن معمولی در یک مخزن git معمولی تولید می‌کند؛ بنابراین اگر پروژه متوقف شود، شما کد را حفظ می‌کنید و فقط wrapper را از دست می‌دهید. این وضعیت بسیار بهتر از استفاده از یک سرویس build میزبانی‌شده است که مالکیت پروژه شما را در اختیار دارد. برای دیدگاهی گسترده‌تر درباره اینکه چه مواردی در سال 2026 ارزش میزبانی شخصی (self-hosting) را دارند، به چه چیزی در سال 2026 ارزش میزبانی شخصی دارد مراجعه کنید.

FAQ

حداقل مشخصات سرور برای sandboxd چقدر است؟

این پروژه اعلام کرده است که 2 هسته vCPU و 4 گیگابایت رم برای شروع کافی است که شامل control plane، Traefik و یک sandbox کوچک می‌شود. اگر می‌خواهید چندین برنامه را هم‌زمان فعال نگه دارید، از 8 گیگابایت رم و 40 گیگابایت فضای دیسک استفاده کنید، زیرا هر sandbox در حال اجرا، یک toolchain کامل Node یا Python را در خود جای می‌دهد و هر workspace درخت وابستگی‌های (dependency tree) مخصوص به خود را روی دیسک نگه می‌دارد. هنگامی که منابع میزبان کم می‌آید، قابلیت pressure reaper در sandboxd برای آزاد کردن حافظه، sandboxها را متوقف می‌کند و buildهایی که از سقف حافظه کانتینر خود فراتر بروند توسط kernel کشته می‌شوند: docker ps -a برای این وضعیت کد خروج 137 را نشان می‌دهد.

تفاوت sandboxd با Dify یا OpenHands چیست؟

آن‌ها خروجی‌های متفاوتی تولید می‌کنند. Dify برنامه‌هایی می‌سازد که در زمان اجرا مدل را فراخوانی می‌کنند، مانند رابط‌های چت و خط‌لوله‌های بازیابی (retrieval pipelines). OpenHands مخزنی که از قبل دارید را ویرایش می‌کند، دستورات را اجرا کرده و تغییراتی را برای کدهای موجود پیشنهاد می‌دهد. sandboxd یک پروژه کاملاً جدید را از روی یک prompt داربست‌بندی (scaffold) می‌کند، آن را درون کانتینر اختصاصی خود build کرده و در یک URL پیش‌نمایش ارائه می‌دهد؛ نتیجه یک برنامه وب معمولی است که برای اجرا به مدل نیاز ندارد.

کدی که عامل (agent) می‌نویسد در کجا ذخیره می‌شود؟

روی فایل‌سیستم میزبان، نه داخل image کانتینر. هر برنامه یک دایرکتوری در /var/lib/sandboxed/workspaces/<id>/ دریافت می‌کند که به صورت bind mount به sandbox متصل می‌شود و فایل‌ها در مسیر /home/sandbox/workspace/app داخل آن ظاهر می‌شوند. وضعیت control plane یک فایل SQLite واحد در مسیر state/ در همان دایرکتوری داده است. شما می‌توانید از طریق تب Git در کنسول یا از طریق endpointهای /v1/apps/<id>/git/commit و /git/push، تغییرات را commit کرده و به یک git remote push کنید؛ توکن مربوط به remoteهای خصوصی توسط control plane به صورت رمزنگاری‌شده ذخیره می‌شود و در اختیار sandbox قرار نمی‌گیرد.

آیا قرار دادن sandboxd در معرض اینترنت امن است؟

URLهای پیش‌نمایش و کنسول را در معرض دید قرار دهید، اما هرگز API مربوط به control plane را در معرض اینترنت نگذارید. آن API، داکر را روی میزبان کنترل می‌کند و بنابراین معادل دسترسی root است؛ به همین دلیل به‌طور پیش‌فرض روی 127.0.0.1:9090 گوش می‌دهد. sandboxها همچنین در نسخه self-hosted دارای خروجی شبکه (egress) باز هستند، به این معنی که کدی که عامل می‌نویسد می‌تواند به شبکه محلی شما و endpointهای متادیتای ابری دسترسی پیدا کند؛ بنابراین اگر در شبکه میزبان همسایه‌هایی دارید که ارزش محافظت دارند، قوانین فایروال میزبان را اعمال کنید. برای promptهای دریافتی از افرادی که به آن‌ها اعتماد ندارید، به جای تکیه بر مرزهای کانتینر، به ازای هر کاربر (tenant) یک میزبان مجزا اجرا کنید.

#sandboxd#ai-agents#self-hosted#app-builder#docker