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

Menjalankan Claude Code di VPS dengan tmux

Pelajari cara menjalankan Claude Code di VPS Linux yang selalu aktif dengan tmux agar sesi agent tetap berjalan setelah koneksi SSH terputus, termasuk instalasi dan kendala umum.

Masalahnya adalah penutup laptop, bukan CLI

Claude Code berjalan baik di laptop Anda sampai penutupnya ditutup: sesi SSH terputus, shell menerima SIGHUP, dan agent yang baru tiga menit menjalankan pengujian ikut berhenti. Jalankan CLI pada mesin yang tidak pernah masuk mode tidur, di dalam terminal multiplexer yang prosesnya bukan child dari sesi SSH Anda. Itulah satu-satunya trik yang diperlukan. Bagian pentingnya adalah tmux, bukan proses instalasi.

Halaman ini membahas cara mengoperasikan mesin yang digunakan untuk menjalankan agent. Jika Anda tidak memiliki server Linux yang dapat dibiarkan menyala, tidak ada bagian dari panduan ini yang berlaku. Itulah satu-satunya prasyarat yang perlu disampaikan secara jelas.

Apa yang sebenarnya dilakukan tmux

Saat Anda login melalui SSH, sshd membuat proses shell dan memberinya pseudo-terminal; semua proses yang Anda jalankan dari shell tersebut menjadi proses turunannya. Jika koneksi terputus, kernel menghentikan pty, shell menerima SIGHUP, lalu shell meneruskan sinyal hangup kepada proses turunannya. Proses foreground yang berjalan lama akan berhenti.

tmux membalikkan hubungan kepemilikan ini. Perintah tmux yang Anda ketik adalah thin client yang berkomunikasi melalui unix socket dengan server tmux yang berjalan terpisah dari terminal Anda. Shell di dalam session merupakan proses turunan server tersebut, bukan proses turunan sshd. Jika koneksi SSH dihentikan, client keluar, tetapi server, session, dan agent yang sedang menjalankan tugas tetap berjalan. Hubungkan kembali, jalankan tmux attach, dan Anda kembali ke shell yang sama dengan scrollback yang sama. nohup juga tetap berjalan setelah hangup, tetapi tidak menyediakan cara untuk masuk kembali; Anda tidak dapat melakukan re-attach ke TUI yang berjalan di background. Claude Code bersifat interaktif; tmux (atau screen) adalah tool yang tepat.

Menentukan ukuran server

CLI adalah proses Node; CLI bukan komponen yang memenuhi kapasitas mesin. Komponen yang memenuhi kapasitas mesin adalah apa pun yang dijalankan agen atas nama Anda: build, rangkaian pengujian lengkap, tsc, language server, atau database di Docker. Tentukan ukuran berdasarkan toolchain, bukan CLI. Tambahkan swap meskipun Anda berencana tidak pernah menggunakannya. Swap mengubah penghentian paksa akibat OOM menjadi build yang lambat:

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 juga disk: repositori, node_modules, dan image Docker cepat memenuhi kapasitas penyimpanan. Jika toolchain menggunakan lebih dari container, misalnya virtual machine penuh atau node Kubernetes lokal berbasis KVM, pastikan paket yang dipilih menyediakan ekstensi virtualisasi CPU sebelum Anda berlangganan. Menjalankan virtualisasi bertingkat pada VPS adalah fitur yang diaktifkan oleh provider, bukan fitur yang dapat Anda aktifkan dari dalam guest.

Pengguna non-root terlebih dahulu

Buat pengguna khusus dengan direktori home sendiri, lalu tempatkan kunci publik Anda:

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 login dari terminal kedua sebelum melanjutkan, saat autentikasi kata sandi masih tersedia sebagai cadangan. Jika muncul Akses ditolak (publickey), penyebabnya biasanya adalah kepemilikan atau mode pada direktori .ssh, bukan kuncinya.

Secara sengaja, agent tidak termasuk dalam grup sudo. Jika diperlukan paket sistem, instal paket tersebut. Keputusan ini menghilangkan sebagian besar kemungkinan perintah shell yang tidak semestinya merusak host.

