SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-08-25

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

Запуск Claude Code на Linux VPS внутри tmux предотвращает завершение сессии при разрыве SSH. Узнайте, как настроить среду, избежать ошибки SIGHUP и обеспечить работу агента.

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

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

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

Принцип работы tmux

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

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

Выбор размера сервера

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

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

Проверьте возможность входа со второго терминала, прежде чем продолжать работу, пока аутентификация по паролю доступна в качестве резервного варианта. Если система возвращает ошибку Permission denied (publickey), проблема обычно заключается в правах доступа или владельце каталога .ssh, а не в самом ключе.

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

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

Использование парольной аутентификации на машине, которая постоянно находится в публичном доступе, содержит 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.

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

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

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

# /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, обновление ядра перезагрузит сервер и завершит все сессии. Оставьте эту опцию выключенной и выполняйте перезагрузку по собственному графику, когда никакие процессы не запущены. Та же осторожность требуется при обновлении релиза: переход сервера с Ubuntu 24.04 на 26.04 приводит к перезапуску sshd и ядра, поэтому такие операции следует выполнять в окне обслуживания, когда в tmux нет важных незавершенных задач.

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

Claude Code — это CLI-инструмент на базе Node, поэтому вам потребуется актуальная версия 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 может запускать неинтерактивные оболочки, которые считывают ~/.bashrc и пропускают ~/.profile, а ~/.profile выполняется только для оболочек входа. Использование Node для конкретного пользователя через менеджер версий, такой как nvm, дает тот же результат; цель в любом случае состоит в том, чтобы npm install -g никогда не требовал sudo. npm по-прежнему работает корректно, либо используйте официальный скрипт установки от Anthropic — это текущий документированный стандарт. Перед выполнением команд сверьтесь с документацией по установке от Anthropic, так как методы установки могут меняться.

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

Разговор о радиусе поражения

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

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

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

Deploy key против SSH agent forwarding

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

Вместо этого сгенерируйте ключ на сервере, зарегистрируйте его как 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 — это команда, которую нужно запомнить: она подключается к существующей сессии или создает новую, если та отсутствует. Таким образом, одна команда подходит и для начала работы, и для восстановления после разрыва соединения. Создайте для неё алиас. Внутри сессии 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': OOM-killer ядра выбрал самый «тяжелый» процесс. В Node вы можете увидеть FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory. Решения в порядке приоритета: добавьте swap (см. выше), ограничьте параллелизм тестов и компиляции, увеличьте кучу Node с помощью NODE_OPTIONS=--max-old-space-size=... или увеличьте размер VPS. OOM-killer может выбрать и сервер tmux вместо процесса сборки, что приведет к потере сессии; если запущен systemd-oomd, он может убить весь пользовательский срез с тем же результатом.

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 ниже условия «Если оболочка не интерактивна, ничего не делать», поэтому неинтерактивные оболочки пропускают его. Переместите экспорт выше этого условия и держите его в ~/.bashrc, а не в ~/.profile: tmux может запускать неавторизованные (non-login) оболочки, которые читают ~/.bashrc и никогда не обращаются к ~/.profile.

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

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

Что перестает работать при масштабировании

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

Больше людей. Сокеты 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. Когда вы пробрасываете полдюжины портов или хотите получить доступ к превью с телефона и ноутбука одновременно, лучше разверните собственный WireGuard VPN на VPS. В этом случае dev-серверы будут привязаны к внутреннему интерфейсу, а ufw продолжит блокировать все входящие соединения из публичной сети. Межсетевой экран помогает только в том случае, если вы перестанете делать в нем исключения.

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

FAQ

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

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

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

Нет. Глобальный префикс, принадлежащий root, приводит к ошибкам EACCES при последующих установках и появлению файлов, принадлежащих root, в кэше npm. Установите префикс 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?

Одно слово без стека вызовов означает, что сработал 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 service?

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