SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-28

Как развернуть SandBase Harness на собственном VPS

Пошаговое руководство по установке SandBase v0.3.2 на ваш сервер. Настройка YAML конфигурации, подключение MCP серверов, выбор режимов песочницы и интеграция с Anthropic SDK.

Что вы получаете при самостоятельном хостинге среды выполнения агента SandBase

Самостоятельный хостинг среды выполнения SandBase означает запуск SandBase Harness на собственном сервере. В этом случае сессии, учетные данные, память и журналы аудита хранятся на вашем диске, а не на сторонних ресурсах. Это Node-сервис. Он ожидает подключений на 127.0.0.1:3000, предоставляет HTTP API /v1 и веб-консоль, а также хранит свое состояние в SQLite рядом с файлами вашего агента.

API /v1 спроектирован по аналогии с Claude Managed Agents (CMA) — облачным API для управления агентами. Именно это делает данную среду выполнения универсальной: вы можете писать код с использованием Anthropic SDK, указывая в качестве baseURL адрес вашего сервера, а затем перенести этот же код в облачную среду.

SandBase Harness не поставляется с предустановленной моделью. Он обращается к ней по запросу. По состоянию на август 2026 года поддерживаются OpenAI, Anthropic и совместимые с OpenAI конечные точки, что позволяет использовать собственные шлюзы и таких провайдеров, как DeepSeek V4. Вам по-прежнему потребуется предоставить API-ключ или использовать локальный сервер, поддерживающий протокол OpenAI API.

Что необходимо перед началом работы

  • VPS под управлением Ubuntu 24.04 с объемом оперативной памяти не менее 2 GB. Сборка TypeScript — самый ресурсоемкий этап установки.
  • Node.js версии 22 или новее, и npm версии 10 или новее. Это жесткие минимальные требования, установленные разработчиками проекта.
  • git, а также API-ключ для выбранного вами провайдера моделей.
  • Docker, если вы планируете использовать изолированные контейнеры для каждой сессии.

В репозиториях Ubuntu 24.04 поставляется Node 18.19, что ниже минимально допустимой версии, поэтому устанавливайте Node из NodeSource.

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs git
node -v
npm -v

Команда node -v должна выводить v22 или выше, а npm -v — 10 или выше. Если node -v по-прежнему выводит v18.19.1, значит, установлена версия из репозитория дистрибутива, которая имеет приоритет в PATH. Удалите её перед продолжением, так как процесс сборки использует ту версию node, которую оболочка находит первой.

Установка SandBase из тега v0.3.2

Выполняйте установку из тега, а не из нестабильной ветки. «Голый» клон main предоставит вам код, который был добавлен час назад, и приведенные ниже ключи конфигурации могут с ним не совпасть. v0.3.2 — это актуальный тег на 16 августа 2026 года.

sudo install -d -o "$USER" -g "$USER" /opt/sandbase
cd /opt/sandbase
git clone --branch v0.3.2 --depth 1 https://github.com/sandbaseai/sandbase-harness.git
cd sandbase-harness
npm ci
npm run build

Используйте npm ci, а не npm install. ci устанавливает точные версии, зафиксированные в закоммиченном lock-файле, поэтому ваше дерево будет соответствовать дереву, которое тестировали разработчики. npm install разрешено подтягивать более новые версии, из-за чего закрепленный тег может незаметно перестать быть таковым.

Теперь создайте рабочую область (workspace). Рабочая область — это отдельный каталог, в котором хранятся файлы агента и все данные времени выполнения. Размещение этой области вне каталога с исходным кодом позволяет обновлять тег, не затрагивая ваши данные.

mkdir -p /opt/sandbase/workspace
cd /opt/sandbase/workspace
node /opt/sandbase/sandbase-harness/dist/index.js init
node /opt/sandbase/sandbase-harness/dist/index.js start

init создает каталог .managed-agents/ внутри рабочей области. start запускает консоль на http://127.0.0.1:3000/dashboard и API на http://127.0.0.1:3000/v1. Пока ни то, ни другое недоступно с вашего ноутбука, что является ожидаемым поведением и будет рассмотрено далее. На данный момент подключайтесь к консоли через SSH:

ssh -N -L 3000:127.0.0.1:3000 you@your-server

Этот длинный путь node .../dist/index.js утомляет, поэтому присвойте ему имя.

alias sandbase='node /opt/sandbase/sandbase-harness/dist/index.js'

Приведенные ниже команды написаны как sandbase <command> с учетом этого сокращения.

Не устанавливайте пакет из npm

В документации по установке самого проекта указано: пакет без области видимости managed-agents, доступный в npm, не относится к данному проекту. Поэтому команды npx managed-agents и npm install -g managed-agents загружают компоненты, не имеющие отношения к нужной вам среде выполнения. Выполняйте установку из исходного кода с тегом в GitHub, пока разработчики не выпустят официальный пакет с областью видимости. Это не просто примечание в истории проекта: версия v0.3.1 была выпущена главным образом для того, чтобы заменить старый способ быстрого запуска через npm на путь к зафиксированной версии в исходном коде.

Укажите провайдера моделей для рабочей области

init записывает .managed-agents/config.yaml. Для всей рабочей области настраивается один провайдер, а конкретные идентификаторы моделей затем выбираются отдельными агентами.

model:
  provider: openai
  api_key: ${OPENAI_API_KEY}
storage:
  metadata:
    provider: sqlite
    options: {}
  artifacts:
    provider: local
    options:
      base_path: files

Форма ${OPENAI_API_KEY} получает значение из переменных окружения процесса, поэтому ключ не попадает в конфигурационный файл и в любые его резервные копии. Поместите его в файл окружения, доступный для чтения только пользователю root, так как systemd считывает EnvironmentFile= от имени root до того, как понизит привилегии.

sudo install -d -m 750 /etc/sandbase
sudo touch /etc/sandbase/runtime.env
sudo chmod 600 /etc/sandbase/runtime.env

Откройте этот файл в редакторе и добавьте одну строку: OPENAI_API_KEY=sk-.... Здесь должны храниться ключи провайдеров. Секреты, которые агент использует во время сеанса, следует хранить в хранилищах учетных данных среды выполнения — это другая задача с другим радиусом поражения, и статью как не допустить попадания секретов в AI-агенты стоит прочитать до того, как вы вставите рабочий токен в любое из этих мест.

YAML-файл агента: mcp_servers, инструменты и политики разрешений

Агенты определяются как YAML-файлы в директории agents/ рабочей области. Это та часть среды выполнения, с которой вы будете работать чаще всего. Назначение ключей становится понятнее после того, как вы самостоятельно напишете простой цикл агента, так как каждый из них — это настройка того, что иначе пришлось бы программировать вручную: системный промпт, список инструментов и проверка, выполняемая перед запуском инструмента.

name: Incident commander
description: Triages alerts and coordinates response.
model: gpt-4o
system: |-
  You are an on-call incident commander.
mcp_servers:
  - name: sentry
    type: url
    url: https://mcp.sentry.dev/mcp
tools:
  - type: agent_toolset_20260401
    default_config:
      permission_policy: { type: always_ask }
    configs:
      - name: bash
        permission_policy: { type: always_ask }
  - type: mcp_toolset
    mcp_server_name: sentry
metadata:
  template: incident-commander

Загрузите его и проверьте, что он был успешно добавлен:

sandbase reload
sandbase list
sandbase chat agent_assistant --message "hello"

reload импортирует исходный YAML в SQLite. list теперь должен вывести агента с присвоенным ID. Если list не отображает его, значит, файл не был обработан, и причина этого записана в .managed-agents/logs/runtime.log.

mcp_servers объявляет конечные точки MCP (model context protocol). type: url означает, что среда выполнения обменивается данными по HTTP с сервером, работающим в другом месте. Поэтому здесь можно использовать всё, чем вы уже управляете, включая MCP-серверы, размещённые на том же VPS, что и среда выполнения. Веб-поиск обычно становится первым инструментом, к которому обращаются пользователи. Перед его подключением стоит прочитать о передаче агенту собственного экземпляра SearXNG, поскольку инструмент, возвращающий страницы, написанные посторонними пользователями, помещает непроверенный текст непосредственно в контекст модели. Более безопасный первый вариант интеграции имеет обратную структуру: доступная только для чтения конечная точка поверх данных, которыми вы уже владеете. Именно это предоставляет openGym рядом с самим трекером тренировок. Агент сможет отвечать на вопросы об истории тренировок, но не сможет изменять эти данные.

