SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor

Как развернуть OpenBot на своем VPS

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

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

Вы размещаете OpenBot AI-агентов самостоятельно, запуская один сервер-шлюз и по одному контейнеру на каждого бота на оборудовании под вашим контролем. Каждый контейнер с ботом содержит собственный браузер Chromium и выделенный том для рабочей области с профилем браузера, который сохраняется между сессиями. Каждое действие, которое бот выполняет в системе, с файлом, через MCP (model context protocol) сервер или с компонентом интерфейса, проходит через этот шлюз. Шлюз проверяет действие на соответствие политике перед выполнением и регистрирует его после.

OpenBot публикуется компанией CopilotKit под лицензией MIT по адресу github.com/CopilotKit/openbot. Первый релиз с тегом v0.0.1 был выпущен 17 августа 2026 года, и проект позиционирует себя как альфа-версия в стадии активной разработки. Относитесь к нему как к серьезному проекту с возможными недоработками ранней стадии.

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

Как шлюз определяет каждое действие

API-сервер на порту 3001 является единственным путем к компьютеру бота. Перед выполнением действия в браузере шлюз определяет цель по снимку страницы, оценивает правила политики CEL (common expression language) в контексте, записывает строку аудита с принятым решением и только после этого вызывает контейнер. Если после этого выполнение завершается неудачей, он записывает вторую строку. Документация четко определяет границы: компьютер не принимает решений по политике, границей действия является серверный шлюз.

Политика работает по принципу «запрещено по умолчанию», при этом правила запрета оцениваются перед правилами разрешения. Направление сбоя важнее синтаксиса правил. Отсутствие политики не разрешает ничего, а некорректное правило приводит к блокировке независимо от того, является ли оно запрещающим или разрешающим. Таким образом, ошибка в политике приведет к остановке бота, а не к его бесконтрольной работе с вашими учетными записями.

Журнал аудита хранится в PostgreSQL, поэтому он сохраняется после перезагрузки. Передача управления записывается как computer.help_requested, computer.control_taken и computer.control_released — именно так вы видите, как бот запрашивает участие человека, и как человек возвращает управление. Секреты записываются как количество символов, а не как значения. Файловые операции фиксируют путь и размер, но никогда не записывают содержимое. Если вам нужна такая же граница контроля без использования браузера, в разделе ограничение действий агентов ИИ через подтверждения рассматривается этот более узкий случай.

Потребление RAM и дискового пространства одним ботом

Проект публикует измеренные показатели для одного бота на архитектуре arm64. Это единственные цифры по планированию ресурсов, которые предоставляет OpenBot. Они описывают работу одного бота на одной архитектуре, поэтому рассматривайте их как отправную точку, а не как готовый план масштабирования.

ChartOpenBot published resource figures, one Bot on arm64 (August 2026)
The data behind this chart
[
  {
    "label": "Measured, one Bot",
    "memory_gb": 0.55,
    "disk_gb": 5.3,
    "vcpu": 0.06
  },
  {
    "label": "Documented minimum",
    "memory_gb": 2,
    "disk_gb": 8,
    "vcpu": 1
  },
  {
    "label": "Documented recommended",
    "memory_gb": 4,
    "disk_gb": 10,
    "vcpu": 2
  }
]

Пиковое потребление памяти составило 0.55 ГБ на одного бота, при этом задокументированный минимум составляет 2 ГБ, а рекомендуемый объем — 4 ГБ. Разница между измеренным значением и минимумом — это запас для Chromium при нагрузке, так как потребление памяти браузером зависит от открытых страниц, а не от процесса в состоянии покоя. Потребление CPU в простое близко к нулю и составляет 0.06 ядра в верхней границе измеренного диапазона, поэтому CPU не является критическим ресурсом. Критическим ресурсом является диск. Только сам образ занимает 5.3 ГБ при рекомендуемом объеме тома в 10 ГБ. Такой размер обусловлен тем, что в комплект поставки входят бинарные файлы Playwright для Firefox и WebKit помимо Chromium.

Эти данные не показывают стоимость запуска нескольких ботов одновременно, и проект не публикует таких цифр. Проведите измерения самостоятельно. Запустите одного бота, дайте ему реальную задачу с открытой страницей и наблюдайте за контейнером во время работы.

docker stats --no-stream
free -m

Используйте значение из столбца MEM USAGE для контейнера бота в качестве базовой цифры на одного бота, добавьте к нему потребление шлюза и PostgreSQL, а затем умножьте полученный результат на количество ботов, которые должны работать одновременно. Бот в состоянии покоя всё равно удерживает процесс браузера, поэтому множитель применяется ко всем существующим ботам, а не только к активным. Расчет выполняется так же, как описано в планировании RAM и CPU для VPS с агентом кодинга, а аспекты работы браузера рассмотрены в запуске headless-браузера для агентов на VPS.

