SSD Nodes Learn Hosting plans →
Panduan Matt ConnorOleh Matt Connor · Dikemas kini 2026-08-29

Jalankan Claude Code pada VPS jauh dengan tmux

Pastikan sesi Claude Code terus berjalan pada VPS Linux walaupun SSH terputus. Ketahui cara memasang, mengeraskan pelayan dan menangani kegagalan SIGHUP.

Masalahnya ialah penutup komputer riba, bukan CLI

Claude Code berjalan dengan baik pada komputer riba anda sehingga anda menutup penutupnya: sesi SSH terputus, shell menerima SIGHUP, dan ejen yang baru tiga minit menjalankan ujian turut terhenti. Jalankan CLI pada mesin yang tidak pernah tidur, di dalam multiplexer terminal yang prosesnya bukan anak kepada sesi SSH anda. Itulah keseluruhan caranya. tmux, bukan pemasangan, ialah bahagian yang paling penting.

Halaman ini menerangkan cara mengendalikan mesin yang digunakan untuk menjalankan ejen secara berterusan. Jika anda tidak mempunyai pelayan Linux yang boleh dibiarkan hidup, tiada satu pun langkah ini terpakai. Itulah prasyarat yang perlu dinyatakan dengan jujur.

Apa yang sebenarnya dilakukan oleh tmux

Apabila anda menyambung melalui SSH, sshd mencabang satu shell dan memberikannya pseudo-terminal; segala yang anda mulakan daripada shell itu menjadi proses anaknya. Apabila sambungan terputus, kernel memusnahkan pty tersebut, shell menerima SIGHUP, kemudian menghantar isyarat hangup kepada proses anaknya. Proses latar hadapan yang berjalan lama akan terhenti.

tmux membalikkan hubungan pemilikan ini. Perintah tmux yang anda taip ialah klien ringan yang berkomunikasi melalui unix socket dengan pelayan tmux yang berjalan secara detached daripada terminal anda. Shell dalam satu session ialah proses anak pelayan tersebut, bukan proses anak sshd. Apabila sambungan SSH ditamatkan, klien terhenti tetapi pelayan, session dan agent yang sedang menjalankan tugas terus berjalan. Sambung semula, tmux attach, dan anda kembali ke shell yang sama dengan scrollback yang sama. nohup juga kekal berjalan selepas hangup, tetapi tidak menyediakan cara untuk anda masuk semula; anda tidak boleh attach semula kepada TUI yang dijalankan di latar belakang. Claude Code bersifat interaktif; tmux (atau screen) ialah alat yang sesuai.

Menentukan saiz pelayan

CLI ialah proses Node; CLI bukan komponen yang memenuhi sumber mesin. Yang memenuhi sumber mesin ialah apa-apa sahaja yang dijalankan oleh ejen bagi pihak anda: binaan, suite ujian penuh, tsc, pelayan bahasa atau pangkalan data dalam Docker. Tentukan saiz berdasarkan toolchain, bukan CLI. Tambahkan swap walaupun anda bercadang untuk tidak menggunakannya. Swap menukar penamatan proses akibat OOM yang serta-merta kepada binaan yang perlahan:

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

Pantau ruang cakera juga. Repositori, node_modules dan imej Docker cepat memenuhi ruang. Jika toolchain melangkaui kontena hingga menggunakan mesin maya penuh, seperti tetamu KVM atau nod Kubernetes tempatan, semak dahulu sama ada pelan tersebut mendedahkan sambungan virtualisasi CPU sebelum membuat komitmen. Menjalankan virtualisasi bersarang pada VPS memerlukan penyedia mengaktifkannya untuk anda, bukan anda mengaktifkannya dari dalam tetamu.

Pengguna bukan root dahulu

Cipta pengguna khusus dengan direktori home sendiri, kemudian letakkan kunci awam anda di tempat yang betul:

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

Uji log masuk dari terminal kedua sebelum meneruskan, sementara pengesahan kata laluan masih tersedia sebagai sandaran. Jika anda menerima Kebenaran ditolak (publickey), puncanya biasanya pemilikan atau mod pada direktori .ssh itu, bukannya kunci tersebut.

Secara sengaja, agent tidak termasuk dalam kumpulan sudo. Jika pakej sistem diperlukan, pasangkannya. Satu keputusan ini menghapuskan kebanyakan cara arahan shell yang tersalah jalankan boleh merosakkan hos.

