Рано или поздно хочется отпустить Claude Code поработать без присмотра: пусть сам прогонит рутинную правку по проекту, пока ты занят другим. Флаг, который снимает все вопросы о разрешениях, существует. Но запускать его прямо на своём компьютере — всё равно что дать ключи от квартиры человеку, которого видишь впервые, и уйти гулять.
Правильное место для такого запуска — dev-контейнер. Разберём, как его собрать, почему после пересборки пропадает вход и где проходит граница, которую контейнер не охраняет.
Чем контейнер отличается от песочницы
У Claude Code есть встроенная песочница: она ограничивает, что могут делать команды оболочки. Dev-контейнер идёт дальше. Это Docker-контейнер, к которому подключается редактор, — на твоём компьютере или в облаке вроде GitHub Codespaces. Внутри живёт весь процесс Claude Code: инструменты правки файлов, MCP-серверы, хуки. Команды выполняются в контейнере, а правки попадают в твой репозиторий через монтирование.
Собирается такая среда в три слоя, и каждый опирается на предыдущий.
Слой 1: фича Claude Code
Самое простое — добавить готовую фичу в .devcontainer/devcontainer.json:
{
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node:1": { "version": "lts" },
"ghcr.io/anthropics/devcontainer-features/claude-code:1.0": {}
},
"postCreateCommand": "sudo apt-get update && sudo apt-get install -y bubblewrap socat"
}
Подвох в теге :1.0. Кажется, что он закрепляет версию Claude Code, но нет: он закрепляет скрипт установки фичи. Фича ставит последний релиз, и дальше тот обновляется сам. А postCreateCommand доставляет bubblewrap и socat — без них на Linux не работает песочница для Bash.
Слой 2: вход, который не пропадает
Типичная история: вошёл в Claude Code внутри контейнера, пересобрал его — и claude auth status возвращает код 1. Пересборка сохраняет папку с проектом, но выбрасывает домашнюю папку, а с ней и ~/.claude. В Codespaces то же самое: после Rebuild Container /workspaces на месте, а входа нет.
Решение — именованный том Docker в ~/.claude плюс переменная CLAUDE_CONFIG_DIR с тем же путём. Том живёт отдельно от контейнера, поэтому вход и настройки переживают пересборку:
"mounts": [
"source=claude-code-config-${devcontainerId},target=/home/node/.claude,type=volume"
],
"containerEnv": {
"CLAUDE_CONFIG_DIR": "/home/node/.claude"
}
Если вход всё равно пропадает, почти всегда причина одна: target тома и CLAUDE_CONFIG_DIR называют разные пути. Путь зависит от пользователя в образе — в базовом образе Ubuntu это vscode, а не node.
Слой 3: эталонный контейнер
В репозитории Claude Code лежит эталонный .devcontainer/ из трёх файлов: devcontainer.json, Dockerfile и init-firewall.sh. Он добавляет две вещи, ради которых всё и затевается:
- обычного пользователя
nodeвместо root; - файрвол: исходящий трафик идёт только на адреса из списка в
init-firewall.sh.
Именно такой контейнер документация поддерживает для прогонов с --dangerously-skip-permissions. От root CLI этот флаг вообще не примет.
Перед первой сборкой сделай три вещи:
- Прочитай все три файла.
init-firewall.shвыполняется от root при каждом старте контейнера. - Добавь домены входа. Рядом с
api.anthropic.comв списке должны бытьclaude.aiиplatform.claude.com, иначе вход упрётся в файрвол. Нужен PyPI или приватный реестр пакетов — тоже допиши. - Закрепи версию. В аргументе сборки
CLAUDE_CODE_VERSIONзамениlatestна конкретную версию, а вcontainerEnvдобавь"DISABLE_AUTOUPDATER": "1".
Проверить файрвол просто: изнутри контейнера запрос к example.com должен падать, а к api.github.com — проходить.
Запуск без вопросов — но с рамками
Контейнер не отменяет рамок, о которых мы говорили в уроке про автономный запуск. Он добавляет внешнюю стену, а лимиты по-прежнему нужны внутри:
claude -p "Добавь в начало README.md однострочное описание репозитория" \
--dangerously-skip-permissions --model sonnet --max-turns 10
Логика та же, что и без контейнера: --max-turns ограничивает число ходов, --max-budget-usd — примерную стоимость, а коммитишь результат ты сам, после того как прочитал дифф. Когда лимит срабатывает, в JSON-выводе subtype объясняет причину — error_max_turns или error_max_budget_usd. И помни, что total_cost_usd в этом выводе — оценка на стороне клиента, а не твой счёт.
Что контейнер НЕ защищает
Контейнер не мешает прогону унести всё, что доступно внутри: в том числе учётные данные Claude Code в ~/.claude и сам проект с его .git. Расширение Dev Containers в VS Code ещё и пробрасывает в контейнер твои Git-учётки и SSH-агент, а эталонный файрвол пропускает GitHub — так что прогон может запушить от твоего имени. Используй контейнер только с репозиториями, которым доверяешь, никогда не монтируй туда ~/.ssh или файлы с облачными ключами, а после прогона прочитай .git/config, список .git/hooks и дифф .devcontainer — до пересборки и до git commit.
Уборка после работы
Том переживает контейнер, а значит, и твой вход в нём. Закончил — выполни claude auth logout внутри контейнера, затем удали контейнер и тома, чьи имена начинаются с claude-code-config- и claude-code-bashhistory- (docker volume ls, потом docker volume rm). Codespace удаляй отдельно: даже остановленный, он занимает место.
Частые вопросы
Закрепляет ли тег :1.0 версию Claude Code в контейнере?
Нет. Тег закрепляет скрипт установки фичи, а она ставит последний релиз Claude Code, который потом обновляется сам. Чтобы версия не менялась, задай конкретную версию в CLAUDE_CODE_VERSION при сборке и добавь DISABLE_AUTOUPDATER=1.
Почему после пересборки контейнера Claude Code просит войти заново?
Пересборка выбрасывает домашнюю папку вместе с ~/.claude. Смонтируй именованный том в эту папку и задай CLAUDE_CONFIG_DIR с тем же путём — тогда вход переживёт пересборку.
Можно ли запускать --dangerously-skip-permissions от root?
Нет, от root CLI этот флаг не примет. Документация поддерживает такие прогоны в эталонном контейнере с обычным пользователем и файрволом.
Где разобраться глубже
Настройке контейнера посвящён урок «Claude Code в dev-контейнере», а рамкам для запуска без присмотра — урок «Автономный запуск с лимитами». Оба — в бесплатном курсе «Claude Code: уровень профи», с тренажёром в браузере. Флаги из этого поста собраны в шпаргалке по Claude Code.