SSD Nodes Learn
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-07-24

Как запустить Claude Code на VPS через tmux

Инструкция по запуску Claude Code на Linux VPS в сессии tmux. Решение проблемы обрыва работы агента при потере SSH-соединения или закрытии ноутбука.

Проблема в крышке ноутбука, а не в CLI

Claude Code работает исправно, пока вы не закроете крышку ноутбука: SSH-сессия обрывается, оболочка получает сигнал SIGHUP, и агент завершает работу через три минуты после начала выполнения теста. Запускайте CLI на устройстве, которое не переходит в спящий режим, внутри терминального мультиплексора, процессы которого не являются дочерними по отношению к вашей SSH-сессии. В этом заключается основной принцип — ключевым элементом является tmux, а не процесс установки.

Эта страница посвящена эксплуатации сервера, на котором запущены агенты. Если у вас нет Linux-сервера, который может работать постоянно, данные инструкции не применимы. Это единственное обязательное условие.

Что на самом деле делает tmux

При подключении по SSH sshd создает процесс shell и передает ему псевдотерминал; все процессы, запущенные из этого shell, являются его дочерними процессами. При разрыве соединения ядро закрывает pty, shell получает сигнал SIGHUP и, в свою очередь, завершает работу своих дочерних процессов. Долго выполняющиеся процессы в активном режиме (foreground) завершаются.

tmux меняет принцип владения процессами. Команда tmux, которую вы вводите, является тонким клиентом, который через unix socket взаимодействует с tmux server, работающим независимо от вашего терминала. Shell внутри сессии являются дочерними процессами этого сервера, а не sshd. Если разорвать SSH-соединение, клиент завершится, но сервер, сессия и агент продолжат выполнение задачи. При повторном подключении через tmux attach вы вернетесь в тот же shell с тем же буфером прокрутки. nohup также сохраняется после разрыва соединения, но не предоставляет возможности вернуться — вы не сможете повторно подключиться к фоновому TUI. Claude Code является интерактивным инструментом; tmux (или screen) — подходящий инструмент для этих целей.

Выбор ресурсов системы

CLI — это процесс Node; он не является основным потребителем ресурсов. Основную нагрузку создают процессы, которые агент запускает от вашего имени: сборка, полный набор тестов, tsc, языковой сервер или база данных в Docker. Выбирайте ресурсы исходя из требований инструментария, а не CLI. Добавьте swap, даже если не планируете его использовать — это превратит критическую ошибку OOM kill в медленную сборку:

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Также следите за диском: репозитории, node_modules и образы Docker быстро накапливаются. Если инструментарий выходит за пределы контейнеров и использует полноценные виртуальные машины — например, гостевую ОС KVM или локальный узел Kubernetes — перед покупкой убедитесь, что тарифный план поддерживает расширения виртуализации CPU. Запуск вложенной виртуализации на VPS — это функция, которую провайдер должен включить на своей стороне, а не настройка, которую можно активировать внутри гостевой системы.

Сначала создайте пользователя без прав root

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

sudo adduser --disabled-password --gecos "" agent
sudo install -d -m 700 -o agent -g agent /home/agent/.ssh
sudo cp ~/.ssh/authorized_keys /home/agent/.ssh/authorized_keys
sudo chown agent:agent /home/agent/.ssh/authorized_keys
sudo chmod 600 /home/agent/.ssh/authorized_keys

Намеренно agent не входит в группу sudo. Если потребуется системный пакет, вы установите его. Такое решение исключает большинство способов, которыми случайная команда в shell может повредить хост.

Гигиена SSH для постоянно работающего сервера