Объявление сервера не передает его инструменты агенту. Это делает список tools через запись mcp_toolset, в которой mcp_server_name совпадает с name выше. Если агент ведет себя так, будто инструменты MCP отсутствуют, сравните эти две строки символ в символ, прежде чем искать проблему в другом месте.

agent_toolset_20260401 — это встроенный набор инструментов. Суффикс с датой — это версия схемы, поэтому агент, привязанный к ней, сохраняет те определения инструментов, для которых он был написан. default_config устанавливает политику для каждого инструмента в наборе, а каждая запись в configs переопределяет конкретный инструмент по имени, например bash.

permission_policy — это то, за счет чего среда выполнения выигрывает по сравнению с прямым вызовом модели. always_ask приостанавливает сессию и ожидает одобрения человека перед выполнением вызова. always_allow разрешает его выполнение. Установка bash в значение always_ask означает, что агент не сможет выполнить shell-команду, пока вы не увидите её в явном виде. Это тот же уровень контроля, который вы используете при безопасном запуске Claude Code на VPS. Если вы также используете DeepSeek Harness, аналогичные элементы управления добавляются туда в виде расширений, а не YAML-ключей, и плагины, ограничивающие бюджеты и контролирующие вызовы инструментов, являются ближайшим аналогом этого блока.

Три режима песочницы и сценарии их использования

Вызовы инструментов, выполняющие код, запускаются внутри песочницы. Бэкенд выбирается для каждой среды через sandbox_provider в объекте config среды или в консоли в разделе Settings, а затем Sandbox. Среды создаются через API по адресу POST /v1/environments.

local запускает код как дочерний процесс среды выполнения на хосте от имени пользователя, под которым работает сама среда. Это режим по умолчанию; он приемлем, если вы единственный пользователь, а агент только читает принадлежащие вам файлы. Это не изоляция. Вызов инструмента, удаляющий файлы, удалит ваши файлы, а вызов, читающий /etc/sandbase/runtime.env, получит доступ к вашему ключу провайдера.

docker запускает один контейнер на сессию.

{
  "sandbox_provider": "docker",
  "image": "node:22-slim",
  "resources": { "memory": "1g", "cpu": 1 }
}

Сессия получает собственную файловую систему, ограничение по памяти и долю ресурсов CPU, а контейнер удаляется вместе с сессией. Переключайтесь на этот режим, как только агент начинает выполнять код, написанный не вами. Минус в том, что пользователю среды выполнения нужен доступ к Docker socket, а членство в группе docker эквивалентно правам root на хосте. Контейнеры для каждой сессии устроены так же, как self-hosted agent sandboxes with one container per run, поэтому рассуждения о том, к чему может получить доступ сбежавший процесс, применимы здесь в полной мере.

kubernetes запускает рабочую нагрузку сессии в виде пода и управляет ею с помощью kubectl exec и kubectl cp. В образе среды выполнения должен присутствовать kubectl, а его ServiceAccount должен иметь права RBAC (управление доступом на основе ролей) для создания, удаления, получения, перечисления и отслеживания подов в целевом пространстве имен, а также доступ к подресурсу exec. Этот режим стоит настраивать, только если у вас уже есть работающий кластер.

Почему среда выполнения привязана к 127.0.0.1?

Потому что она запускается с отключенной аутентификацией. Среда выполнения включает аутентификацию по bearer-токену, когда существует хотя бы один API key, а свежая установка init не создает ни одного. Привязка к 0.0.0.0 по умолчанию привела бы к тому, что неаутентифицированная среда выполнения агента, имеющая доступ к инструментам командной оболочки и вашему ключу провайдера, оказалась бы доступна из публичного интернета.

Поэтому, если вы хотите сделать её доступной, оставьте адрес привязки без изменений и выполните два других действия.