Одна особенность Chromium влияет на выбор тарифных планов с малым объемом ресурсов. OpenBot запускает Chromium с флагом --disable-dev-shm-usage, поэтому браузер записывает данные в /tmp вместо /dev/shm. Это позволяет избежать сбоев на хостах с малым /dev/shm и переносит нагрузку на корневую файловую систему, что является еще одной причиной, по которой рекомендуемый объем диска больше размера образа.

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

Вам потребуются Docker, Bun версии 1.3 или новее, проект CopilotKit Intelligence и API-ключ для модели. Документация для разработчиков также предполагает наличие на сервере lsof, python3 и curl. Клонируйте помеченный релиз, а не main, так как main в альфа-проектах меняется без предупреждения.

git clone --branch v0.0.1 https://github.com/CopilotKit/openbot.git
cd openbot
cp .env.example .env

Подготовьте проект Intelligence. Эти три команды записывают ключ среды выполнения и токен лицензии в ваш файл окружения.

npx --yes copilotkit@latest login
npx --yes copilotkit@latest project select
npx --yes copilotkit@latest license --write

Сгенерируйте ключ для шифрования сохраненных учетных данных и поместите результат в .env в качестве KEY_ENCRYPTION_KEY. Добавьте ваш OPENAI_API_KEY в тот же файл или установите BOT_PROVIDER в значение anthropic или google с соответствующим ключом.

openssl rand -base64 32

Затем выполните установку и запуск.

bun install
bash scripts/start.sh

scripts/start.sh запускает Docker-сервисы, выполняет миграции базы данных, запускает сервер и приложение, а также проверяет их работоспособность. По завершении приложение будет отвечать на порту 3010, а API — на порту 3001. Скрипт сообщает о конфликтах портов и не затрагивает уже запущенные сервисы, поэтому его можно безопасно запускать повторно.

Проверьте работу с самого сервера, прежде чем открывать доступ извне.

curl -sS -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3010
ss -ltnp | grep -E ':(3010|3001|4100|4500|5432)'

200 в выводе первой команды означает, что приложение работает. Вторая команда показывает, к каким адресам привязаны эти порты; это критически важная информация для VPS. Строка 127.0.0.1:3001 означает, что сервис доступен только локально. Строка 0.0.0.0:3001 означает, что сервис доступен любому, кто может направить трафик на ваш сервер.

Единый образ контейнера

В документации по развертыванию также поставляется единый образ, содержащий приложение, API и Chromium, который работает на порту 3001.

docker build -t openbot .
docker run -p 127.0.0.1:3001:3001 --env-file .env \
  -e EMBEDDED_POSTGRES=on -v openbot-data:/var/lib/postgresql/data openbot

EMBEDDED_POSTGRES=on запускает PostgreSQL внутри контейнера и применяет миграции при старте. Именованный том сохраняет историю аудита при переразвертывании; без него каждая пересборка приводит к потере этой истории. Если вы указываете DATABASE_URL на управляемую базу данных, на ней должно быть включено расширение vector. Управляемые сервисы, такие как RDS, Cloud SQL и Azure Database, поддерживают это расширение, но ни один из них не включает его автоматически. Поэтому миграция на чистой управляемой базе данных завершится ошибкой, так как тип столбца vector еще не существует.

Выполняйте миграции как этап релиза, если база данных является внешней.

docker run --rm --env-file .env openbot \
  sh -c "cd /app/server && bun x drizzle-kit migrate --config=drizzle.config.ts"

Этот образ намеренно оставляет порт браузера неопубликованным. В нем также отсутствует супервизор, так как супервизору требуется Docker socket, который не предоставляется serverless-платформами. Без супервизора каждый бот использует один браузер и, следовательно, один набор учетных данных, что исключает изоляцию, ради которой стоило запускать отдельные контейнеры для каждого бота. Если раздельные учетные данные для каждого бота — это причина, по которой вы здесь, запустите стек compose с установленными COMPUTER_SUPERVISOR_URL и SUPERVISOR_TOKEN на хосте, где вы принимаете соответствующие риски. Процесс, имеющий доступ к Docker socket, может запустить привилегированный контейнер, поэтому на практике он обладает правами root на хосте. Это веская причина держать OpenBot на отдельной машине, в том же духе, что и предоставление агентам для кодинга одноразовой виртуальной машины.

Почему OPENBOT_SINGLE_USER — это настройка для ноутбука

.env.example поставляется с OPENBOT_SINGLE_USER=true. Эта настройка принимает любой запрос как запрос от одного администратора и полностью пропускает вход в систему. На ноутбуке это удобно, так как единственный клиент, который может подключиться к порту, — это вы. На VPS это означает, что первый человек, который обратится к порту 3010, станет администратором системы, хранящей зашифрованные учетные данные и управляющей браузером, в котором вы уже авторизованы в своих аккаунтах.

