SSD Nodes Learn
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-07-24

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

Запускайте Claude Code на Linux VPS у сесії tmux, щоб уникнути переривання агентів через SIGHUP при розриві SSH-з'єднання. Покрокова інструкція з налаштування.

Проблема у кришці ноутбука, а не у CLI

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

Ця сторінка присвячена експлуатації сервера, на якому залишаються запущені агенти. Якщо у вас немає Linux-сервера, який може працювати постійно, ці поради не застосовуються. Це єдина обов'язкова умова.

Що насправді робить tmux

При підключенні через SSH sshd створює дочірчий процес shell і передає йому pseudo-terminal; усі процеси, запущені з цього shell, є його дочірніми процесами. Якщо розірвати з'єднання, ядро видаляє pty, shell отримує сигнал SIGHUP і, відповідно, завершує роботу своїх дочірніх процесів. Довготривалі foreground-процеси при цьому завершуються.

tmux змінює принцип володіння процесами. Команда tmux, яку ви вводите, є тонким клієнтом, що взаємодіє через unix socket із tmux server, який працює окремо від вашого термінала. Shell всередині сесії є дочірнім процесом сервера, а не sshd. Якщо розірвати SSH-з'єднання, клієнт завершиться, але сервер, сесія та агент продовжуватимуть виконання завдання. Після повторного підключення через tmux attach ви повернетеся в той самий shell із тим самим буфером прокрутки (scrollback). nohup також витримує розрив зв'язку, але не дозволяє повернутися — ви не зможете приєднатися (re-attach) до фонового 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 може пошкодити host.

SSH-гігієна для сервера, що працює постійно

Автентифікація за паролем на машині, що постійно перебуває в публічному інтернеті та має доступ до agent та вашого вихідного коду, створює надмірний ризик. Вимкніть її. В 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 працює через socket-activation. Налаштування автентифікації застосовуються на 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 — це Node CLI, тому вам потрібна актуальна версія 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 shells, які зчитують ~/.bashrc і пропускають ~/.profile~/.profile виконується лише для login shells. Використання Node для окремого користувача через менеджер версій, наприклад nvm, дає той самий результат; мета полягає в тому, щоб npm install -g ніколи не потребував sudo. npm працюватиме коректно, або можна використати нативний скрипт встановлення від Anthropic, який зараз є стандартним. Перевірте документацію Anthropic перед копіюванням — методи встановлення змінюються.

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

Обговорення радіуса ураження

Агент із доступом до shell — це shell. Він може читати все, що доступно користувачу, під яким він запущений, і здійснювати push куди завгодно, куди має доступ цей користувач. Це не критика інструменту, а його визначення. Саме тому обліковий запис, під яким працює агент, важливіший за будь-які окремі налаштування.

  • Виділений непривілейований користувач. Без групи sudo та без спільної домашньої директорії з вашим основним обліковим записом.
  • Відсутність production-credentials на хості. Жодних ~/.aws/credentials з production-ключами, жодних .env, скопійованих з production, жодних паролів до баз даних із правами на запис до критичних об'єктів. Надайте агенту staging або read-only credentials.
  • Обмежені токени (Scoped tokens). Токен GitHub з точковим доступом лише до одного репозиторію; deploy key, якщо достатньо лише прав на читання.

Claude Code має прапорець, який повністю пропускає запити на підтвердження дозволів. На ноутбуці або в тимчасовому проєкті це рішення за вами. На сервері, де зберігаються токени, цей прапорець прибирає останній бар'єр між помилковою інструкцією та git push --force. Що саме змінює цей прапорець і як обмежити агента, який працює з ним — від вбудованого sandbox до тимчасового 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, перш ніж залишати сесію працювати на тиждень.

Failure modes

"My session is gone." 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. Одне слово, без stack trace. Перевірте за допомогою 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 за іменем хоста.

Більше людей. Сокети tmux створюються для кожного користувача окремо, тому два розробники на одному сервері отримують власні сервери tmux і не бачать сеансів один одного. Використання одного сеансу через спільний сокет означає, що всі вводять команди в одну і ту ж оболонку під одним Unix-користувачем, що несе ризики для аудиту та прав доступу. Використання окремих користувачів — це правильний і надійний варіант.

Автоматизація завдань. tmux призначений для інтерактивних сеансів, до яких ви підключаєтеся. Завдання, що виконуються за розкладом без участі людини, мають бути оформлені як systemd unit та timer. Це забезпечує логування, політику перезапуску та автоматичний запуск після завантаження системи. Використання tmux для завдань типу cron означає, що це завдання має стати сервісом.

Останнє зауваження: прив'язуйте (bind) 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 продовжуватиме блокувати всі запити з публічного інтерфейсу. Фаєрвол корисний лише тоді, коли ви не створюєте в ньому постійні винятки.

Claude Code — не єдиний варіант: running a coding AI agent on a VPS також розглядає Aider та Goose.

FAQ

Чи продовжує Claude Code роботу після розриву SSH-з'єднання?

Тільки якщо ви запустили його всередині tmux. Процес, запущений безпосередньо через SSH-оболону, є дочірнім процесом цієї оболони та завершується разом із pty після розриву зв'язку. У tmux оболона належить від'єднаному (detached) серверу tmux, тому агент продовжує виконання завдання, а tmux attach поверне вас до того самого буфера прокрутки. Використовуйте 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 для конкретного репозиторію з правами на запис лише у разі необхідності пушу.

Чому мій білд просто виводить 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, це завдання має бути службою.