Во-первых, включите аутентификацию. Установите MANAGED_AGENTS_API_KEY в файле окружения службы или создайте ключ с помощью POST /v1/api-keys, который один раз вернет поле secret_key и больше никогда его не покажет. После этого клиенты должны отправлять Authorization: Bearer <key> в каждом запросе. Один ключ — это одна общая учетная запись, поэтому, если вам на самом деле нужен отдельный изолированный агент для каждого сотрудника с ключами провайдера, хранящимися в едином шлюзе, OneCLI создан именно для такой архитектуры.

Во-вторых, установите перед ней reverse proxy и настройте там TLS (transport layer security) termination. Среда выполнения по своей архитектуре работает по обычному HTTP и предполагает, что обработкой сертификатов будет заниматься стороннее ПО.

server {
    listen 443 ssl;
    server_name agents.example.com;

    ssl_certificate     /etc/letsencrypt/live/agents.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/agents.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        proxy_buffering off;
        proxy_read_timeout 3600s;
    }
}

Две из этих строк — не просто оформление. proxy_buffering off важна, так как сессии передаются через server-sent events (SSE), и при включенном буферизации nginx удерживает ответ до заполнения буфера, из-за чего консоль ничего не показывает во время работы агента, а затем выводит всё содержимое сразу в конце. proxy_read_timeout 3600s важна, так как значение по умолчанию составляет 60 секунд, поэтому поток, который остается неактивным дольше минуты, закрывается прокси-сервером в середине выполнения задачи, и этот сбой выглядит как падение среды выполнения.

На фаерволе откройте порты 22 и 443. Порт 3000 оставьте закрытым, так как прокси обращается к нему через loopback, и никто извне сервера не должен иметь к нему доступа.

Настройка Anthropic SDK на собственный сервер

Среда выполнения реализует поверхность /v1 в формате CMA, поэтому клиент Anthropic SDK взаимодействует с ней при изменении одного поля.

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: process.env.MANAGED_AGENTS_API_KEY ?? 'local-dev-key',
  baseURL: 'http://127.0.0.1:3000'
});

Она также принимает бета-заголовки, которые отправляют клиенты Claude Managed Agents, anthropic-beta: managed-agents-2026-04-01 и anthropic-beta: agent-memory-2026-07-22. При работе с локальной средой выполнения они необязательны. Они существуют для того, чтобы код, написанный для развертывания в облаке, работал здесь без изменений.

Совместимость близка к полной, но не абсолютна. Ознакомьтесь с docs/api-matrix.md в локальной копии репозитория, прежде чем предполагать наличие какой-либо функции, так как проект документирует свои ограничения, включая пользовательские инструменты на стороне клиента, которые по-прежнему требуют именованной регистрации поверх текущего протокола событий-результатов.

Обычный HTTP работает так же хорошо и является самым быстрым способом убедиться, что среда выполнения активна:

curl -N -X POST http://127.0.0.1:3000/v1/sessions/SESSION_ID/messages \
  -H "Content-Type: application/json" \
  -d '{"content": "Hello", "stream": true}'

Корректный ответ представляет собой поток событий, который продолжает поступать. Если соединение прервалось, возобновите работу с последнего увиденного события вместо повторного воспроизведения всего цикла:

curl -N http://127.0.0.1:3000/v1/sessions/SESSION_ID/events/stream \
  -H "Last-Event-ID: EVENT_ID"

Этот возобновляемый поток — причина, по которой сессия сохраняется при закрытии ноутбука. События сохраняются на сервере, поэтому клиент воспроизводит журнал, а не хранит единственную копию данных.

Где на диске хранятся учетные данные, память и журналы аудита

Все, чем управляет среда выполнения, находится в каталоге .managed-agents/ внутри рабочей области.