Kebersihan SSH untuk server yang dibiarkan aktif

Autentikasi kata sandi pada mesin yang terus terhubung ke Internet publik sepanjang hari, serta menyimpan agent dan kode sumber Anda, merupakan risiko yang tidak perlu ditanggung. Nonaktifkan autentikasi tersebut. Pada Ubuntu 24.04 dan Debian 13, /etc/ssh/sshd_config menyertakan /etc/ssh/sshd_config.d/*.conf, jadi buat file tambahan alih-alih mengedit konfigurasi utama:

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

Validasi dan muat ulang konfigurasi. Biarkan sesi Anda saat ini tetap terbuka sambil menguji sesi baru dari terminal kedua:

sudo sshd -t && sudo systemctl restart ssh

Ada satu hal khusus pada Ubuntu 24.04: sshd diaktifkan melalui socket. Pengaturan autentikasi berlaku pada systemctl restart ssh, tetapi perubahan pada Port yang menangani koneksi juga memerlukan systemctl daemon-reload dan restart ssh.socket.

Berikutnya, konfigurasi firewall. Izinkan SSH sebelum mengaktifkan firewall, atau Anda akan terkunci di luar server:

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

Instal fail2ban dengan memahami manfaatnya: setelah autentikasi kata sandi dinonaktifkan, brute force tidak akan berhasil; fitur ini hanya mencegah percobaan yang gagal memenuhi journal Anda.

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

Terakhir, lakukan patch otomatis dengan sudo apt install unattended-upgrades dan sudo dpkg-reconfigure -plow unattended-upgrades. Perhatikan interaksinya dengan tmux: aktifkan Unattended-Upgrade::Automatic-Reboot dan pembaruan kernel akan me-reboot server, sehingga semua sesi ikut terputus. Biarkan fitur tersebut nonaktif dan lakukan reboot sesuai jadwal Anda sendiri, saat tidak ada proses yang sedang berjalan. Hal yang sama berlaku untuk upgrade rilis: memindahkan server dari Ubuntu 24.04 ke 26.04 akan me-restart sshd dan kernel, jadi lakukan dalam jadwal pemeliharaan saat tidak ada sesi tmux yang menjalankan pekerjaan penting.

Instal Node.js dan Claude Code di Ubuntu

Claude Code adalah CLI Node, jadi Anda memerlukan Node versi terbaru. Paket dari distro sering tertinggal; NodeSource biasanya digunakan di Ubuntu dan Debian, dan menyediakan repositori bertanda tangan (tanpa apt-key, karena alat tersebut sudah tidak digunakan):

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

Bagian yang sering keliru: instal CLI sebagai pengguna agent Anda, jangan pernah menggunakan sudo npm -g. Prefix global yang dimiliki root dapat menyebabkan error izin di kemudian hari dan meninggalkan file milik root di cache npm. Arahkan prefix npm ke 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

Export tersebut ditambahkan ke ~/.bashrc, bukan ~/.profile, dan harus ditempatkan di atas guard "If not running interactively, don't do anything" di dekat bagian awal file: tmux dapat memulai shell non-login, yang membaca ~/.bashrc dan melewati ~/.profile, sedangkan ~/.profile hanya dijalankan untuk shell login. Node per pengguna melalui version manager seperti nvm memberikan hasil yang sama; tujuannya adalah agar npm install -g tidak pernah memerlukan sudo. npm tetap berfungsi dengan baik. Anda juga dapat menggunakan skrip instalasi native dari Anthropic, yang saat ini menjadi metode default yang didokumentasikan. Periksa dokumentasi instalasi Anthropic sebelum menempelkan perintah, karena metode instalasi dapat berubah.

Jalankan claude di dalam repo untuk memulainya. Pada proses pertama, Anda akan diarahkan melalui autentikasi; server headless tidak memiliki browser, sehingga alurnya memberikan URL untuk dibuka di mesin Anda sendiri dan kode untuk dimasukkan kembali ke terminal. (API key di environment adalah opsi lainnya.) Apa pun metodenya, kredensial tersebut kini tersimpan di server. Selanjutnya, kita perlu membahas bagian yang sering dilewati.

Percakapan tentang cakupan dampak

Agen yang memiliki akses shell adalah shell. Agen tersebut dapat membaca apa pun yang dapat dibaca oleh pengguna yang menjalankannya dan mengirimkan perubahan ke mana pun pengguna tersebut memiliki akses push. Ini bukan kritik terhadap alat tersebut, melainkan definisinya. Karena itu, akun yang digunakan untuk menjalankan agen lebih penting daripada pengaturan individual apa pun.

  • Pengguna khusus tanpa hak istimewa. Jangan masukkan pengguna tersebut ke grup sudo, dan jangan gunakan direktori home yang sama dengan akun Anda.
  • Jangan simpan kredensial produksi di server. Jangan simpan ~/.aws/credentials yang berisi kunci produksi, jangan salin .env dari lingkungan produksi, dan jangan gunakan kata sandi database yang memiliki akses tulis ke data penting. Berikan kredensial staging atau kredensial hanya-baca kepada agen.
  • Token dengan cakupan terbatas. Gunakan token GitHub dengan cakupan terperinci yang dibatasi ke satu repositori; gunakan deploy key jika akses baca sudah mencukupi.

Claude Code menyediakan flag yang sepenuhnya melewati prompt izinnya. Di laptop atau proyek sementara, keputusan tersebut ada di tangan Anda. Namun, pada server yang menyimpan token, flag itu menghilangkan penghalang terakhir antara instruksi yang salah ditafsirkan dan git push --force. Prompt yang dilewati juga tidak hanya memiliki pilihan aktif atau nonaktif. Dengan mode otomatis menjadi default baru, Anda perlu mengetahui mode izin yang harus ditetapkan secara eksplisit pada server yang tidak Anda pantau. Perubahan yang sebenarnya dilakukan oleh flag tersebut serta cara membatasi agen yang berjalan dengannya, mulai dari sandbox bawaan hingga VPS sekali pakai, dibahas dalam menjalankan Claude Code dengan aman di server.

Deploy key vs penerusan SSH agent

Anda mungkin tergoda untuk ssh -A agar git dapat menggunakan key di laptop Anda. Pahami hak akses yang diberikan: penerusan agent mengekspos socket SSH agent lokal Anda kepada proses yang berjalan sebagai pengguna tersebut di server. Apa pun yang berjalan sebagai agent, termasuk agen tersebut, dapat meminta key Anda menandatangani autentikasi untuk host mana pun yang dapat dijangkaunya, selama Anda tetap terhubung. Hak akses ini jauh lebih besar daripada sekadar "mengizinkan git melakukan pull pada repositori ini".

Buat key di server sebagai gantinya, daftarkan key tersebut sebagai deploy key khusus repositori (berikan akses tulis hanya jika agen perlu melakukan push), lalu tetapkan identitas git agar commit dari server dapat dikenali:

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"

Alur kerja tmux

Instal tmux (sudo apt install tmux), lalu buat konfigurasi minimal ~/.tmux.conf:

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

Empat perintah ini mencakup penggunaan sehari-hari:

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 adalah perintah yang perlu diingat. Perintah ini menyambungkan ke sesi jika sesi tersebut sudah ada dan membuat sesi baru jika belum ada. Dengan demikian, satu perintah dapat digunakan untuk memulai pekerjaan dan melanjutkannya setelah koneksi terputus. Buat alias untuk perintah ini. Di dalam sesi, Ctrl-b c membuka window, Ctrl-b n dan Ctrl-b p berpindah antar-window, sedangkan Ctrl-b [ masuk ke mode salin untuk menggulir ke bagian sebelumnya (q untuk keluar).

Satu hal yang perlu diketahui tentang sesi yang tidak pernah Anda hentikan: agent mengirim ulang seluruh percakapan pada setiap giliran. Karena itu, baca apa saja yang menghabiskan token dalam sesi Claude Code yang berjalan lama sebelum membiarkan sesi tetap berjalan selama seminggu.

Mode kegagalan

"Sesi saya hilang." tmux ls menampilkan no server running on /tmp/tmux-1000/default. Ini hampir selalu berarti proses tersebut tidak pernah berjalan di dalam tmux, Anda masuk melalui SSH, menjalankan claude secara langsung, lalu koneksi terputus dan menghentikan proses itu. Tidak ada yang dapat dipulihkan. Kebiasaan yang mencegahnya: tmux new -A -s <project> adalah perintah pertama setelah setiap login.

Panel menyusut menjadi kotak kecil. tmux menyesuaikan ukuran sesi dengan client terlampir yang paling kecil, sehingga client lama yang masih terhubung dari mesin lain mempersempit tampilan. Putuskan client lain secara paksa saat Anda melakukan attach: tmux attach -d -t claude.

Build menampilkan Killed. Hanya satu kata, tanpa stack trace. Konfirmasikan dengan sudo dmesg -T | grep -i -E 'out of memory|killed process'; kernel OOM killer memilih proses terbesar. Dari Node, Anda mungkin justru melihat FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory. Perbaikan, secara berurutan: tambahkan swap (di atas), batasi paralelisme pengujian dan compiler, naikkan heap Node dengan NODE_OPTIONS=--max-old-space-size=..., atau tingkatkan ukuran VPS. OOM killer juga dapat memilih tmux server, bukan build, sehingga sesi Anda ikut terhenti; jika systemd-oomd sedang berjalan, proses itu dapat menghentikan seluruh user slice dengan efek yang sama.

npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Instalasi global ke prefix yang dimiliki root. Gunakan prefix ~/.npm-global di atas. Jika sebelumnya Anda pernah menjalankan sudo npm, Anda mungkin juga melihat Your cache folder contains root-owned files; perbaiki dengan sudo chown -R $(id -u):$(id -g) ~/.npm.

claude: command not found, tetapi hanya kadang-kadang. Export PATH Anda berada di ~/.bashrc, di bawah guard "If not running interactively, don't do anything", sehingga shell non-interaktif melewatinya. Pindahkan export tersebut ke atas guard itu dan simpan di ~/.bashrc, bukan ~/.profile: tmux dapat memulai shell non-login, yang membaca ~/.bashrc dan tidak pernah memproses ~/.profile.

Warna kacau setelah attach. Ini disebabkan ketidaksesuaian TERM; baris default-terminal di atas adalah perbaikannya.

Sesi hilang setelah reboot. Ini bukan bug: tmux server adalah sebuah proses, dan reboot menghentikannya. Periksa uptime.

Apa yang mulai bermasalah seiring pertumbuhan

Lebih banyak proyek. Gunakan satu sesi tmux untuk setiap repo dan beri nama sesuai repo tersebut; tmux ls kemudian menjadi dasbor Anda. Jika disiplin penamaan diabaikan, Anda akan mendapatkan sesi 0, 1, 2. Setelah beberapa sesi berjalan secara bersamaan, sesi-sesi tersebut tidak harus bekerja secara terisolasi, karena satu sesi dapat mengirim pesan ke sesi lain pada mesin yang sama. Ini berguna ketika agent yang sedang melakukan refactor panjang ingin meminta agent lain menjalankan pengujian. Port juga dapat bertambah tanpa terkendali. Jika enam repo sama-sama menginginkan :3000, hentikan penetapan port secara manual dan biarkan reverse proxy Traefik merutekan beberapa aplikasi di bawah Docker Compose berdasarkan hostname.

Lebih banyak pengguna. Socket tmux berlaku per pengguna. Karena itu, dua developer pada mesin yang sama masing-masing memiliki server tmux sendiri dan tidak dapat melihat sesi pengguna lain. Berbagi satu sesi melalui socket bersama berarti semua orang mengetik ke shell yang sama sebagai pengguna Unix yang sama, beserta konsekuensi audit dan izin yang ditimbulkannya. Memisahkan pengguna adalah pilihan yang sederhana dan benar.

Pekerjaan tanpa pengawasan. tmux ditujukan untuk sesi interaktif yang Anda lampirkan. Pekerjaan terjadwal yang berjalan tanpa pengawasan sebaiknya ditempatkan dalam unit dan timer systemd. Dengan begitu, pekerjaan tersebut memperoleh logging, kebijakan restart, dan kemampuan bertahan setelah boot secara langsung. Menggunakan tmux untuk menjalankan pekerjaan seperti cron menunjukkan bahwa pekerjaan tersebut seharusnya dijalankan sebagai service.

Satu catatan terakhir: bind dev server yang dijalankan agent ke 127.0.0.1, bukan 0.0.0.0, lalu akses melalui tunnel SSH (ssh -L 3000:127.0.0.1:3000 agent@your-server), bukan dengan membuka port di ufw. Jika Anda sudah meneruskan sekitar enam port, atau ponsel dan laptop sama-sama perlu mengakses preview yang sama, tempatkan VPN WireGuard yang di-host sendiri pada VPS di depannya. Dengan demikian, dev server melakukan bind ke interface privat, dan ufw tetap menolak semua koneksi dari interface publik. Firewall hanya membantu jika Anda berhenti membuat lubang di dalamnya.

Claude Code bukan satu-satunya pilihan: menjalankan agent AI pemrograman pada VPS juga mencakup Aider dan Goose.

FAQ

Apakah Claude Code tetap berjalan setelah koneksi SSH terputus?

Hanya jika Anda menjalankannya di dalam tmux. Proses yang langsung dijalankan dari shell SSH merupakan child dari shell tersebut dan berhenti bersama pty ketika koneksi terputus. Di dalam tmux, shell menjadi milik server tmux yang detached, sehingga agent tetap bekerja di tengah tugas dan tmux attach mengembalikan Anda ke scrollback yang sama. Jadikan tmux new -A -s <project> perintah pertama setiap kali login agar masalah ini tidak terjadi lagi.

Apakah CLI sebaiknya saya instal dengan sudo npm install -g?

Tidak. Prefix global yang dimiliki root akan menyebabkan error EACCES pada instalasi berikutnya dan membuat file di npm cache dimiliki root. Atur prefix npm ke ~/.npm-global (atau gunakan version manager seperti nvm), lakukan instalasi sebagai user non-privileged agent, lalu export ~/.npm-global/bin ke PATH dari ~/.bashrc, di atas guard interaktif. Jika Anda sudah menjalankan sudo npm, perbaiki cache dengan sudo chown -R $(id -u):$(id -g) ~/.npm.

Apakah penerusan agent ssh -A aman pada server yang menjalankan agent?

Penerusan tersebut memberikan akses yang jauh lebih besar daripada yang diperlukan oleh tugas. Forwarding mengekspos socket SSH agent lokal Anda ke setiap proses yang berjalan sebagai user tersebut. Artinya, apa pun yang berjalan di server dapat meminta key Anda menandatangani koneksi ke host mana pun yang dapat dijangkaunya selama koneksi Anda tetap terpasang. Buat key ed25519 di server dan daftarkan sebagai deploy key per repository. Berikan akses tulis hanya jika agent memang harus melakukan push.

Mengapa build saya hanya menampilkan Killed?

Satu kata tanpa stack trace menunjukkan OOM killer pada kernel. Konfirmasikan dengan sudo dmesg -T | grep -i -E 'out of memory|killed process'; dari Node, Anda mungkin melihat JavaScript heap out of memory sebagai gantinya. Terapkan perbaikan secara berurutan: tambahkan swapfile, batasi paralelisme pengujian dan compiler, naikkan NODE_OPTIONS=--max-old-space-size=..., lalu tingkatkan ukuran VPS. Perhatikan bahwa OOM killer dapat memilih server tmux, bukan proses build, sehingga seluruh sesi Anda ikut terputus.

tmux atau service systemd?

tmux cocok untuk sesi interaktif yang Anda sambungkan, pantau, dan gunakan untuk mengetik. Ini tepat untuk sesi agent. Pekerjaan terjadwal yang tidak dipantau siapa pun sebaiknya menggunakan unit dan timer systemd. Logging, kebijakan restart, dan kelangsungan saat boot tersedia secara bawaan. Jika Anda menggunakan tmux untuk menjalankan pekerjaan seperti cron, pekerjaan tersebut seharusnya menjadi service.