Существует два корректных способа запуска. Оставьте OPENBOT_SINGLE_USER=true, привяжите все порты к 127.0.0.1 и обращайтесь к приложению только через SSH-туннель или частный сетевой интерфейс.

ssh -N -L 3010:127.0.0.1:3010 -L 3001:127.0.0.1:3001 you@your-vps

В этом случае приложение будет доступно по адресу http://localhost:3010 в вашем браузере, что считается безопасным контекстом. Поэтому файлы cookie для входа и функции браузера, необходимые для работы «живого» экрана, будут функционировать корректно. Другой способ — отключить однопользовательский режим и настроить полноценного провайдера идентификации. Поддерживаются Google, Microsoft Entra, Okta, SAML и OIDC. Для любого провайдера также требуется BETTER_AUTH_SECRET длиной 32 символа или более, BETTER_AUTH_URL, установленный в базовый URL публичного API для обратных вызовов OAuth, INITIAL_ADMIN_EMAILS и TRUSTED_ORIGINS. Учетные данные провайдера должны быть полными, так как неполная конфигурация провайдера останавливает запуск приложения, вместо того чтобы вернуться к открытому доступу.

Если приложение доступно по публичному имени, настройте перед ним TLS (transport layer security). Страница, передаваемая по обычному http:// на любом хосте, кроме localhost, не является безопасным контекстом. В результате файлы cookie с пометкой Secure не сохраняются, и вход в систему завершается ошибкой, которая выглядит как баг в OpenBot.

Ограничение доступа к низкоуровневым портам

В документации по безопасности OpenBot указано, что низкоуровневые конечные точки сервисов защищены токенами. Их следует держать в закрытом доступе и не использовать для обхода шлюза. Токены — это второй уровень защиты. Первый уровень заключается в том, что порт вообще не должен быть доступен извне.

Агент на компьютере ожидает соединений на порту 4100 и требует COMPUTER_TOKEN. Конечные точки бота работают на портах 4200 и 4201. Супервизор слушает порт 4500 на хосте и 4300 внутри своего контейнера. PostgreSQL использует порт 5432. Ни один из этих портов не должен быть доступен через публичный интерфейс; при развертывании для одного пользователя это также относится к приложению и API.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

Здесь существует ловушка для тех, кто считает, что одного файрвола достаточно. Публикация порта контейнера с помощью -p 3001:3001 заставляет Docker добавить правило DNAT. В результате трафик обрабатывается в цепочке FORWARD и никогда не проходит через цепочку INPUT, которой управляет политика запрета по умолчанию в ufw. Порт остается открытым, даже если ufw status по-прежнему выводит Status: active. Привязывайте опубликованный порт к интерфейсу loopback непосредственно в маппинге, как -p 127.0.0.1:3001:3001, или укажите адрес хоста в файле compose. Проверяйте результат с помощью ss -ltnp, а не ufw status.

OpenBot не является автономным стеком

Учитывайте это перед планированием развертывания. OpenBot зависит от проекта CopilotKit Intelligence, который хранит постоянные потоки и историю диалогов вне вашего сервера. При запуске сервер проверяет INTELLIGENCE_API_URL, INTELLIGENCE_GATEWAY_WS_URL, INTELLIGENCE_API_KEY и COPILOTKIT_LICENSE_TOKEN; все четыре параметра должны присутствовать одновременно, иначе запуск завершится ошибкой. По состоянию на август 2026 года доступен бесплатный тарифный план, а сам Intelligence можно разместить на собственном оборудовании, поэтому полностью локальное развертывание возможно, хотя оно требует больше усилий, чем описано в руководстве по быстрому старту.

Модель — это вторая внешняя зависимость. В комплекте поставки ничего нет. BOT_PROVIDER принимает openai, anthropic или google, а OPENAI_BASE_URL указывает путь OpenAI на любой совместимый endpoint. Здесь пригодится запуск Ollama на VPS для хостинга LLM своими силами, если вы хотите, чтобы токены оставались на вашем оборудовании. Управление браузером предъявляет высокие требования к модели, поэтому протестируйте локальную модель на реальной задаче, прежде чем переходить на неё окончательно.

Запуск в одном экземпляре на текущий момент

Шлюз кэширует снимки страниц в оперативной памяти серверного процесса. При наличии двух реплик снимок, сделанный одним процессом, будет недоступен другому, что приводит к периодическим сбоям с ошибками element-not-found, которые выглядят случайными. В документации по развертыванию указано прямо: запускайте только одну реплику и ограничьте максимальное количество экземпляров в вашей платформе значением 1. Это ограничение будет снято, когда кэширование снимков будет перенесено в базу данных. До тех пор масштабируйте OpenBot путем увеличения ресурсов сервера, а не добавления новых узлов. Изоляция между ботами по-прежнему обеспечивается контейнерами для каждого отдельного бота, точно так же, как песочницы для self-hosted агентов предотвращают влияние ошибок одного агента на работу остальных.