.managed-agents/
├── config.yaml
├── data.db
├── logs/runtime.log
├── files/
├── skills/
├── snapshots/
└── sandbox/
  • data.db — метаданные SQLite: агенты, сессии, записи хранилища учетных данных, записи хранилища памяти и API-ключи.
  • files/ содержит байты загруженных файлов, а skills/ — загруженные пакеты навыков.
  • snapshots/ хранит снимки рабочих областей сессий, а sandbox/ — рабочие каталоги сессий в локальном режиме.
  • logs/runtime.log — первое место, куда стоит заглянуть, если что-то перестало работать без вывода ошибок.

Хранилища учетных данных — это группы секретов, каждая из которых добавляется с помощью auth_type, например environment_variable, и привязывается к сессии через vault_ids при её создании. Хранилища памяти содержат именованные записи, которые вы подключаете к сессии как memory_store с собственными настройками доступа и инструкциями. И то, и другое находится в data.db, что и составляет принципиальное отличие от обычного вызова модели: среда выполнения запоминает данные между сессиями и записывает историю событий.

Поскольку это единый каталог, создавайте его резервную копию целиком.

sudo systemctl stop sandbase
sudo tar czf /root/sandbase-$(date +%F).tgz -C /opt/sandbase/workspace .managed-agents
sudo systemctl start sandbase

Сначала остановите службу. Копирование базы данных SQLite во время записи может привести к созданию поврежденного файла, который не откроется при восстановлении, и вы узнаете об этом в самый неподходящий момент. Если вы предпочитаете хранить YAML-файлы агентов в git, а состояние — в другом месте, документация по развертыванию позволяет зафиксировать расположение состояния с помощью --data-dir в start.

Восстановление выполняется в обратном порядке: разверните ту же версию на новом сервере, распакуйте архив в рабочую область и запустите службу. Ваш ключ провайдера не попадет в архив, если вы использовали форму ${OPENAI_API_KEY}, поэтому сохраните его отдельно в надежном месте.

Запуск через systemd

Создайте для процесса отдельного пользователя, чтобы вызов инструмента в режиме локальной песочницы не мог выполняться от вашего имени.

sudo adduser --system --group --no-create-home --home /opt/sandbase sandbase
sudo chown -R sandbase:sandbase /opt/sandbase

Сохраните это как /etc/systemd/system/sandbase.service.

[Unit]
Description=SandBase Harness runtime
After=network-online.target

[Service]
User=sandbase
Group=sandbase
WorkingDirectory=/opt/sandbase/workspace
EnvironmentFile=/etc/sandbase/runtime.env
ExecStart=/usr/bin/node /opt/sandbase/sandbase-harness/dist/index.js start --host 127.0.0.1 --port 3000
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

В примере развертывания от разработчиков проекта используется бинарный файл managed-agents по пути PATH. При установке из исходного кода с тегами такой файл не создается, поэтому ExecStart запускает node напрямую через скомпилированную точку входа.

sudo systemctl daemon-reload
sudo systemctl enable --now sandbase
sudo systemctl status sandbase
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/dashboard

При успешном выполнении вы получите active (running) из status и 200 из curl. Если результат отличается, сначала изучите journalctl -u sandbase -n 50, а затем .managed-agents/logs/runtime.log. enable --now — это критически важная часть, так как процесс, запущенный вручную, завершится после следующей перезагрузки сервера.

Что может сломаться и какие сообщения вы увидите

npm run build завершается без ошибки со стороны npm. На VPS с 1 GB оперативной памяти процесс компиляции TypeScript принудительно завершается OOM-killer (out-of-memory killer) ядра. Информация об этом попадает в системный журнал, а не в вывод npm. Проверьте это с помощью journalctl -k | grep -i "out of memory": команда выведет строку с названием завершенного процесса node. Добавьте swap или выполните сборку на более мощном сервере, а затем скопируйте dist/.

Error: listen EADDRINUSE: address already in use 127.0.0.1:3000. Порт уже занят другим процессом. sudo ss -lntp | grep 3000 покажет, какой именно процесс его использует. Остановите этот процесс или запустите среду выполнения с --port 3001 и обновите настройки прокси.

Дашборд не открывается с вашего ноутбука. Это ожидаемое поведение, так как среда выполнения привязывается к интерфейсу loopback. Используйте SSH-туннель, как описано выше, или завершите настройку reverse proxy. Не пытайтесь «исправить» это с помощью --host 0.0.0.0, так как аутентификация отключена до тех пор, пока не будет создан ключ.

