Как запустить sandboxd на собственном VPS
Пошаговое руководство по развертыванию sandboxd для создания AI приложений. Настройка Docker, ключей моделей, HTTPS через Traefik, лимитов RAM и очистка старых контейнеров.
Что такое sandboxd и что дает его самостоятельный запуск
Для самостоятельного размещения sandboxd вам потребуется один Linux-сервер с Docker и доменное имя. Вы отправляете запрос (prompt), агент по написанию кода создает полноценное приложение внутри изолированного контейнера, и это приложение становится доступным по собственному URL для предварительного просмотра. Генераторы приложений по запросу — самая популярная категория сервисов в 2026 году, а sandboxd — это решение, которое работает на вашем VPS под лицензией MIT, при этом сгенерированный код хранится на вашем собственном диске.
Архитектура намеренно сделана компактной. Панель управления на Go управляет Docker, Traefik v3 маршрутизирует каждое имя хоста для предварительного просмотра, SQLite хранит состояние, а каждое приложение работает в отдельном контейнере. Здесь нет Kubernetes и отдельного сервера баз данных, поэтому система способна работать даже на машине с 2 vCPU.
Вся модель строится на четырех объектах. App (приложение) — это постоянный проект, содержащий свое имя, метаданные git и секреты. Sandbox (песочница) — это Docker-контейнер, в котором работает приложение; одно приложение в каждый момент времени связано с одной песочницей. Workspace (рабочая область) — это файлы приложения, которые находятся на хосте и сохраняются после остановки контейнера. Task (задача) — это один запрос, переданный агенту внутри песочницы. Остановка песочницы освобождает память, но сохраняет файлы. Удаление песочницы уничтожает контейнер, после чего приложение может запустить новый.
В чем разница между sandboxd, Dify и OpenHands?
Эти три инструмента часто путают, так как все они запускают LLM (большую языковую модель) на вашем сервере, но результат их работы различается. Dify создает приложения на базе LLM: чат-интерфейсы, конвейеры поиска (retrieval pipelines) и рабочие процессы, которые обращаются к модели при каждом использовании. Модель является частью готового продукта. OpenHands работает с уже существующим репозиторием: вы указываете путь к коду, и инструмент читает файлы, выполняет команды и предлагает изменения. sandboxd начинает с нуля. Он создает каркас проекта на основе шаблона, собирает его в изолированном контейнере и предоставляет URL для просмотра. На выходе получается обычное приложение на React или FastAPI, которому для работы не требуется модель.
Выбирайте инструмент в зависимости от того, что вы хотите получить в итоге. sandboxd предназначен для создания проекта из текстового описания с последующим сохранением кода. Два других инструмента подходят для случаев, когда репозиторий или продукт на базе модели уже существуют.
Другое различие заключается в возрасте проекта, и это фактор, который стоит оценить перед тем, как строить на его основе что-то серьезное.
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 июня 2026 года, поэтому по состоянию на август 2026 года проекту два месяца, в то время как OpenHands существует с марта 2024 года, а Dify — с апреля 2023 года. Релиз v0.1.0 вышел 6 июня 2026 года, а v0.3.6 — 1 августа 2026 года. Проект позиционирует себя как бета-версию и предупреждает, что релизы 0.x могут нарушать обратную совместимость. Воспринимайте эти цифры как риск при выборе зависимости, а не как оценку качества: двухмесячный проект прошел лишь два месяца тестирования другими пользователями, которые находили в нем ошибки.
Что нужно серверу и что ломается при нехватке ресурсов
В документации проекта указано, что для запуска достаточно 2 vCPU и 4 GB RAM. Это верно для управляющей плоскости (control plane) и одной небольшой «песочницы» (sandbox), но этого недостаточно для одновременной работы двух пользователей. Планируйте распределение памяти по частям. Traefik и управляющая плоскость на Go потребляют мало ресурсов. Каждая запущенная «песочница» содержит полноценный инструментарий Node или Python, а пиковая нагрузка приходится на npm install, за которым следует сборка production-версии. Рассчитывайте на 8 GB для сервера, который должен поддерживать работу нескольких приложений, и рассматривайте swap как страховку, а не как основной объем памяти, так как сборка, ушедшая в swap, будет выполняться минуты вместо секунд.
При нехватке памяти возникают два разных типа сбоев, которые выглядят совершенно по-разному. Внутри «песочницы» контейнер достигает жесткого лимита --memory, установленного sandboxd, и ядро завершает самый ресурсоемкий процесс, поэтому сборка прерывается без полезных сообщений от агента. docker ps -a показывает код завершения 137 для этого контейнера, а docker inspect сообщает о нем "OOMKilled": true. Сборка на Node, которая завершается таким образом, часто перед этим выводит JavaScript heap out of memory.
Второй тип сбоя происходит на хосте. sandboxd запускает механизм очистки по давлению памяти (pressure reaper), который останавливает «песочницы» при нехватке памяти на хосте, поэтому на слабом сервере «песочница» может исчезнуть прямо во время просмотра превью. Файлы остаются в безопасности, и следующий запрос к URL превью разбудит её, но задача, которая выполнялась в момент остановки контейнера, не возобновится.
Диск — менее очевидная проблема. Каждое приложение хранит свое рабочее пространство на хосте, а JavaScript-проект содержит дерево node_modules размером в сотни мегабайт. Десять приложений — это несколько гигабайт зависимостей еще до учета образов. Начинайте с 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.
Установщик представляет собой 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.shSANDBOXD_REF — это git-ссылка, которую установщик использует для оформления версии в $HOME/.sandboxd/src; по умолчанию используется main. Если оставить эту переменную не установленной, будет установлена версия, актуальная на момент последнего слияния кода, что критично для проекта, выпустившего шесть релизов только за июль 2026 года. Зафиксируйте версию и обновляйте её осознанно после прочтения списка изменений.
Скрипт клонирует исходный код, собирает образы, запускает стек с помощью docker compose up -d и в конце выводит URL консоли и API-токен. Сохраните этот токен в безопасном месте. Это учетные данные для API, который управляет Docker с правами root.
curl http://127.0.0.1:9090/healthzЭта команда выводит 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. Установите пароль для консоли при первом посещении.
Назначение модели агенту
В базовый образ включены два агента для написания кода: OpenCode и Claude Code. SANDBOXD_DEFAULT_AGENT определяет, какой из них выполнит задачу, если агент не указан явно; по умолчанию используется opencode. Если ключ не подключен, задачи выполняются с использованием бесплатных моделей OpenCode Zen без ключа. Таким образом, первая сборка не требует затрат, и вы можете протестировать весь цикл работы перед оплатой.
Подключите собственный ключ, если вам нужна более мощная модель. Ключи передаются в плоскость управления (control plane) и никогда не попадают в песочницу: они хранятся в зашифрованном виде в каталоге данных и передаются по сети через прокси учетных данных. Благодаря этому ни агент, ни написанный им код не могут прочитать эти ключи.
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-ключа. Модель, используемая агентом по умолчанию, настраивается на той же панели, при этом для отдельной задачи её можно переопределить.
Создание небольшого приложения от начала до конца
Создайте приложение, запустите его изолированную среду (sandbox), а затем отправьте запрос. Идентификаторы возвращаются в формате 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"Обе переменные должны содержать идентификатор. Пустое значение $SB означает, что изолированная среда не была запущена; обычно это происходит из-за того, что базовый образ всё ещё собирается или на хосте закончилась оперативная память. Значение 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"}'Ответ содержит идентификатор задачи. GET /v1/sandboxes/$SB/tasks/<task id> возвращает результат выполнения, а путь /events для той же задачи предоставляет поток SSE (server sent events) в реальном времени, отображающий действия агента. Консоль выводит тот же поток в виде чата.
Приложение становится доступным по адресу http://s-<sandbox id>-3000.preview.localhost, где 3000 — это порт, который вы запросили. Если изолированная среда находилась в спящем режиме, первый запрос попадает на catch-all в Traefik, sandboxd запускает контейнер, ожидает ответа от порта и выдаёт короткую страницу прогрева, которая автоматически обновляется до вашего приложения. Если страница предварительного просмотра не обновляется, это означает, что процесс внутри контейнера не слушает порт, указанный в sandbox.yaml приложения.
Размещение превью на реальном домене с HTTPS
У каждой «песочницы» (sandbox) есть собственное имя хоста, поэтому одна wildcard DNS-запись покрывает их все. Укажите *.preview.yourdomain.com на IP-адрес сервера с помощью A-записи. Затем задайте переменные превью в .env в файле ~/.sandboxd/src:
PREVIEW_DOMAIN=yourdomain.com
PREVIEW_ENTRYPOINT=websecure
PREVIEW_TLS=true
SANDBOXD_API_AUTH_DISABLED=falseДля Traefik требуется ответная часть: включите entrypoint websecure в traefik/traefik.yml и добавьте резолвер сертификатов. Используйте проверку DNS-01, так как один wildcard-сертификат покроет все имена хостов для превью. При использовании HTTP-01 для каждой новой «песочницы» потребовался бы отдельный выпуск сертификата, и при активной работе можно быстро упереться в лимиты Let's Encrypt. В Wildcard-сертификаты через проверку DNS-01 описана настройка DNS для этого случая.
cd ~/.sandboxd/src
docker compose up -dURL-адреса превью примут вид https://s-<id>-3000.preview.yourdomain.com. Откройте порты 80 и 443 в брандмауэре, а порт 9090 оставьте закрытым для внешнего доступа: см. базовые правила брандмауэра ufw. Помните, что любой, кто сможет угадать имя хоста превью, сможет загрузить приложение, поэтому относитесь к превью как к публичным ресурсам.
Где сохраняется сгенерированный код и можно ли его экспортировать?
На хосте — в каталоге данных. Каждое рабочее пространство представляет собой обычную директорию по пути /var/lib/sandboxed/workspaces/<id>/, которая монтируется в контейнер, а файлы приложения находятся внутри песочницы по адресу /home/sandbox/workspace/app. Состояние панели управления хранится в одном файле SQLite по пути state/sandboxd.db, а зашифрованные учетные данные агента — в 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. Он хранится в зашифрованном виде вне песочницы, поэтому агент не может прочитать его или выполнить push без вашего ведома. Выполняйте push как можно чаще. Пока вы этого не сделали, директория рабочего пространства является единственной копией кода, и команда DELETE /v1/apps/<id> удаляет её без возможности восстановления.
Во сколько обходится сборка в токенах модели?
sandboxd не отслеживает ваши расходы, поэтому итоговые цифры доступны только в консоли вашего провайдера. Бесплатные модели OpenCode Zen не требуют оплаты, но они медленнее и слабее платных моделей, что приводит к большему количеству итераций исправления для любых задач сложнее учебных приложений.
Структура счета зависит от принципа работы цикла агента. Каждый шаг отправляет необходимый контекст заново, поэтому стоимость зависит от количества итераций, а не от количества приложений. Один успешный промпт стоит недорого. Пятнадцать итераций запроса «исправь отступы» для проекта из пятидесяти файлов обойдутся дорого, так как содержимое файлов передается каждый раз. Входящие и исходящие токены тарифицируются по-разному, а в статье сколько стоит сессия агента для написания кода приведены реалистичные диапазоны цен. Установите жесткий лимит расходов у провайдера, прежде чем запускать цикл без присмотра.
Очистка неактивных песочниц
Idle reaper останавливает любую песочницу, которая простаивает дольше SANDBOXD_IDLE_THRESHOLD_SECONDS, значение по умолчанию составляет 2100 секунд, или 35 минут. Это освобождает оперативную память и сохраняет файлы, а следующий запрос к URL предварительного просмотра запускает контейнер. Уменьшите это значение на сервере с ограниченными ресурсами, так как 35 минут простоя контейнеров — это 35 минут памяти, которую вы не можете использовать.
Остановка не означает удаление, именно поэтому диски постепенно заполняются. Остановленная песочница по-прежнему владеет своим рабочим пространством и контейнером. Удаление песочницы при сохранении приложения — это DELETE для песочницы, что удаляет контейнер и рабочее пространство вместе с ней. Удаление приложения удаляет всё без возможности восстановления.
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 покажет больше места, которое можно освободить, чем вы ожидаете, так как каждое приложение, загрузившее собственный набор инструментов, оставило после себя слои. docker image prune очищает «висячие» (dangling) слои. Сначала проверьте GET /v1/apps, так как образ, на который всё ещё ссылается спящая песочница, не является мусором.
Что дает и чего не дает граница контейнера
Каждая «песочница» запускается от имени непривилегированного пользователя с корневой файловой системой в режиме «только чтение», с отключенными возможностями Linux (capabilities), установленным no-new-privileges, а также лимитами на память и количество процессов. Проект честно предупреждает об ограничениях: контейнер Linux с общим ядром — это надежная граница изоляции, но слабая граница безопасности. Ошибка в ядре означает компрометацию хоста.
Два факта требуют принятия мер. Исходящий сетевой трафик из «песочницы» в self-hosted сборке разрешен, поэтому сгенерированный код может обращаться к интернету, вашей локальной сети и конечным точкам метаданных облачных провайдеров. Подсистема исходящего трафика на базе nftables присутствует в исходном коде, но отключена при компиляции в переносимой сборке Docker Compose, что означает необходимость настройки ограничений на уровне межсетевого экрана хоста. Кроме того, API плоскости управления (control plane) фактически обладает правами root на хосте, так как управляет сокетом Docker. По умолчанию он привязывается к 127.0.0.1:9090, значение SANDBOXD_API_AUTH_DISABLED должно оставаться false, и его ни в коем случае нельзя публиковать в интернете.
Если вы планируете позволить другим пользователям отправлять запросы (промпты) в вашу среду, этой модели защиты недостаточно. Проект рекомендует использовать gVisor с SANDBOXD_RUNTIME=runsc, который помещает ядро в пространстве пользователя между «песочницей» и хостом, что замедляет работу с интенсивными системными вызовами примерно в 1.7–4 раза. Более надежное решение — выделение отдельной машины на каждого пользователя, что соответствует подходу запуска агентов для написания кода в одноразовых виртуальных машинах.
Стоит ли использовать проект, которому два месяца?
Для личного сервера сборки — да, при соблюдении очевидных мер предосторожности: зафиксируйте версию SANDBOXD_REF, создайте резервную копию /var/lib/sandboxed и отправляйте все важные приложения в удаленный git-репозиторий. Если проект предназначен для работы с клиентами, дождитесь версии 1.0 или заложите бюджет на возможные поломки, так как разработчики прямо предупреждают, что в версиях 0.x возможны любые изменения. По состоянию на август 2026 года разработчики также предлагают управляемую установку за 79 долларов в месяц; это стоит учитывать при оценке перспективности проекта.
Риск оправдан результатом работы. sandboxd создает обычное приложение в обычном git-репозитории, поэтому в случае прекращения поддержки проекта у вас останется код, а потеряется только оболочка. Это гораздо более выгодная позиция, чем использование облачного конструктора, который владеет вашим проектом. Общий обзор того, что стоит размещать на своем сервере в этом году, см. в что стоит хостить самостоятельно в 2026.
FAQ
Каковы минимальные требования к серверу для sandboxd?
Проект указывает, что 2 vCPU и 4 GB RAM достаточно для запуска, что покрывает control plane, Traefik и одну небольшую «песочницу». Используйте 8 GB RAM и 40 GB дискового пространства, если планируете запускать несколько приложений одновременно, так как каждая активная «песочница» содержит полный toolchain Node или Python, а каждое рабочее пространство хранит собственное дерево зависимостей на диске. При нехватке ресурсов на хосте механизм pressure reaper в sandboxd останавливает «песочницы» для освобождения памяти, а сборка, превысившая лимит памяти контейнера, принудительно завершается ядром: docker ps -a в этом случае показывает код завершения 137.
Чем sandboxd отличается от Dify или OpenHands?
Они создают разные артефакты. Dify строит приложения, которые обращаются к модели во время выполнения, например, чат-интерфейсы или конвейеры поиска (retrieval pipelines). OpenHands редактирует уже существующий репозиторий, выполняя команды и предлагая изменения в коде. sandboxd создает проект «с нуля» по запросу, собирает его внутри собственного контейнера и предоставляет URL для предварительного просмотра; результат — обычное веб-приложение, которому не требуется модель для работы.
Где физически находится код, который пишет агент?
В файловой системе хоста, а не внутри образа контейнера. Для каждого приложения создается каталог по пути /var/lib/sandboxed/workspaces/<id>/, который монтируется (bind mount) в «песочницу», и файлы становятся доступны по пути /home/sandbox/workspace/app внутри неё. Состояние control plane хранится в одном файле SQLite по пути state/ в том же каталоге данных. Вы можете выполнять commit и push в удаленный git-репозиторий через вкладку Git в консоли или через эндпоинты /v1/apps/<id>/git/commit и /git/push; токен для приватных репозиториев хранится в зашифрованном виде на стороне control plane, а не передается в «песочницу».
Безопасно ли открывать sandboxd в Интернет?
Открывайте доступ к URL предварительного просмотра и консоли, но никогда — к API control plane. Этот API управляет Docker на хосте, поэтому он эквивалентен доступу root, и по этой причине по умолчанию он привязан к 127.0.0.1:9090. В self-hosted версии «песочницы» также имеют открытый исходящий сетевой трафик, что означает, что код, написанный агентом, может достичь вашей локальной сети и эндпоинтов метаданных облака. Поэтому добавьте правила межсетевого экрана на хосте, если рядом есть ресурсы, требующие защиты. Для обработки запросов от пользователей, которым вы не доверяете, используйте отдельный хост для каждого арендатора, не полагаясь исключительно на изоляцию контейнеров.