OpenClaw в Docker: песочница и права доступа для агента с доступом к shell
Коротко. Песочница в OpenClaw выключена по умолчанию: пока вы её не включили, агент выполняет команды прямо на хосте от имени того пользователя, под которым запущен. Включается она одним ключом agents.defaults.sandbox.mode в файле ~/.openclaw/openclaw.json и по умолчанию использует Docker. Важно понимать три вещи. Первая: в контейнер уезжает только выполнение инструментов — сам процесс Gateway всегда остаётся на хосте. Вторая: настройками песочницы, списком разрешённых инструментов и режимом прав сессии управляют три независимых механизма, и «агент всё равно что-то может» почти всегда означает, что вы закрутили не тот. Третья, и самая обидная: изменение конфига не влияет на уже запущенные контейнеры — без openclaw sandbox recreate вы будете смотреть в правильный конфиг и получать старое поведение. Ниже — рабочая минимальная конфигурация, команда проверки того, что реально применилось, и разбор мест, где изоляция протекает по вашему же согласию.
На чём это проверено
Все ключи конфигурации, команды, значения по умолчанию и списки заблокированных путей сверены с официальной документацией и релизными данными проекта 8 сентября 2026 года. Актуальный релиз на эту дату — OpenClaw 2026.9.2 (опубликован 5 сентября 2026 года; в реестре npm канал latest — 2026.9.2, канал extended-stable — 2026.6.34). Проект выпускает релизы часто, поэтому перед копированием в боевой конфиг сверьтесь с docs.openclaw.ai.
Статья предполагает, что OpenClaw уже установлен и отвечает: провайдер подключён, модель выбрана. Если нет — начните с материалов как установить OpenClaw и первичная настройка OpenClaw, а сюда возвращайтесь, когда дойдёт до вопроса «а что этот агент вообще может сделать с моим сервером».
Что изолируется, а что нет
Формулировка из документации прямая, и её стоит принять до того, как вы начнёте что-то настраивать: песочница — не идеальная граница безопасности, она существенно ограничивает доступ к файлам и процессам, когда модель делает глупость. Это разумная цель. Это не защита от целенаправленной атаки на ваш сервер.
В песочницу уезжает:
- выполнение инструментов —
exec,read,write,edit,apply_patch,processи подобные; - опциональный браузер в песочнице (
agents.defaults.sandbox.browser).
В песочницу не уезжает:
- сам процесс Gateway — он всегда на хосте;
- нативные плагины: они работают внутри процесса Gateway и разделяют его границу доверия;
- всё, что явно выпущено наружу через
tools.elevated(об этом ниже).
Три независимых рычага — и почему их путают
Это главная развилка всей темы. В OpenClaw три разных механизма, и они отвечают на три разных вопроса:
- Песочница (
agents.defaults.sandbox.*) — где выполняются инструменты: в контейнере или на хосте. - Политика инструментов (
tools.*,tools.sandbox.tools.*) — какие инструменты вообще доступны агенту. - Elevated (
tools.elevated.*) — аварийный выход только дляexec: разрешить конкретное выполнение на хосте в обход обычной песочницы.
Практический вывод: если агент делает то, чего вы не хотите, сначала определите, какой из трёх рычагов за это отвечает. Запрет инструмента не переносит его выполнение в контейнер, а включение песочницы не отбирает у агента инструмент. Половина вопросов вида «я же настроил, почему не работает» — это попытка закрутить не тот механизм.
Шаг 1. Собрать образ песочницы
Образ по умолчанию — openclaw-sandbox:bookworm-slim. Его нужно собрать заранее: OpenClaw не подставляет молча обычный debian:bookworm-slim, если нужного образа нет. Запуск упадёт сразу с инструкцией по сборке — потому что штатный образ несёт python3, на котором работают помощники записи и правки файлов внутри песочницы.
Если вы ставили OpenClaw глобально через npm (исходников на диске нет), соберите образ так:
docker build -t openclaw-sandbox:bookworm-slim - <<'DOCKERFILE'
FROM debian:bookworm-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
bash ca-certificates curl git jq python3 ripgrep \
&& rm -rf /var/lib/apt/lists/*
RUN useradd --create-home --shell /bin/bash sandbox
USER sandbox
WORKDIR /home/sandbox
CMD ["sleep", "infinity"]
DOCKERFILE
Если вы работаете из клона репозитория, есть готовый скрипт scripts/sandbox-setup.sh — в npm-пакет он не входит.
Обратите внимание на две строки. USER sandbox — контейнер работает не от root. И в образе нет Node: если вашему навыку нужен Node или другой рантайм, либо соберите свой образ, либо ставьте через sandbox.docker.setupCommand — но последнее требует сетевого доступа, записываемого корня и пользователя root, то есть ровно тех трёх послаблений, ради отмены которых вы всё это и затеяли. Лучше собрать образ. Для более функционального варианта в проекте есть Dockerfile.common с curl, jq, Node 24, pnpm, python3 и git — собирается в образ openclaw-sandbox-common:bookworm-slim.
Шаг 2. Включить песочницу
Настройки живут в ~/.openclaw/openclaw.json под ключом agents.defaults.sandbox (переопределения для отдельного агента — в agents.entries.*.sandbox). Поведением управляют три независимые настройки:
| Настройка | Ключ | Значения | По умолчанию |
|---|---|---|---|
| Режим | sandbox.mode | off, non-main, all | off |
| Область | sandbox.scope | agent, session, shared | agent |
| Бэкенд | sandbox.backend | docker, podman, ssh, openshell | docker |
Про mode есть неочевидный момент, который в документации помечен как «типичный сюрприз». Режим non-main изолирует все сессии, кроме основной сессии агента (её ключ всегда agent:<agentId>:main и не настраивается). Групповые и канальные сессии используют собственные ключи — то есть всегда считаются не-основными и всегда попадают в песочницу. Если агент отвечает в общем чате, non-main уже даёт вам основную защиту, а вы продолжаете работать с ним напрямую без контейнера.
Такие края — где настройка называется одним, а применяется к другому — и составляют основную часть работы. Разбираться в них на сервере, где агент уже что-то делает с вашими данными, дорого: цена ошибки здесь не «сломалось», а «не защищено, и мы об этом не знаем». Если периметр нужно закрыть не в тестовом контуре, а в бою, мы проверим доступы вашего агента и попробуем выйти из его песочницы — проверка на проникновение даёт ответ быстрее, чем выяснение границ механизмов методом проб.
Минимальная строгая конфигурация, которая сохраняет ограничительные настройки по умолчанию и делает рабочую папку агента доступной только на чтение:
{
"agents": {
"defaults": {
"sandbox": {
"mode": "all",
"backend": "docker",
"scope": "session",
"workspaceAccess": "ro",
"docker": {
"image": "openclaw-sandbox:bookworm-slim",
"readOnlyRoot": true,
"tmpfs": ["/tmp", "/var/tmp", "/run"],
"network": "none",
"capDrop": ["ALL"]
}
}
}
}
}
Значения network: "none", readOnlyRoot: true и capDrop: ["ALL"] — это и есть настройки Docker-бэкенда по умолчанию; в конфиге выше они выписаны явно, чтобы их было видно при code review, а не чтобы что-то изменить. Дополнительно OpenClaw создаёт контейнеры песочницы с init-процессом и флагом no-new-privileges. При workspaceAccess: "ro" рабочая папка агента монтируется только на чтение в /agent, попытки записи в неё отклоняются, а перечисленные пути tmpfs остаются записываемыми.
Отдельно проговорим сеть. По умолчанию у локальных контейнеров песочницы сети нет вообще. Это сильное ограничение и его стоит подержать как можно дольше: агент без egress не выгрузит наружу то, что прочитал.
Шаг 3. Пересоздать контейнеры — та самая ошибка
Если вы запомните из статьи одну команду, пусть это будет она. Правка конфига не влияет на уже запущенные контейнеры. Существующие рантаймы продолжают работать со старыми настройками. Простаивающие удаляются только по таймауту prune.idleHours (по умолчанию 24 часа) и prune.maxAgeDays (по умолчанию 7 дней), а у регулярно используемого агента контейнер может не простаивать никогда — и жить со старым конфигом сколько угодно долго.
openclaw sandbox recreate --all
Команда удаляет старые рантаймы, и при следующем обращении к агенту они пересобираются по текущему конфигу. Точечные варианты:
openclaw sandbox recreate --agent mybot
openclaw sandbox recreate --session "agent:main:main"
openclaw sandbox recreate --all --force
Ровно один из флагов --all, --session или --agent; --force пропускает подтверждение. Пересоздавать нужно после смены образа, любых ключей agents.defaults.sandbox.* и после правки setupCommand.
Шаг 4. Проверить, что применилось на самом деле
Не верьте конфигу — спросите систему. Отдельная команда показывает эффективный режим, область, доступ к рабочей папке, действующую политику инструментов в песочнице и открытые elevated-шлюзы, причём с указанием ключей конфига, которые надо править:
openclaw sandbox explain
openclaw sandbox explain --session agent:main:main
openclaw sandbox explain --agent work
openclaw sandbox explain --json
Посмотреть, что вообще запущено, — openclaw sandbox list (со статусом, бэкендом, совпадением с конфигом, возрастом и временем простоя). Общая диагностика — openclaw doctor, а openclaw doctor --fix дополнительно чинит часть находок, включая перенос устаревших файлов реестра песочниц в базу состояния.
Доступ к рабочей папке: три значения, которые решают многое
| Значение | Что происходит |
|---|---|
none (по умолчанию) | Инструменты читают и пишут в изолированную папку песочницы под ~/.openclaw/sandboxes. Рабочая папка агента не видна вообще. |
ro | Рабочая папка агента монтируется только на чтение в /agent; write, edit и apply_patch отключаются. |
rw | Рабочая папка агента монтируется на чтение и запись в /workspace. |
Значение по умолчанию здесь — самое строгое, и это правильная отправная точка. Повышайте до ro, когда агенту действительно нужно видеть ваши файлы, и до rw — только когда он должен их менять.
Проброс папок: где изоляция протекает с вашего согласия
Когда одному агенту нужна не только его рабочая папка, используются bind-монтирования в формате хост:контейнер:режим:
{
"agents": {
"entries": {
"research": {
"workspace": "/srv/openclaw/research-workspace",
"sandbox": {
"workspaceAccess": "rw",
"docker": {
"binds": [
"/srv/shared/reference:/reference:ro",
"/srv/shared/drafts:/drafts:rw"
],
"dangerouslyAllowExternalBindSources": true
}
}
}
}
}
}
Здесь важны четыре факта, каждый из которых кого-нибудь уже подводил:
- Bind пробивает песочницу. Смонтированное видно внутри контейнера ровно с тем режимом, который вы указали.
- Если режим не указан, по умолчанию будет запись. Для исходников и секретов всегда пишите
:roявно. - Режим bind и
workspaceAccessнезависимы. СменаworkspaceAccessне превращаетro-проброс вrwи наоборот. scope: "shared"игнорирует пер-агентные пробросы — применяются только глобальные. Для пер-агентных binds держитеscopeв значенииagentилиsession.
По умолчанию OpenClaw блокирует опасные источники: системные пути (/etc, /proc, /sys, /dev, /root, /boot), каталоги сокета Docker (/run, /var/run и варианты с docker.sock) и типовые каталоги учётных данных в домашней директории (~/.aws, ~/.docker, ~/.gnupg, ~/.netrc, ~/.npm, ~/.ssh, ~/.config, ~/.cargo). Заблокированы и цели, перекрывающие зарезервированные точки монтирования /workspace и /agent. Источники вне разрешённых корней требуют явного dangerouslyAllowExternalBindSources: true — флаг назван так не для красоты.
Проверка источника выполняется дважды: сначала по нормализованному пути, затем повторно после разрешения через ближайшего существующего родителя — так что подмена через симлинк на родительском каталоге не проходит, даже если конечного файла ещё нет.
И отдельной строкой: проброс /var/run/docker.sock фактически отдаёт песочнице управление хостом. Это не «ещё один том» — это конец изоляции. Делайте это только осознанно и никогда «чтобы заработало».
Режимы прав сессии
Параллельно с песочницей у каждой сессии есть режим прав: он задаёт границу по файловой системе и то, кто согласует повышение при выполнении команд.
| Режим | Файловая система | Кто согласует повышение exec |
|---|---|---|
read-only | Чтение в пределах корня сессии; изменяющие инструменты скрыты | Никто; exec запрещён |
guarded | Чтение и запись в пределах корня сессии | Человек, после быстрого прохода по белому списку |
workspace | Чтение и запись в пределах корня сессии | Проверка моделью, с откатом на человека |
full | Неограниченный доступ к файловой системе | Никто |
Режим full требует прав operator.admin, остальные — operator.write. Менять режим можно прямо во время задачи через меню Permissions в поле ввода. При смене режима ожидающие согласования из старого режима отменяются, а не выдаются; уже сделанные записи и запущенные процессы не откатываются.
Практический режим для повседневной работы — guarded: агент читает и пишет в своей папке, а всё, что выходит за рамки белого списка команд, приходит к вам на подтверждение.
Политика инструментов и ловушка «exec разрешён, write запрещён»
Политика инструментов отвечает на вопрос «какие инструменты вообще существуют для этого агента». Правила короткие:
denyвсегда побеждает;- если
allowнепустой, всё остальное считается заблокированным; - политика инструментов — жёсткий стоп: команда
/execне может переопределить запрещённый инструментexec.
А теперь ловушка, которая стоит отдельного абзаца. Политика фильтрует инструменты по имени и не смотрит на побочные эффекты внутри exec. Если exec разрешён, то запрет write, edit и apply_patch не делает shell-команды доступными только на чтение — агент просто напишет файл через оболочку. Конфигурация «разрешаем exec, запрещаем запись» выглядит безопасной в конфиге и не является таковой в реальности. Настоящий read-only-агент требует запрета группы group:runtime (это exec, process, code_execution) вместе с изменяющими файловыми инструментами — либо отдельной границы на уровне файловой системы песочницы.
Группы задаются сокращениями group:*: group:fs — это read, write, edit, apply_patch; group:web — web_search, x_search, web_fetch; и так далее. Когда сессия изолирована, добавляется вторая решётка — tools.sandbox.tools.allow и tools.sandbox.tools.deny. Про неё стоит помнить, если у вас подключены MCP-серверы: в изолированных сессиях их инструменты нужно разрешить отдельно, иначе агент увидит только встроенные.
Проверить постфактум, что именно отрезалось, можно по журналу: Gateway пишет записи аудита agents/tool-policy, когда политика убирает инструменты или блокирует вызов. Смотреть — командой openclaw logs; там же видно метку правила, ключ конфига и имена затронутых инструментов.
Elevated: осознанная дыра
Elevated не выдаёт дополнительных инструментов — он влияет только на exec. Если сессия обычно изолирована, /elevated on выполняет команду вне песочницы (согласования при этом могут по-прежнему применяться), а /elevated full отключает согласования exec для сессии. Шлюзы: tools.elevated.enabled и белые списки отправителей tools.elevated.allowFrom.<provider>.
Два ограничения, которые полезно знать: elevated не переопределяет разрешения и запреты инструментов, и он не может обойти песочницу, обязательную по роли создателя сессии. Если вы задали именованной операторской роли политику sandbox: "required", её сессии изолируются независимо от режима агента, требование неизменяемо для сессии, а при недоступном бэкенде система отказывает, а не откатывается на выполнение на хосте. Это самая жёсткая из доступных настроек, и для агента, которым пользуется кто-то кроме вас, она обычно и нужна.
Если сам Gateway живёт в контейнере
Отдельный случай, дающий неочевидные ошибки. Если вы разворачиваете Gateway как Docker-контейнер, он управляет соседними контейнерами песочницы через сокет Docker на хосте. Отсюда требование к путям: в openclaw.json ключ workspace должен содержать абсолютный путь хоста, а не внутренний путь контейнера Gateway, — демон Docker разбирает пути в пространстве имён хоста. Кроме того, контейнеру Gateway нужно дать идентичный маппинг тома, чтобы тот же путь резолвился и изнутри. Несовпадение проявляется как EACCES при записи файлов рабочей области. И там же — правило, которое не стоит нарушать: не монтируйте сокет Docker хоста в контейнеры агентской песочницы.
Чек-лист перед тем, как дать агенту доступ к shell
- Образ
openclaw-sandbox:bookworm-slimсобран. sandbox.mode—allили как минимумnon-main, если агент отвечает в групповых чатах.workspaceAccess— минимально необходимый:none, иначеro, и только при реальной нуждеrw.networkоставлен вnone, пока не доказано обратное.- Список
docker.bindsпросмотрен построчно; у всех чувствительных пробросов явный:ro; сокета Docker в списке нет. - Выполнен
openclaw sandbox recreate --allпосле последней правки конфига. openclaw sandbox explainпоказывает то, что вы ожидали, а не то, что вы написали.- Режим прав сессии осознанно выбран;
fullне является режимом по умолчанию. - Если нужен read-only-агент — запрещён
group:runtime, а не только файловые инструменты. tools.elevated.allowFromперечисляет конкретных отправителей, а не открыт всем.
Когда не стоит делать это самому
Всё описанное выше делается руками за вечер — если у вас уже есть Docker, вы читаете JSON без раздражения и готовы потом раз в несколько недель пересобирать образ под новые релизы. Это честная оценка: тут нет скрытого шага, который мы намеренно не назвали.
Сложность не в первичной настройке, а в эксплуатации. Образ песочницы устаревает вместе с базовым Debian. Контейнеры молча живут со старым конфигом, пока кто-нибудь не вспомнит про recreate. Каждый новый навык агента приносит соблазн добавить ещё один bind «на время», и через полгода в списке пробросов оказывается половина файловой системы. А ошибка в конфигурации песочницы не проявляется как поломка — она проявляется как отсутствие защиты, о котором вы узнаёте по факту.
Если держать этот слой в порядке некому, мы возьмём на себя серверы, образы и обновления под агентом — контейнеры пересобираются по расписанию, конфиг под контролем версий, доступы ревизуются, а не накапливаются. Что входит в сопровождение и во что оно обходится — на странице тарифов. Если же вопрос стоит уже, а агент работает в бою, начните с проверки текущего периметра: она обычно окупается тем, что находит один лишний rw-проброс, о котором все забыли.
Дальше по теме — тюнинг OpenClaw: маршрутизация моделей, память и контроль расходов.