Режимы сбоев и их признаки

Процесс завершается сразу после заполнения .env. Сервер проверяет конфигурацию перед началом работы. Неполный блок Intelligence, отсутствие KEY_ENCRYPTION_KEY или провайдер OAuth, у которого указан client ID, но нет секрета, приводят к остановке запуска, а не к работе в ограниченном режиме. Прочитайте первое сообщение об ошибке, исправьте указанное поле и запустите процесс снова.

Миграции завершаются ошибкой на управляемой базе данных. Расширение vector не включено по умолчанию, поэтому миграция пытается использовать тип столбца, который PostgreSQL не распознает. Подключитесь как суперпользователь, выполните CREATE EXTENSION vector;, затем повторите шаг миграции.

Приложение загружается, но сессия входа не сохраняется. Вы используете обычный http:// на публичном адресе, что не является безопасным контекстом, поэтому cookie Secure отбрасывается. Настройте TLS перед приложением или используйте SSH-туннель, чтобы браузер видел localhost.

Боты используют общие учетные данные, хотя должны быть разделены. Супервизор не запущен, поэтому нет изоляции для каждого бота, и все они используют общий браузер. Убедитесь, что COMPUTER_SUPERVISOR_URL задан и супервизор имеет доступ к Docker socket.

Бот останавливается и запрашивает помощь. Это штатное поведение системы. В журнале аудита фиксируется computer.help_requested, вы берете управление на себя в режиме реального времени, и факт передачи управления записывается с обеих сторон.

FAQ

Безопасно ли оставлять OPENBOT_SINGLE_USER включенным при развертывании на VPS?

Только если шлюз недоступен из интернета. OPENBOT_SINGLE_USER=true принимает любой запрос как запрос администратора без авторизации, поэтому любой, кто может открыть порт, получает полный контроль над развертыванием, сохраненными учетными данными и сессией браузера. Это допустимо, если все порты привязаны к 127.0.0.1, а доступ к приложению осуществляется через SSH-туннель или частный сетевой интерфейс. При работе через публичный интерфейс отключите эту опцию и настройте Google, Microsoft Entra, Okta или OIDC вместе с BETTER_AUTH_SECRET, BETTER_AUTH_URL, INITIAL_ADMIN_EMAILS и TRUSTED_ORIGINS.

Сколько оперативной памяти нужно одному боту OpenBot?

Согласно опубликованным данным для одного бота на архитектуре arm64, пиковое потребление памяти составляет 0.55 ГБ, при этом 2 ГБ является задокументированным минимумом, а 4 ГБ — рекомендуемым значением. Официальных данных для нескольких ботов одновременно нет, так как каждый из них запускает собственный экземпляр Chromium. Запустите одного бота для реальной задачи, проверьте потребление памяти контейнером через docker stats, добавьте потребление шлюза и базы данных, а затем умножьте на количество ботов, которые должны работать одновременно.

Нужна ли учетная запись CopilotKit для самостоятельного хостинга OpenBot?

Да. OpenBot зависит от проекта CopilotKit Intelligence для обеспечения работы потоков и памяти, и сервер не запустится, если не заданы URL API Intelligence, URL WebSocket шлюза, API-ключ и токен лицензии. По состоянию на август 2026 года доступен бесплатный тарифный план, кроме того, Intelligence можно развернуть самостоятельно, поэтому зависимость от облачного сервиса можно устранить при дополнительных усилиях. Вам также потребуется предоставить собственный API-ключ для модели, так как OpenBot поставляется без встроенных моделей.

Почему каждый бот использует собственный браузер, а не общий?

Потому что профиль браузера — это идентификатор. Общий браузер означает общие файлы cookie и общие сессии, поэтому бот, вошедший в учетную запись, делает это для всех остальных ботов. Использование отдельных контейнеров для каждого бота дает каждому «сотруднику» свой профиль и свои учетные данные. Платой за это является расход памяти, так как экземпляр Chromium на каждого бота — это самый ресурсоемкий компонент при расчете нагрузки.

Какие порты OpenBot должны быть открыты в брандмауэре?

Никакие из низкоуровневых. Агент на порту 4100, конечные точки бота на 4200 и 4201, супервизор на 4500 и PostgreSQL на 5432 должны оставаться приватными. Проект защищает их токенами и требует, чтобы они оставались недоступными извне. Публикуйте только то, к чему пользователю нужен прямой доступ, и помните, что порт контейнера, опубликованный через -p 3001:3001, доступен независимо от правила ufw default-deny, так как правило DNAT в Docker направляет этот трафик по пути FORWARD, минуя INPUT.