Песочницы Docker завершаются с ошибкой permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock. Пользователь sandbase не входит в группу docker. Исправьте это командой sudo usermod -aG docker sandbase и перезапустите сервис. Помните: эта группа обладает правами root на хосте, поэтому такое решение частично нивелирует смысл использования отдельного пользователя для среды выполнения.

Песочницы Kubernetes завершаются с ошибкой Error from server (Forbidden). У ServiceAccount отсутствуют права на работу с подами или подресурсом exec. Проверьте права напрямую с помощью kubectl auth can-i create pods/exec -n <namespace>, которая вернет yes или no.

Каждый запрос возвращает 401 после добавления API-ключа. Аутентификация включается автоматически при создании первого ключа и применяется как к консоли, так и к API. Передавайте Authorization: Bearer <key>. Если вы потеряли ключ, создайте новый, так как secret_key отображается только один раз и не сохраняется в читаемом виде.

Инструменты MCP-сервера не появляются в сессии. Сверьте mcp_server_name в блоке tools с name в mcp_servers, затем убедитесь, что среда выполнения может получить доступ к URL с самого сервера с помощью curl -i <url>. MCP-сервер типа URL является сетевой зависимостью, а VPS может разрешать имена и маршрутизировать трафик иначе, чем ваш ноутбук.

FAQ

Можно ли запустить SandBase Harness без ключа OpenAI или Anthropic?

Да, если у вас есть эндпоинт, совместимый с OpenAI. Среда выполнения поддерживает OpenAI, Anthropic и провайдеров, совместимых с OpenAI, поэтому локальный сервер, поддерживающий API OpenAI, будет работать. Укажите провайдера рабочей области в .managed-agents/config.yaml и направьте на него api_key и эндпоинт. Среда выполнения не содержит встроенных моделей, поэтому для обработки вызовов необходим внешний сервис.

Безопасно ли открывать среду выполнения на публичном порту?

В стандартной конфигурации — нет. Она привязывается к 127.0.0.1:3000 и запускается без аутентификации, и простое изменение адреса привязки не решит проблему. Создайте API-ключ или задайте MANAGED_AGENTS_API_KEY, чтобы включить аутентификацию через bearer-token. Затем установите nginx или Caddy перед приложением для TLS и закройте порт 3000 на межсетевом экране, чтобы доступ осуществлялся только через прокси.

В чем разница между локальной песочницей, Docker и Kubernetes?

local запускает код инструментов как дочерний процесс среды выполнения на хосте с правами пользователя, от имени которого запущен процесс, без изоляции. docker предоставляет каждой сессии отдельный контейнер с собственной файловой системой, лимитами памяти и долей CPU, который удаляется после завершения сессии. kubernetes запускает сессию как под и управляет ею с помощью kubectl exec, что требует наличия kubectl внутри образа среды выполнения, RBAC для подов, а также доступа к подресурсу exec в целевом пространстве имен.

Что именно нужно резервировать?

Каталог .managed-agents/ в рабочей области. В нем хранятся config.yaml, база данных SQLite data.db с агентами, сессиями, записями хранилища учетных данных и памяти, а также загруженные файлы, пакеты навыков и снимки сессий. Остановите сервис перед копированием, чтобы SQLite не находился в процессе записи во время создания архива. API-ключи провайдеров, на которые ссылается ${OPENAI_API_KEY}, не входят в резервную копию, поэтому храните их отдельно.

Почему стоит клонировать тег v0.3.2, а не ветку main?

Тег — это зафиксированное состояние дерева исходного кода, поэтому ключи конфигурации и команды CLI, о которых вы читаете, будут соответствовать тому, что вы получите. main меняется, и ключ конфигурации может быть переименован в период между написанием руководства и его выполнением. Проект также предупреждает, что пакет managed-agents в npm не относится к данному проекту, поэтому npx managed-agents установит не то, что нужно. Релиз v0.3.1 существует в основном для того, чтобы заменить быстрый старт через npm на путь к зафиксированному тегу исходного кода.