Kebersihan SSH untuk pelayan yang dibiarkan berjalan

Pengesahan kata laluan pada mesin yang sentiasa berada di Internet awam, serta menyimpan ejen dan kod sumber anda, bukan risiko yang wajar ditanggung. Matikannya. Pada Ubuntu 24.04 dan Debian 13, /etc/ssh/sshd_config menyertakan /etc/ssh/sshd_config.d/*.conf, jadi masukkan fail dan bukannya mengedit konfigurasi utama:

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

Sahkan konfigurasi dan muat semula, sambil mengekalkan sesi semasa terbuka ketika anda menguji sesi baharu dari terminal kedua:

sudo sshd -t && sudo systemctl restart ssh

Terdapat satu perkara khusus pada Ubuntu 24.04: sshd diaktifkan melalui socket. Tetapan pengesahan digunakan pada systemctl restart ssh, tetapi perubahan pada Port yang mendengar juga memerlukan systemctl daemon-reload dan mula semula ssh.socket.

Kemudian konfigurasikan firewall. Benarkan SSH sebelum mengaktifkannya, atau anda akan terkunci di luar pelayan:

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

Pasang fail2ban dengan memahami manfaatnya: selepas pengesahan kata laluan dimatikan, serangan brute force tidak lagi boleh berjaya; ia hanya menghalang percubaan yang gagal daripada memenuhi journal anda.

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

Akhir sekali, pasang patch secara automatik dengan sudo apt install unattended-upgrades dan sudo dpkg-reconfigure -plow unattended-upgrades. Ambil perhatian tentang interaksinya dengan tmux: hidupkan Unattended-Upgrade::Automatic-Reboot dan kemas kini kernel akan memulakan semula pelayan, lalu menamatkan semua sesi bersamanya. Biarkan ia dimatikan dan mulakan semula pelayan mengikut jadual anda sendiri, ketika tiada proses sedang berjalan. Langkah berjaga-jaga yang sama terpakai untuk peningkatan keluaran: menaik taraf pelayan daripada Ubuntu 24.04 kepada 26.04 akan memulakan semula sshd dan kernel, jadi lakukan dalam tempoh apabila tiada sesi tmux yang sedang menjalankan tugas penting.

Pasang Node.js dan Claude Code pada Ubuntu

Claude Code ialah CLI Node, jadi anda memerlukan Node semasa. Pakej distro selalunya ketinggalan; NodeSource ialah kaedah biasa pada Ubuntu dan Debian, dan menyediakan repositori bertandatangan (tanpa apt-key kerana alat itu sudah tidak digunakan):

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

Sekarang bahagian yang sering dilakukan dengan salah: pasang CLI sebagai pengguna agent anda, jangan sekali-kali gunakan sudo npm -g. Awalan global yang dimiliki root akan menyebabkan ralat permission kemudian dan meninggalkan fail milik root dalam cache npm. Tetapkan prefix npm kepada direktori home pengguna terlebih dahulu:

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

Eksport itu diletakkan dalam ~/.bashrc, bukan ~/.profile, dan mesti diletakkan di atas pengawal "If not running interactively, don't do anything" berhampiran bahagian atas fail tersebut: tmux mungkin memulakan shell bukan login, yang membaca ~/.bashrc dan melangkau ~/.profile, manakala ~/.profile hanya dijalankan untuk shell login. Node setiap pengguna melalui pengurus versi seperti nvm mencapai hasil yang sama; matlamatnya ialah npm install -g tidak perlu menggunakan sudo. npm masih berfungsi dengan baik, atau gunakan skrip pemasangan asli Anthropic, iaitu kaedah lalai yang didokumenkan pada masa ini. Semak dokumentasi pemasangan Anthropic sebelum menampalnya kerana kaedah pemasangan boleh berubah.

Jalankan claude dalam repo untuk memulakannya. Pada kali pertama dijalankan, anda akan dipandu melalui proses pengesahan; mesin headless tidak mempunyai browser, jadi proses itu memberikan URL untuk dibuka pada mesin anda sendiri dan kod untuk dibawa kembali ke terminal. (API key dalam persekitaran ialah kaedah alternatif.) Walau apa pun kaedahnya, kelayakan itu kini tersimpan pada pelayan, dan ini membawa kita kepada bahagian yang sering dilangkau.

Perbincangan tentang skop kesan

Ejen yang mempunyai akses shell ialah shell. Ejen itu boleh membaca apa-apa yang boleh dibaca oleh pengguna yang menjalankannya dan menghantar ke mana-mana lokasi yang boleh dicapai oleh pengguna tersebut. Ini bukan kritikan terhadap alat itu. Ini ialah takrif alat tersebut, dan sebabnya akaun yang digunakan untuk menjalankannya lebih penting daripada sebarang tetapan individu.

  • Pengguna khusus tanpa keistimewaan. Tiada kumpulan sudo, dan tiada direktori rumah yang dikongsi dengan akaun anda sendiri.
  • Tiada bukti kelayakan produksi pada pelayan. Tiada ~/.aws/credentials yang menyimpan kunci produksi, tiada .env yang disalin daripada produksi, dan tiada kata laluan pangkalan data dengan akses tulis kepada apa-apa yang penting. Berikan ejen bukti kelayakan staging atau baca sahaja.
  • Token berskop. Token GitHub berbutir halus yang dihadkan kepada satu repositori; deploy key apabila akses baca sudah mencukupi.

Claude Code menyediakan flag yang melangkau gesaan kebenarannya sepenuhnya. Pada komputer riba atau projek sementara, keputusan itu terpulang kepada anda. Pada pelayan yang menyimpan token, flag tersebut menghapuskan perlindungan terakhir antara arahan yang disalah tafsir dengan git push --force. Gesaan yang dilangkau itu juga bukan pilihan semua atau tiada langsung. Dengan mod automatik yang akan menjadi lalai baharu, anda perlu mengetahui mod kebenaran yang patut ditetapkan secara kekal pada pelayan yang tidak anda pantau. Perubahan sebenar yang dibuat oleh flag tersebut serta cara mengehadkan ejen yang dijalankan bersamanya, daripada sandbox terbina dalam hingga VPS pakai buang, dibincangkan dalam menjalankan Claude Code dengan selamat pada pelayan.

Deploy key berbanding pemajuan SSH agent

Anda mungkin tergoda untuk ssh -A supaya git boleh menggunakan kunci pada komputer riba anda. Fahami akses yang diberikan: pemajuan agent mendedahkan soket SSH agent tempatan anda kepada proses yang dijalankan sebagai pengguna tersebut pada pelayan. Apa-apa sahaja yang dijalankan sebagai agent, termasuk ejen itu sendiri, boleh meminta kunci anda menandatangani untuk mana-mana hos yang boleh dicapainya, selagi anda kekal bersambung. Akses itu jauh lebih luas daripada sekadar “membenarkan git pull repositori ini”.

Sebaliknya, jana kunci pada pelayan, daftarkannya sebagai deploy key untuk repositori tertentu (akses tulis hanya jika ejen perlu push), dan tetapkan identiti git supaya commit daripada pelayan dapat dikenal pasti:

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"

Aliran kerja tmux

Pasang tmux (sudo apt install tmux), kemudian gunakan konfigurasi minimum ~/.tmux.conf:

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

Empat arahan ini mencukupi untuk penggunaan harian:

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 ialah arahan yang perlu dihafal. Arahan ini menyambungkan anda kepada sesi jika sesi tersebut wujud dan menciptanya jika sesi tersebut tiada. Oleh itu, satu arahan boleh digunakan untuk memulakan kerja dan menyambung semula selepas sambungan terputus. Jadikan arahan ini sebagai alias. Dalam sesi, Ctrl-b c membuka tetingkap, Ctrl-b n dan Ctrl-b p beralih antara tetingkap, manakala Ctrl-b [ memasuki mod salin untuk menatal ke log lama (q untuk keluar).

Satu perkara yang perlu diketahui tentang sesi yang tidak pernah ditamatkan: ejen menghantar semula keseluruhan perbualan pada setiap giliran. Oleh itu, baca perkara yang menggunakan token dalam sesi Claude Code yang berjalan lama sebelum anda membiarkan sesi tersebut berjalan selama seminggu.

Mod kegagalan

"Sesi saya hilang." tmux ls mencetak no server running on /tmp/tmux-1000/default. Ini hampir selalu bermaksud proses tersebut tidak pernah berjalan di dalam tmux. Anda membuat sambungan SSH, menjalankan claude secara terus, lalu pemutusan sambungan menamatkan proses itu. Tiada apa-apa yang boleh dipulihkan. Amalan yang mengelakkan masalah ini: tmux new -A -s <project> ialah arahan pertama selepas setiap log masuk.

Anak tetingkap mengecil menjadi kotak yang sangat kecil. tmux menetapkan saiz sesi mengikut klien terlampir yang paling kecil. Oleh itu, klien lama yang masih terlampir dari mesin lain mengecilkan paparan. Paksa klien lain ditamatkan semasa anda melampirkan sesi: tmux attach -d -t claude.

Binaan mencetak Killed. Hanya satu perkataan tanpa jejak tindanan. Sahkan dengan sudo dmesg -T | grep -i -E 'out of memory|killed process'. Kernel OOM killer telah memilih proses yang paling besar. Dari Node, anda mungkin melihat FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory. Penyelesaian mengikut urutan: tambah swap seperti di atas, hadkan keupayaan selari ujian dan pengkompil, tingkatkan heap Node dengan NODE_OPTIONS=--max-old-space-size=..., atau tingkatkan saiz VPS. OOM killer juga mungkin memilih pelayan tmux, bukannya proses binaan, lalu menamatkan sesi anda. Jika systemd-oomd sedang berjalan, proses itu juga boleh menamatkan keseluruhan user slice dengan kesan yang sama.

npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Pemasangan global ke dalam prefix yang dimiliki oleh root. Gunakan prefix ~/.npm-global di atas. Jika anda pernah menjalankan sudo npm, anda mungkin turut melihat Your cache folder contains root-owned files. Baikinya dengan sudo chown -R $(id -u):$(id -g) ~/.npm.

claude: command not found, tetapi hanya kadangkala. Eksport PATH anda berada dalam ~/.bashrc di bawah pengawal "If not running interactively, don't do anything", jadi shell bukan interaktif melangkau eksport itu. Alihkan eksport tersebut ke atas pengawal itu dan kekalkannya dalam ~/.bashrc, bukan ~/.profile. tmux mungkin memulakan shell bukan login yang membaca ~/.bashrc dan tidak pernah membaca ~/.profile.

Warna menjadi bercelaru selepas melampirkan sesi. Berlaku ketidakpadanan TERM. Baris default-terminal di atas ialah pembaikannya.

Sesi hilang selepas reboot. Ini bukan pepijat. Pelayan tmux ialah proses, dan reboot menamatkannya. Semak uptime.

Perkara yang berubah apabila skala bertambah

Lebih banyak projek. Gunakan satu sesi tmux bagi setiap repositori dan namakan sesi itu mengikut repositori; tmux ls menjadi papan pemuka anda. Jika disiplin penamaan diabaikan, anda akan mendapat sesi 0, 1, 2. Apabila beberapa sesi berjalan serentak, sesi tersebut tidak semestinya berfungsi secara berasingan kerana satu sesi boleh menghantar mesej kepada sesi lain pada pelayan yang sama. Ini berguna apabila ejen yang sedang menjalankan refaktor panjang mahu meminta ejen kedua menjalankan ujian. Port turut bertambah dengan cara yang sama. Jika enam repositori semuanya memerlukan :3000, berhenti menetapkan port secara manual dan biarkan reverse proxy Traefik menghala beberapa aplikasi dalam Docker Compose berdasarkan hostname.

Lebih ramai pengguna. Soket tmux adalah khusus bagi setiap pengguna. Oleh itu, dua pembangun pada pelayan yang sama masing-masing mendapat pelayan tmux sendiri dan tidak dapat melihat sesi pengguna lain. Berkongsi satu sesi melalui soket yang dikongsi bermakna semua orang menaip ke dalam shell yang sama sebagai pengguna Unix yang sama, dengan implikasi terhadap audit dan permission. Menggunakan pengguna berasingan ialah pilihan yang lebih mudah dan betul.

Kerja tanpa pemantauan. tmux adalah untuk sesi interaktif yang anda sambungkan. Kerja yang dijalankan mengikut jadual tanpa sesiapa memantaunya sepatutnya menggunakan unit dan timer systemd. Dengan cara ini, kerja tersebut mendapat log, polisi restart dan keupayaan untuk terus berjalan selepas boot. Menggunakan tmux untuk menjalankan kerja berbentuk cron menunjukkan bahawa kerja itu sepatutnya dijadikan servis.

Satu perkara terakhir: ikat pelayan dev yang dimulakan oleh ejen kepada 127.0.0.1, bukan 0.0.0.0, dan capainya melalui SSH tunnel (ssh -L 3000:127.0.0.1:3000 agent@your-server), bukannya dengan membuka port dalam ufw. Jika anda sudah memajukan enam port atau lebih, atau telefon dan komputer riba mahu mengakses pratonton yang sama, letakkan VPN WireGuard yang dihoskan sendiri pada VPS di hadapannya. Pelayan dev akan diikat pada antara muka peribadi, manakala ufw terus menolak semua sambungan daripada antara muka awam. Firewall hanya membantu jika anda berhenti membuka lubang padanya.

Claude Code bukan satu-satunya pilihan: menjalankan ejen AI pengekodan pada VPS turut membandingkan Aider dan Goose.

FAQ

Adakah Claude Code terus berjalan selepas sambungan SSH saya terputus?

Hanya jika anda memulakannya di dalam tmux. Proses yang dilancarkan terus daripada shell SSH ialah proses anak shell tersebut dan akan terhenti bersama pty apabila sambungan terputus. Di dalam tmux, shell itu dimiliki oleh pelayan tmux yang telah dipisahkan, jadi ejen terus bekerja pada tugasan semasa dan tmux attach membawa anda kembali ke scrollback yang sama. Jadikan tmux new -A -s <project> arahan pertama selepas setiap log masuk supaya masalah ini tidak berlaku lagi.

Patutkah saya memasang CLI dengan sudo npm install -g?

Tidak. Prefix global yang dimiliki root akan menyebabkan ralat EACCES semasa pemasangan seterusnya dan menghasilkan fail milik root dalam cache npm. Tetapkan prefix npm kepada ~/.npm-global (atau gunakan pengurus versi seperti nvm), pasang sebagai pengguna tanpa keistimewaan agent, kemudian eksport ~/.npm-global/bin ke PATH daripada ~/.bashrc, di atas pengawal interaktif. Jika anda sudah menjalankan sudo npm sekali, baiki cache dengan sudo chown -R $(id -u):$(id -g) ~/.npm.

Adakah ssh -A agent forwarding selamat pada pelayan yang menjalankan ejen?

Ia memberikan keistimewaan yang jauh melebihi keperluan tugasan. Forwarding mendedahkan soket SSH agent tempatan anda kepada setiap proses yang berjalan sebagai pengguna tersebut. Oleh itu, apa-apa sahaja pada pelayan itu boleh meminta kunci anda menandatangani permintaan untuk mana-mana hos yang boleh dicapainya, selagi sambungan anda kekal aktif. Jana kunci ed25519 pada pelayan dan daftarkannya sebagai deploy key khusus repositori, dengan akses tulis hanya jika ejen memang perlu melakukan push.

Mengapakah binaan saya hanya mencetak Killed?

Satu perkataan tanpa stack trace biasanya menunjukkan kernel OOM killer. Sahkan dengan sudo dmesg -T | grep -i -E 'out of memory|killed process'; daripada Node, anda mungkin melihat JavaScript heap out of memory pula. Laksanakan pembaikan mengikut turutan: tambah swapfile, hadkan keparalelan ujian dan pengkompil, tingkatkan NODE_OPTIONS=--max-old-space-size=..., kemudian naik taraf saiz VPS. Berhati-hati kerana OOM killer boleh memilih pelayan tmux dan bukannya proses binaan, lalu memutuskan seluruh sesi anda.

tmux atau servis systemd?

tmux sesuai untuk sesi interaktif yang anda sambungkan, pantau dan gunakan untuk memasukkan arahan. Itulah ciri sesi ejen. Kerja yang berjalan mengikut jadual tanpa sesiapa memantaunya lebih sesuai diletakkan dalam unit dan timer systemd, kerana pengelogan, dasar mula semula dan kesinambungan selepas boot tersedia secara terbina dalam. Jika anda menggunakan tmux untuk menjalankan kerja yang berbentuk seperti cron, kerja itu sebenarnya memerlukan servis.