OpenCode — open-source harness-система для ИИ-агентов без привязки к вендору. Агент читает файлы, запускает тесты, привлекает другие модели, передаёт задачи субагентам и подключает MCP, скиллы и плагины. В разборе запуска OpenCode на сервере хорошо видна разница между демонстрацией в терминале и рабочей автономной схемой.
По умолчанию сессия живёт, пока открыт терминал. Отошли от ноутбука, и работа повисла между «подумать» и «сделать». Закрыли крышку, и процесс умер. Для фоновых задач нужен headless-режим: opencode serve поднимает HTTP-сервер с API, потоком событий и эндпоинтом OpenAPI-спецификации. К серверу стучатся из CI, cron, другого скрипта или IDE. Держать его прогретым между запусками полезно, чтобы не платить за холодный старт MCP и LSP каждый раз.
Короткий ответ: серверный OpenCode нужен, когда агенту надо работать без человека в контуре или принимать запросы из внешних систем. Для разовой задачи в терминале хватит TUI: сервер добавит инфраструктуру, которую придётся защищать, обновлять и мониторить.
Claude Code и Codex — закрытые проприетарные инструменты, заточенные под модели своего автора. OpenCode не привязан к одному поставщику: можно подключать официальных провайдеров, сторонние шлюзы и разные модели. Эта независимость делает серверный режим практичным: один harness, несколько моделей, внешние клиенты через API.
Зачем выносить OpenCode на сервер
Чем TUI отличается от headless-режима
Под капотом OpenCode уже клиент-серверная схема. TUI общается с локальным HTTP-сервером, который публикует OpenAPI-спецификацию и отдаёт её любому клиенту. opencode serve выставляет этот же сервер в headless-режиме, без терминального интерфейса. API остаётся тем же, меняется способ управления.
Если TUI уже запущен, opencode serve поднимет второй сервер и не тронет первый. Один процесс остаётся интерактивным, второй принимает запросы от CI или скриптов. На практике удобно держать отдельный сервер для автоматизации, а TUI использовать для ручной работы.
Разница проявляется в состоянии. TUI привязан к терминалу и вашей сессии. Headless-сервер живёт как обычный процесс: его можно запустить через systemd, положить в контейнер, перезапустить, проверить healthcheck. Он не спасает от нестабильных моделей и ошибок агента, но убирает зависимость от открытого ноутбука.
Кому серверный режим реально нужен, а кому нет
Серверный режим полезен в четырёх сценариях: ревью пул-реквестов из GitHub Actions, ночные cron- и systemd-задачи, удалённое управление из IDE, веб-клиенты через API. В каждом случае агент работает без постоянного присутствия человека или принимает запросы от другой системы.
Для разовых задач в терминале сервер не нужен. Если вы просите агента поправить файл и сразу смотрите результат, TUI проще. Сервер добавляет порты, пароли, логи, обновления и риск оставить открытый API. Это лишняя инфраструктура, пока нет повторяемого фонового сценария.
Для многодневных прогонов и автономных задач важнее не сам сервер, а ограничение контекста, память в файлах и проверка результатов. Эти вопросы разобраны в материале о harness для автономных задач.
Как устроен opencode serve: API, порт и сеть
Сервер по умолчанию слушает порт 4096 (либо выбирает случайный порт), а адрес и порт меняются флагами --hostname и --port. Те же параметры можно задать в конфигурационном файле: port, hostname, mdns. Для браузерных клиентов есть --cors (дополнительные разрешённые origin, флаг можно передавать несколько раз), а --mdns включает обнаружение сервиса в локальной сети и автоматически выставляет hostname в 0.0.0.0. Описание флагов и режимов работы сервера приведено в документации по HTTP-серверу OpenCode.
Флаги --hostname, --port, --cors и --mdns
| Флаг | Что делает | Когда трогать |
|---|---|---|
--hostname | Задаёт адрес, на котором слушает сервер | Когда нужен доступ с другой машины, и только с паролем, firewall или VPN |
--port | Меняет порт; по умолчанию 4096 или случайный | Когда порт занят или нужна отдельная схема проброса |
--cors | Добавляет разрешённые браузерные origin; можно указать несколько раз | Когда веб-интерфейс открыт с другого origin; не открывайте всем подряд |
--mdns | Включает mDNS-обнаружение и автоматически ставит hostname в 0.0.0.0 | Когда машин несколько и прописывать адреса вручную неудобно |
Пример запуска: opencode serve --port 4096 --hostname 0.0.0.0. Смена --hostname на 0.0.0.0 без пароля и firewall — плохая идея. Сервер получит доступ к файлам и инструментам, а вы получите открытый API в сети. Для внешнего доступа ставьте reverse proxy с TLS и ограничением по IP.
При запуске TUI OpenCode случайным образом назначает порт и hostname; вместо этого можно передать свои значения и подключиться к серверу по ним.
OpenAPI-спецификация и генерация SDK
Сервер публикует OpenAPI 3.1 spec endpoint. По спецификации генерируют клиентов и инспектируют типы запросов и ответов. Сценарий простой: скрипт в пайплайне создаёт сессию, отправляет промпт с ссылкой на дифф, забирает события и комментарии. SDK убирает ручную сборку HTTP-запросов.
Спецификацию надо сверять с версией сервера. После обновления OpenAPI может измениться, и старый SDK начнёт ломаться. Pinned-версия и контрактный тест на пару ключевых вызовов экономят время при обновлениях.
Провайдер моделей и авторизация сервера
Провайдер подключается через OpenAI-совместимый эндпоинт. Подойдут официальные API, сторонние шлюзы и локальные серверы с совместимым интерфейсом. Тот же материал приводит BotHub как пример шлюза с оплатой в рублях без VPN. Это один из вариантов, не единственный.
Список моделей зависит от провайдера. В исходном описании упомянуты GLM 5.3 и Claude Opus 5.5. На сервере важна модель, а ещё лимиты, задержки и стабильность эндпоинта. Для ночных задач берите модель с предсказуемой стоимостью и таймаутом, иначе счёт вырастет быстрее, чем польза.
OPENCODE_SERVER_PASSWORD: что он закрывает и чего не делает
Базовая авторизация включается переменной OPENCODE_SERVER_PASSWORD: она защищает сервер через HTTP basic auth. Если переменная не задана, сервер остаётся незащищённым — это допустимо для локального использования, но для сетевого доступа пароль нужно задавать. Имя пользователя по умолчанию в доступных выдержках документации обрывочно, поэтому сверьте его с документацией вашей версии.
Пароля мало для публичного интернета: он не разграничивает права между клиентами, не шифрует трафик и не заменяет firewall или VPN. Если сервер смотрит в интернет, нужен reverse proxy с TLS и ограничением по IP. Пароль — минимум, а не полноценная система аутентификации. Для CI выдавайте отдельный пароль и меняйте его при утечке.
Ограничение исходного материала: статья на Habr обрывается на флаге --, поэтому детали systemd-юнитов, Docker-образов и плагинов сверяйте с документацией вашей версии. Ниже даны схематические примеры и места, где обычно ломается.
Разрешения allow/ask/deny и авто-режим
Система разрешений сводит каждое правило к одному из трёх исходов. allow выполняется без подтверждения, ask требует подтверждения, deny блокирует действие. Для сервера это ключевая настройка: в CI и cron человека нет, ответить на ask некому. Правила и их приоритеты описаны в документации по разрешениям OpenCode.
Правила применяются по шаблонам, и при совпадении нескольких правил побеждает последнее совпавшее. Разрешения задаются глобально и переопределяются для конкретных инструментов или агентов; правила агента имеют приоритет над глобальными.
В OpenCode есть auto mode: он автоматически одобряет запросы на разрешения, которые не запрещены явно, при этом deny-правила продолжают действовать. Auto mode меняет только те запросы, которые иначе требовали бы подтверждения. Отдельный CLI-флаг --auto в доступных материалах не подтверждён — сверьтесь с документацией версии, прежде чем прописывать его в юните или workflow.
allow: чтение файлов, запуск тестов и линтеров в рабочей копии.ask: установка зависимостей, сетевые вызовы, изменение конфигов.deny: push в main, доступ к секретам, удаление данных, произвольные команды за пределами workspace.
Правила стоит писать от запрета, а не от разрешения. Сначала deny на всё опасное, потом точечный allow на нужные инструменты. Широкий allow в сочетании с auto mode означает, что агент действует без человека в контуре. Это нормально для песочницы, но плохо для VPS с доступом к продакшену.
Деплой: systemd на VPS или Docker-контейнер
Два рабочих способа: systemd-сервис на VPS и Docker-контейнер. Первый даёт прямой доступ к файлам и окружению, второй — воспроизводимость и изоляцию. Выбор зависит от того, что важнее: минимум слоёв или предсказуемая среда.
Systemd-сервис: PATH, HOME и другие грабли
Главная ловушка systemd — минимальное окружение. Сервис запускается не из вашей shell-сессии, поэтому PATH не содержит путей из .bashrc или .zshrc, а HOME может отличаться от ожидаемого. Агент не находит бинарник, пишет конфиг не туда или видит пустой кэш.
Лечится явным указанием Environment, EnvironmentFile, WorkingDirectory и абсолютных путей в ExecStart. Пример скелета юнита:
[Service]
WorkingDirectory=/srv/projects/my-repo
Environment=HOME=/srv/opencode
Environment=PATH=/usr/local/bin:/usr/bin:/bin
ExecStart=/usr/local/bin/opencode serve --hostname 127.0.0.1 --port 4096
Restart=on-failure
Это скелет, а не готовый юнит. Подставьте свои пути и проверьте, под каким пользователем работает сервис. Логи systemd пишет в journald, отдельный файл не нужен. Если агент запускает тесты, убедитесь, что в окружении есть нужные переменные и доступ к workspace.
Docker: pinned-версия, изоляция и volume
Docker даёт pinned-версию образа: тег фиксируется, обновление становится осознанным действием. Workspace и сессии монтируются отдельными volume, чтобы состояние переживало пересоздание контейнера. Файловая система контейнера изолирована, но это не песочница безопасности: доступ к смонтированному workspace и сети остаётся.
docker run -d --name opencode -p 127.0.0.1:4096:4096 -v opencode-workspace:/workspace -v opencode-sessions:/path/to/sessions -e OPENCODE_SERVER_PASSWORD=... <image>:<pinned-tag>
Минусы Docker: сложнее с доступом к хостовым инструментам и прокси, нужно пробрасывать переменные и проверять сетевой доступ. Если агенту нужен Docker внутри, SSH-ключи хоста или GPU, контейнерная схема усложняется. Состояние проекта между сессиями можно хранить отдельно, например через Later Bender.
| Критерий | systemd | Docker |
|---|---|---|
| Воспроизводимость | Зависит от VPS и ручных настроек | Выше с pinned-тегом |
| Доступ к хосту | Прямой | Через volume и проброс |
| Изоляция | На уровне пользователя и прав ОС | Файловая система контейнера |
| Отладка | journald | docker logs |
Критерий выбора простой. Если нужен минимум слоёв и прямой доступ к файлам, берите systemd. Если важнее повторяемый образ и чистая файловая система, берите Docker. В обоих случаях сервер не должен работать от root.
Практические сценарии: CI, cron, IDE и веб-клиенты
Серверный режим раскрывается в четырёх сценариях. В каждом есть внешний клиент, который не хочет держать терминал.
Ревью пул-реквестов через GitHub Actions
Workflow поднимает сервер или переиспользует уже запущенный, отправляет через API дифф и инструкцию, агент читает файлы, запускает тесты и оставляет комментарий. Нужны auto mode, узкие allow и deny, токен только на комментарии. Push в основную ветку лучше запретить на уровне прав, а не на уровне промпта.
Секреты не должны попадать в контекст агента. Передавайте минимальные переменные, не монтируйте весь .ssh и не давайте токен с правом записи в репозиторий, если агент только комментирует.
Ночные задачи с opencode-scheduler
Плагин opencode-scheduler от different-ai планирует повторяющиеся задачи через нативные планировщики ОС: launchd на macOS, systemd на Linux, Task Scheduler на Windows, с fallback на cron там, где нативные бэкенды недоступны. Плагин записывает файл задачи и ставит таймер в планировщике ОС; в назначенное время планировщик вызывает supervisor-скрипт, который запускает задачу, дописывает логи и обновляет метаданные задачи. Проект упоминается в официальном списке экосистемы OpenCode, а его репозиторий и описание работы доступны на GitHub.
Ночью никто не ответит на ask, поэтому правила должны быть в allow и deny, а результат — в логах и артефактах. Ночной прогон стоит ограничивать по времени и бюджету токенов. Если задача может идти часами, ставьте таймаут и внешний kill-switch. Пример дисциплины для локального марафона описан в разборе Qwen 27B на двух GPU: мелкие фазы, машинная проверка и человек на приёмке.
IDE и веб-клиенты работают через тот же HTTP API. Для браузерного клиента с другого origin нужен --cors, но не открывайте CORS всем подряд. IDE подключается к серверу по адресу и порту, а не запускает второй экземпляр агента.
Ограничения безопасности: OpenCode — не песочница
OpenCode запускает инструменты и читает файлы с правами того пользователя, под которым работает. Запустили сервис как root, агент получил root. Смонтировали docker.sock, агент получил контроль над хостом. Это обычные последствия широких прав, а не экзотическая атака.
Что сделать дополнительно: отдельный пользователь без sudo, контейнер с минимальным набором смонтированных путей, исходящие соединения по allowlist, аудит MCP-серверов и плагинов, read-only токены для CI.
MCP-серверы вне модели угроз
MCP-сервер — отдельный процесс со своими правами. Harness вызывает его инструменты, но не контролирует, что внутри. MCP-сервер может читать файлы, ходить в сеть или выполнять команды, которые вы ему разрешили. Подключайте проверенные серверы и ограничивайте их права на уровне ОС.
Если агенту нужен доступ к состоянию Linux-сервера, посмотрите разбор MCP daemon. Там показано, как выдать точечные права вместо SSH с sudo и где конфигурация превращает агента в полный root.
Bun и прокси: что учесть
OpenCode работает на Bun. У Bun есть особенности работы с прокси, которые влияют на сетевые запросы агента. Проверяйте переменные HTTP_PROXY, HTTPS_PROXY и NO_PROXY, тестируйте доступ к провайдеру и MCP-серверам до запуска в прод.
Прокси может ломать поток событий, если соединение долго живёт. Проверьте таймауты, keep-alive и логи reverse proxy. Ошибка в прокси выглядит как зависший агент, хотя модель и сервер живы.
Мониторинг: health-эндпоинт, journald и Docker logs
Сервер OpenCode предоставляет API для проверки здоровья и версии, возвращающий { healthy: true, version: string }. Исторический маршрут /global/health относился к v1 HTTP API; в v2-серверах этого маршрута нет, и запросы к неизвестным не-/api путям возвращают HTML веб-интерфейса вместо JSON. Поэтому перед настройкой healthcheck уточните версию сервера и точный путь из его OpenAPI-спецификации.
Для systemd логи смотрите в journalctl -u opencode, для Docker — в docker logs. Плагин opencode-otel для телеметрии в OpenTelemetry в доступных материалах не подтверждён: если он нужен, проверьте его существование и настройку по актуальной документации, прежде чем закладывать в схему.
healthcheck:
test: ['CMD', 'curl', '-f', 'http://127.0.0.1:4096/<health-path>']
interval: 30s
timeout: 5s
retries: 3
Это пример для Docker Compose, curl должен быть в образе, а путь подставьте из спецификации вашей версии. Алерт ставьте на недоступность healthcheck и на рост ошибок 5xx. Отдельно полезен алерт на завершение процесса и на исчерпание диска: агент активно пишет логи и артефакты.
Чек-лист перед запуском в прод
- Пароль
OPENCODE_SERVER_PASSWORDзадан, сервер не слушает0.0.0.0без необходимости. - Firewall и reverse proxy с TLS, доступ по IP или VPN.
- Правила
allow,askиdenyпродуманы, auto mode только с внешними ограничениями. - MCP-серверы проверены, их права урезаны.
- Версия OpenCode и образ pinned.
- Workspace и сессии лежат на отдельных volume или в отдельных каталогах.
- healthcheck на health-эндпоинт из спецификации вашей версии, логи в journald или Docker logs.
- CI-токены только на чтение и комментарии, без push в main.
- Прокси-переменные проверены, доступ к провайдеру и MCP протестирован.
Серверный OpenCode — инфраструктурный компонент. Его обновляют, мониторят и ограничивают так же, как любой другой сервис с доступом к коду и сети.