Аутентификация по паролю на устройстве, доступном из публичного интернета, представляет излишний риск, так как на нем хранятся агент и ваш исходный код. Отключите ее. В Ubuntu 24.04 и Debian 13 /etc/ssh/sshd_config включает /etc/ssh/sshd_config.d/*.conf, поэтому вместо редактирования основного конфигурационного файла лучше создать отдельный файл:

# /etc/ssh/sshd_config.d/10-hardening.conf
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no

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

sudo sshd -t && sudo systemctl restart ssh

Особенность Ubuntu 24.04: sshd работает через сокеты. Настройки аутентификации применяются в systemctl restart ssh, но изменения в слушающем Port также требуют systemctl daemon-reload и перезапуска ssh.socket.

Затем настройте firewall. Разрешите SSH до того, как включите его, иначе вы потеряете доступ к системе:

sudo ufw allow OpenSSH
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw enable

Устанавливайте fail2ban, понимая его назначение: после отключения аутентификации по паролю атаки методом перебора (brute force) станут неэффективны — этот инструмент просто очищает журнал от записей о неудачных попытках входа.

# /etc/fail2ban/jail.local
[sshd]
enabled = true
backend = systemd
maxretry = 5
bantime = 1h

Наконец, настройте автоматические обновления с помощью sudo apt install unattended-upgrades и sudo dpkg-reconfigure -plow unattended-upgrades. Учтите взаимодействие с tmux: если включен Unattended-Upgrade::Automatic-Reboot, обновление ядра приведет к перезагрузке системы и завершению всех сессий. Если оставить функцию выключенной, перезагружайте систему самостоятельно в удобное время, когда нет запущенных процессов.

Установка Node.js и Claude Code на Ubuntu

Claude Code — это CLI-инструмент для Node.js, поэтому вам требуется актуальная версия Node. Пакеты из стандартных репозиториев дистрибутива часто устаревают. Для Ubuntu и Debian обычно используют NodeSource; этот репозиторий является подписанным (без apt-key — этот инструмент удален):

curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
node --version

Важный момент, в котором часто допускают ошибку: устанавливайте CLI под вашим agent пользователем, никогда не используйте sudo npm -g. Глобальный префикс, принадлежащий root, приведет к ошибкам прав доступа в дальнейшем и оставит файлы root в кэше npm. Сначала укажите домашнюю директорию пользователя в качестве префикса npm:

mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
npm install -g @anthropic-ai/claude-code
claude --version

Переменную export нужно добавить в ~/.bashrc, а не в ~/.profile. Она должна располагаться выше условия «If not running interactively, don't do anything» в начале файла: tmux может запускать non-login оболочки, которые считывают ~/.bashrc и пропускают ~/.profile~/.profile выполняется только для login оболочек. Использование Node через менеджер версий, например nvm, дает тот же результат; в обоих случаях цель состоит в том, чтобы для npm install -g никогда не требовался sudo. npm будет работать корректно, либо можно использовать нативный скрипт установки от Anthropic, который сейчас является стандартным методом. Перед выполнением команд проверьте документацию Anthropic по установке — методы установки могут меняться.

Чтобы запустить инструмент, выполните claude внутри репозитория. При первом запуске будет выполнена аутентификация; на сервере без монитора (headless) нет браузера, поэтому система предоставит вам URL-адрес для открытия на локальном компьютере и код, который нужно ввести в терминале. (Альтернативный вариант — использование API-ключа в переменных окружения.) В любом случае учетные данные будут сохранены на сервере — это подводит нас к этапу, который часто пропускают.

Обсуждение радиуса поражения

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

  • Выделенный непривилегированный пользователь. Без группы sudo и без домашнего каталога, общего с вашей учетной записью.
  • Отсутствие учетных данных production на машине. Никаких ~/.aws/credentials с ключами production, никаких .env, скопированных из production, и никаких паролей к базам данных с правами записи к критически важным объектам. Предоставьте агенту учетные данные для staging или только для чтения.
  • Ограниченные токены. Токен GitHub с мелкими правами доступа только к одному репозиторию; deploy key, если достаточно прав только на чтение.

Claude Code содержит flag, который полностью отключает запросы на подтверждение прав. На ноутбуке или в тестовом проекте решение остается за вами. На сервере с токенами этот flag убирает последнее препятствие между неверно понятой инструкцией и git push --force. Что именно меняет этот flag и как ограничить агента, работающего с ним — от встроенной песочницы до временного VPS — описано в безопасном запуске Claude Code на сервере.

Deploy key против SSH agent forwarding

Существует соблазн использовать ssh -A, чтобы git мог использовать ключ на вашем ноутбуке. Поймите, что это дает: agent forwarding открывает сокет вашего локального SSH agent процессам, запущенным от имени этого пользователя на машине. Любой процесс, запущенный от agent — включая агента — может запросить подпись вашего ключа для любого хоста, к которому у него есть доступ, пока вы остаетесь в сети. Это гораздо больше, чем просто «разрешить git pull из одного репозитория».

Вместо этого создайте ключ на сервере, зарегистрируйте его как deploy key для конкретного репозитория (только права записи, если агенту нужно выполнять push) и настройте git identity, чтобы коммиты с машины были идентифицируемы:

ssh-keygen -t ed25519 -C "agent deploy key" -f ~/.ssh/id_ed25519_repo
cat ~/.ssh/id_ed25519_repo.pub   # paste into the repo's Deploy Keys
git config --global user.name "Agent (build box)"
git config --global user.email "agent@example.com"

Рабочий процесс tmux

Установите его (sudo apt install tmux), затем настройте минимальный ~/.tmux.conf:

set -g mouse on
set -g history-limit 50000
set -g default-terminal "tmux-256color"

Для повседневного использования достаточно четырех команд:

tmux new -A -s claude     # attach to session "claude", creating it if absent
# ...run `claude` inside it, work normally...
# Ctrl-b then d           -> detach; everything keeps running
tmux ls                   # list sessions
tmux attach -t claude     # reattach, from this machine or any other
tmux kill-session -t claude

Запомните команду tmux new -A -s claude — она подключается к существующей сессии или создает новую, если сессии нет. Это позволяет использовать одну команду как для начала работы, так и для возобновления сессии после разрыва соединения. Создайте для нее alias. Внутри сессии Ctrl-b c открывает окно, Ctrl-b n и Ctrl-b p переключают окна, а Ctrl-b [ включает режим копирования для прокрутки истории (q — выход).

Важная особенность сессий, которые вы не завершаете: агент повторно отправляет всю переписку при каждом шаге. Ознакомьтесь с информацией на что тратит токены длительная сессия Claude Code, прежде чем оставлять сессию запущенной на неделю.

Режимы сбоев

«Моя сессия исчезла». tmux ls выводит no server running on /tmp/tmux-1000/default. Это почти всегда означает, что процесс не запускался внутри tmux — вы вошли через SSH, запустили claude напрямую, и разрыв соединения завершил процесс. Восстановить данные невозможно. Чтобы избежать этого, всегда используйте tmux new -A -s <project> как первую команду после входа.

Панель сжимается до крошечного окна. tmux подстраивает размер сессии под самого маленького подключенного клиента. Если к сессии все еще подключен неактивный клиент с другого устройства, дисплей будет сжат. При подключении принудительно отключите остальных: tmux attach -d -t claude.

Сборка выводит Killed. Одно слово, без трассировки стека. Проверьте с помощью sudo dmesg -T | grep -i -E 'out of memory|killed process' — это сработал kernel OOM killer, выбрав самый ресурсоемкий процесс. В Node вместо этого может появиться FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory. Способы решения (в порядке приоритетности): добавьте swap (см. выше), ограничьте количество потоков тестов и компилятора, увеличьте heap в Node с помощью NODE_OPTIONS=--max-old-space-size=... или увеличьте ресурсы VPS. OOM killer также может выбрать tmux server вместо процесса сборки, что приведет к потере сессии; если запущен systemd-oomd, он может завершить весь user slice с тем же результатом.

npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Глобальная установка в префикс, принадлежащий root. Используйте префикс ~/.npm-global, указанный выше. Если вы ранее запускали sudo npm, вы также можете увидеть Your cache folder contains root-owned files — исправьте это с помощью sudo chown -R $(id -u):$(id -g) ~/.npm.

claude: command not found — но только иногда. Ваш экспорт PATH находится в ~/.bashrc ниже условия «If not running interactively, don't do anything», поэтому неинтерактивные оболочки его пропускают. Перенесите экспорт выше этого условия и храните его в ~/.bashrc, а не в ~/.profile: tmux может запускать non-login shells, которые считывают ~/.bashrc, но не обращаются к ~/.profile.

Искажение цветов после подключения. Несоответствие TERM — решение описано в строке default-terminal выше.

Сессии исчезают после перезагрузки. Это не ошибка: tmux server является процессом, и перезагрузка завершает его работу. Проверьте uptime.

Проблемы при масштабировании

Больше проектов. На каждый репозиторий создается одна сессия tmux с соответствующим именем; в этом случае tmux ls становится вашим дашбордом. Если пренебрегать дисциплиной именования, вы получите сессии 0, 1, 2. Аналогично разрастается количество портов — если шесть репозиториев требуют :3000, следует прекратить ручное назначение портов. Используйте маршрутизацию Traefik reverse proxy для нескольких приложений в Docker Compose, чтобы распределять трафик по hostname.

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

Автоматизированные задачи. tmux предназначен для интерактивных сессий, к которым вы подключаетесь. Задачи, которые запускаются по расписанию без участия человека, должны быть оформлены как systemd unit и timer. Это обеспечивает логирование, политику перезапуска и автоматический запуск после загрузки системы. Использование tmux для запуска задач по типу cron означает, что задачу следует перевести в статус сервиса.

Последнее замечание: привязывайте dev-серверы, которые запускает агент, к 127.0.0.1, а не к 0.0.0.0, и подключайтесь к ним через SSH-туннель (ssh -L 3000:127.0.0.1:3000 agent@your-server), а не через открытие портов в ufw. Если вам нужно пробросить более пяти портов или если к одному превью одновременно подключаются телефон и ноутбук, установите self-hosted WireGuard VPN на VPS. В этом случае dev-серверы будут привязаны к приватному интерфейсу, а ufw продолжит блокировать все входящие соединения на публичном интерфейсе. Механизм firewall эффективен только тогда, когда вы не открываете в нем лишние порты.

Claude Code — не единственный вариант: запуск AI-агента для кодинга на VPS также включает в себя Aider и Goose.

FAQ

Продолжает ли Claude Code работу после разрыва SSH-соединения?

Только если вы запустили его внутри tmux. Процесс, запущенный напрямую из SSH-оболочки, является ее дочерним процессом и завершается вместе с pty при разрыве связи. Внутри tmux оболочка принадлежит отсоединенному (detached) серверу tmux, поэтому агент продолжает выполнение задачи, а tmux attach вернет вас к тому же выводу (scrollback). Используйте tmux new -A -s <project> в качестве первой команды после каждого входа, чтобы избежать этой проблемы.

Стоит ли устанавливать CLI с помощью sudo npm install -g?

Нет. Глобальный префикс под управлением root приведет к ошибкам EACCES при последующих установках и создаст файлы в кэше npm под управлением root. Установите префикс npm в ~/.npm-global (или используйте менеджер версий, например nvm), выполняйте установку от имени непривилегированного пользователя agent и экспортируйте ~/.npm-global/bin в PATH из ~/.bashrc перед интерактивной защитой. Если вы уже запускали sudo npm, исправьте кэш с помощью sudo chown -R $(id -u):$(id -g) ~/.npm.

Безопасен ли агентный форвардинг ssh -A на хосте, где запущен агент?

Это предоставляет гораздо больше прав, чем необходимо для работы. Форвардинг открывает сокет вашего локального SSH-агента для каждого процесса, запущенного от имени этого пользователя. Любой процесс на хосте может использовать ваш ключ для подписи запросов к любому доступному хосту, пока ваше соединение активно. Создайте ключ ed25519 на сервере и зарегистрируйте его как deploy key для конкретного репозитория с правами на запись только в том случае, если агенту действительно требуется выполнять push.

Почему сборка просто выводит Killed?

Одиночное слово без трассировки стека означает работу kernel OOM killer. Подтвердите это с помощью sudo dmesg -T | grep -i -E 'out of memory|killed process'; в Node вместо этого может отображаться JavaScript heap out of memory. Выполняйте исправления в следующем порядке: добавьте swapfile, ограничьте параллелизм тестов и компилятора, увеличьте NODE_OPTIONS=--max-old-space-size=..., затем увеличьте размер VPS. Учтите, что OOM killer может завершить процесс tmux вместо процесса сборки, что приведет к потере всей сессии.

tmux или системная служба systemd?

tmux подходит для интерактивных сессий, к которым вы подключаетесь, за которыми наблюдаете и в которых вводите команды; это именно то, чем является сессия агента. Работа, выполняемая по расписанию без участия пользователя, должна быть оформлена в виде unit и таймера systemd, где логирование, политика перезапуска и автозапуск при загрузке предоставляются по умолчанию. Если вы используете tmux для запуска задачи по типу cron, эту задачу следует оформить как службу.