SSD Nodes Learn
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-07-24

Claude Code VPS tmux ile nasıl çalıştırılır?

SSH bağlantısı kesildiğinde Claude Code oturumunun kapanmasını önlemek için tmux kullanımı ve Linux VPS kurulum adımları hakkında teknik rehber.

Sorun laptop kapağıdır, CLI değil

Claude Code, laptop kapağı kapatılana kadar sorunsuz çalışır: SSH oturumu sonlanır, shell SIGHUP sinyali alır ve bir test çalışmasının üçüncü dakikasında agent da oturumla birlikte kapanır. CLI'ı asla uyku moduna geçmeyen bir makinede ve süreçleri SSH oturumunuzun alt süreci olmayan bir terminal multiplexer içinde çalıştırın. Temel yöntem budur; yükü taşıyan kısım kurulum değil, tmux'tır.

Bu sayfa, üzerinde agent'ların çalışmaya bırakıldığı bir makinenin işletilmesi hakkındadır. Eğer açık bırakabileceğiniz bir Linux sunucunuz yoksa, bu bilgilerin hiçbiri geçerli değildir. Tek gerçek ön koşul budur.

tmux gerçekte ne yapar

SSH ile bağlandığınızda, sshd bir shell başlatır ve buna bir pseudo-terminal atar; bu shell üzerinden başlatılan her şey onun alt sürecidir (child process). Bağlantı kesildiğinde kernel pty yapısını sonlandırır, shell SIGHUP sinyali alır ve sırasıyla alt süreçlerini kapatır. Uzun süren foreground süreçleri ölür.

tmux sahiplik yapısını tersine çevirir. Yazdığınız tmux komutu, terminalinizden bağımsız çalışan bir tmux server ile unix socket üzerinden iletişim kuran ince bir istemcidir (thin client). Bir oturum içindeki shell'ler sshd'in değil, bu server'ın alt süreçleridir. SSH bağlantısını kestiğinizde istemci kapanır; ancak server, oturum ve görev ortasındaki agent çalışmaya devam eder. Yeniden bağlanıp tmux attach komutunu kullandığınızda, aynı scrollback geçmişine sahip aynı shell içine geri dönersiniz. nohup de bağlantı kesilmesine karşı dayanıklıdır ancak size geri dönüş yolu sağlamaz; arka plandaki bir TUI'ye yeniden bağlanamazsınız. Claude Code etkileşimlidir; tmux (veya screen) doğru araçtır.

Makine boyutlandırma

CLI bir Node sürecidir; makineyi dolduran unsur CLI değildir. Makineyi, sizin adınıza çalışan süreçler doldurur: bir build işlemi, tam bir test paketi, tsc, bir dil sunucusu veya Docker üzerinde çalışan bir veritabanı. Boyutlandırma yapılırken CLI değil, toolchain dikkate alınmalıdır. Swap alanı hiç kullanılmayacak olsa bile eklenmelidir; bu, sert bir OOM kill işlemi yerine yavaş bir build süreci sağlar:

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

Disk kullanımını da takip edin: repolar, node_modules ve Docker imajları hızla birikir. Eğer toolchain konteynerların ötesine geçip tam sanal makinelerle (bir KVM guest veya yerel bir Kubernetes node gibi) çalışıyorsa, taahhüt vermeden önce planın CPU sanallaştırma uzantılarını desteklediğinden emin olun; çünkü VPS üzerinde iç içe sanallaştırma çalıştırmak, sağlayıcının sizin için etkinleştirdiği bir özelliktir, misafir işletim sistemi içerisinden açabileceğiniz bir özellik değildir.

İlk olarak root olmayan bir kullanıcı

Kendi home dizinine sahip özel bir kullanıcı oluşturun ve public key dosyanızı ilgili yere yerleştirin:

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 bilerek sudo grubunda değildir. Bir sistem paketi gerekirse, bu paket yüklenir. Bu karar, rastgele bir shell komutunun host sistemine zarar verme olasılığını büyük ölçüde ortadan kaldırır.

SSH hygiene for a box you leave running

Password auth on a machine that sits on the public internet all day, holding an agent and your source code, is not a risk worth carrying. Turn it off. On Ubuntu 24.04 and Debian 13, /etc/ssh/sshd_config includes /etc/ssh/sshd_config.d/*.conf, so drop a file in rather than editing the main config:

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

Validate and reload — keeping your current session open while you test a new one from a second terminal:

sudo sshd -t && sudo systemctl restart ssh

A nuance on Ubuntu 24.04: sshd is socket-activated. Auth settings apply on systemctl restart ssh, but a change to the listening Port also needs systemctl daemon-reload and a restart of ssh.socket.

Then the firewall. Allow SSH before you enable it, or you lock yourself out:

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

Install fail2ban with a clear head about what it buys you: once password auth is off, brute force cannot succeed anyway — it keeps failed attempts out of your journal.

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

Finally, patch automatically with sudo apt install unattended-upgrades and sudo dpkg-reconfigure -plow unattended-upgrades. Note the interaction with tmux: switch on Unattended-Upgrade::Automatic-Reboot and a kernel update reboots the box, taking every session with it. Leave it off and reboot on your own schedule, when nothing is mid-run.

Ubuntu Üzerine Node.js ve Claude Code Kurulumu

Claude Code bir Node CLI aracıdır, bu nedenle güncel bir Node sürümüne ihtiyaç vardır. Dağıtım paketleri genellikle geriden gelir; Ubuntu ve Debian üzerinde yaygın yöntem NodeSource kullanımıdır ve imzalı bir depo sunar (apt-key mevcut değildir — bu araç kaldırılmıştır):

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

Yaygın yapılan hata: CLI aracını agent kullanıcısı olarak kurun, asla sudo npm -g ile kurmayın. Root sahipliğinde bir global prefix, daha sonra yetki hatalarına yol açar ve npm önbelleğinde root sahipliğinde dosyalar bırakır. npm prefix yolunu önce kullanıcının home dizinine yönlendirin:

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 işlemi ~/.profile yerine ~/.bashrc dosyasına eklenmelidir. Bu satır, dosyanın başındaki "If not running interactively, don't do anything" korumasının üstüne yazılmalıdır: tmux, ~/.bashrc dosyasını okuyan ancak ~/.profile dosyasını atlayan non-login shell'ler başlatabilir; ~/.profile yalnızca login shell'ler için çalışır. nvm gibi bir versiyon yöneticisi aracılığıyla kullanıcı bazlı Node kullanımı da aynı sonucu verir; her iki yöntemin amacı da npm install -g'ın sudo gerektirmemesidir. npm sorunsuz çalışmaya devam eder veya şu anki varsayılan yöntem olan Anthropic'in yerel kurulum betiğini kullanabilirsiniz. Komutları yapıştırmadan önce Anthropic'in kurulum dokümanlarını kontrol edin; kurulum yöntemleri değişebilir.

Başlatmak için bir repo içinde claude komutunu çalıştırın. İlk çalıştırma sizi kimlik doğrulama adımları boyunca yönlendirir; headless bir sunucuda tarayıcı bulunmaz, bu nedenle akış size kendi makinenizde açmanız için bir URL ve terminale geri getirmeniz için bir kod sunar. (Alternatif bir yol olarak ortam değişkenlerinde bir API key kullanılabilir.) Her iki durumda da kimlik bilgisi artık sunucuda saklanır — bu da kullanıcıların genellikle atladığı bölüme gelmemizi sağlar.

Blast radius kavramı

Shell erişimine sahip bir agent, bir shell'dir. Çalıştığı kullanıcının okuyabildiği her şeyi okuyabilir ve o kullanıcının erişebildiği her yere veri gönderebilir. Bu bir araç eleştirisi değil, aracın tanımıdır; bu nedenle agent'ın çalıştığı hesabın önemi, tüm bireysel ayarlardan daha büyüktür.

  • Özel, yetkisiz kullanıcı. sudo grubu olmamalı, kendi hesabınızla paylaşılan bir home directory bulunmamalıdır.
  • Makinede production kimlik bilgileri bulunmamalıdır. Prod anahtarlarını tutan bir ~/.aws/credentials, production ortamından kopyalanmış bir .env veya kritik verilere yazma yetkisi olan bir veritabanı şifresi bulunmamalıdır. Agent'a staging veya salt okunur (read-only) bir kimlik bilgisi verin.
  • Kapsamlı (scoped) tokenlar. Tek bir repository ile sınırlandırılmış hassas bir GitHub token'ı; okuma erişiminin yeterli olduğu durumlarda bir deploy key.

Claude Code, izin isteme adımlarını tamamen atlayan bir flag ile birlikte gelir. Bir dizüstü bilgisayarda veya geçici bir projede bu karar kullanıcıya aittir. Ancak token barındıran bir sunucuda, bu flag yanlış okunan bir talimat ile git push --force arasındaki son engeli de kaldırır. Flag'in gerçekte neyi değiştirdiği ve yerleşik sandbox yapısından geçici bir VPS'e kadar, bu flag ile çalışan bir agent'ın nasıl sınırlandırılacağı sunucuda Claude Code güvenli çalıştırma konusunda ele alınmıştır.

Deploy key vs SSH agent forwarding

Git'in dizüstü bilgisayarınızdaki anahtarı kullanabilmesi için ssh -A yapmak cazip gelebilir. Bunun neye izin verdiğini anlayın: agent forwarding, yerel SSH agent socket'inizi makinede o kullanıcı olarak çalışan süreçlere açar. Agent dahil olmak üzere agent olarak çalışan her şey, siz bağlı kaldığınız sürece ulaşabildiği herhangi bir host için anahtarınızın imzalama yapmasını isteyebilir. Bu, "sadece bu repository'yi git pull yapmasına izin ver" mantığından çok daha fazlasıdır.

Bunun yerine anahtarı sunucu üzerinde oluşturun, her repository için bir deploy key olarak kaydedin (eğer agent push yapmaya ihtiyaç duyuyorsa sadece yazma yetkisi verin) ve makineden yapılan commit'lerin tanınabilir olması için bir git kimliği ayarlayın:

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 iş akışı

sudo apt install tmux kurulumunu yapın, ardından minimal bir ~/.tmux.conf yapılandırması oluşturun:

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

Günlük kullanım için dört komut yeterlidir:

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 komutu ezberlenmelidir; oturum mevcutsa oturuma bağlanır, mevcut değilse yeni bir oturum oluşturur. Bu komut hem işe başlarken hem de bağlantı kesildikten sonra devam ederken kullanılır. Bu komuta bir alias atayın. Bir oturum içerisindeyken Ctrl-b c yeni bir pencere açar, Ctrl-b n ve Ctrl-b p pencereler arasında geçiş yapar, Ctrl-b [ ise geçmişe dönüp okuma yapmak için kopyalama moduna (copy mode) girer (q moddan çıkar).

Hiç kapatılmayan oturumlar hakkında bilinmesi gereken bir husus vardır: agent, her adımda tüm konuşmayı yeniden gönderir. Bu nedenle, bir oturumu bir hafta boyunca açık bırakmadan önce uzun süreli bir Claude Code oturumunun token harcamaları konusunu okuyun.

Hata modları

"Oturumum kayboldu." tmux ls, no server running on /tmp/tmux-1000/default çıktısını verir. Bu durum neredeyse her zaman sürecin tmux içinde olmadığını gösterir; SSH ile bağlandınız, claude komutunu doğrudan çalıştırdınız ve bağlantının kesilmesi süreci sonlandırdı. Kurtarılacak bir veri yoktur. Bunu önlemek için alışkanlık: Her girişte çalıştırılacak ilk komut tmux new -A -s <project> olmalıdır.

Panel çok küçük bir kutu haline geliyor. tmux, bir oturumu bağlı olan en küçük istemci boyutuna göre ayarlar; bu nedenle başka bir makineden bağlı kalan eski bir istemci ekranı sıkıştırır. Bağlanırken diğerlerini şu komutla bağlantıdan düşürün: tmux attach -d -t claude.

Bir derleme Killed çıktısı veriyor. Tek bir kelime, stack trace yok. sudo dmesg -T | grep -i -E 'out of memory|killed process' ile kontrol edin; kernel OOM killer en büyük süreci seçmiştir. Node tarafında bunun yerine FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory görebilirsiniz. Çözümler (sırasıyla): swap ekleyin (yukarıda), test ve derleyici paralelliğini sınırlayın, Node heap boyutunu NODE_OPTIONS=--max-old-space-size=... ile artırın veya VPS kapasitesini yükseltin. OOM killer, derleme yerine tmux server sürecini de seçebilir ve oturumunuzu beraberinde sonlandırabilir; eğer systemd-oomd çalışıyorsa, aynı etkiyle tüm bir user slice'ı öldürebilir.

npm error code EACCES / permission denied, mkdir '/usr/lib/node_modules/...'. Root sahipliğindeki bir prefix içine yapılan global kurulum. Yukarıdaki ~/.npm-global prefix'ini kullanın. Eğer bir noktada sudo npm çalıştırdıysanız Your cache folder contains root-owned files hatasını da görebilirsiniz; sudo chown -R $(id -u):$(id -g) ~/.npm ile onarın.

claude: command not found — ancak sadece bazen. PATH export işleminiz, ~/.bashrc içinde "If not running interactively, don't do anything" korumasının altında yer alıyor; bu nedenle non-interactive shell'ler bu satırı atlar. Export işlemini bu korumanın üzerine taşıyın ve ~/.profile yerine ~/.bashrc içinde tutun: tmux, ~/.bashrc dosyasını okuyan ancak ~/.profile dosyasına hiç dokunmayan non-login shell'ler başlatabilir.

Bağlandıktan sonra bozuk renkler. TERM uyumsuzluğu — çözüm yukarıdaki default-terminal satırıdır.

Yeniden başlatma sonrası oturumlar kayboluyor. Bu bir hata değildir: tmux server bir süreçtir ve yeniden başlatma bu süreci sonlandırır. uptime kontrol edin.

Ölçeklendirme ile ortaya çıkan sorunlar

Daha fazla proje. Her repo için o reponun adını taşıyan bir tmux oturumu oluşturulmalıdır; bu durumda tmux ls bir kontrol paneli işlevi görür. İsimlendirme disiplinine uyulmazsa 0, 1 ve 2 gibi oturumlar oluşur. Portlar da benzer şekilde karmaşıklaşır — altı farklı reponun aynı anda :3000 portunu kullanmak istemesi, manuel atamayı bırakıp Docker Compose altında birden fazla uygulamayı Traefik reverse proxy ile yönlendirme yöntemine geçilmesi gereken noktadır.

Daha fazla kullanıcı. tmux soketleri kullanıcı bazlıdır; bu nedenle aynı makinedeki iki geliştirici kendi tmux sunucusuna sahip olur ve birbirlerinin oturumlarını göremezler. Paylaşılan bir soket üzerinden tek bir oturum paylaşmak, herkesin aynı Unix kullanıcısı olarak aynı kabukta işlem yapması anlamına gelir; bu durum denetim ve yetkilendirme sorunlarına yol açar. Doğru ve standart çözüm, kullanıcıları ayırmaktır.

Otomatik yürütülen işler. tmux, bağlanılan etkileşimli oturumlar içindir. Kimse izlemiyorken belirli bir takvimle çalışan işler; loglama, yeniden başlatma politikası ve sistem açılışında çalışma özelliklerine sahip olan systemd unit ve timer yapısına dahil edilmelidir. Cron benzeri bir iş için tmux kullanma isteği, o işin bir servis olması gerektiğinin göstergesidir.

Son bir not: agent tarafından başlatılan dev sunucuları 0.0.0.0 yerine 127.0.0.1 adresine bağlayın ve bunlara ufw üzerinden port açmak yerine bir SSH tüneli (ssh -L 3000:127.0.0.1:3000 agent@your-server) ile erişin. Yarım düzine portu yönlendirmeye başladığınızda veya bir telefon ile bir dizüstü bilgisayar aynı önizlemeye erişmek istediğinde, bunların önüne VPS üzerinde self-hosted WireGuard VPN kurun: dev sunucuları özel bir arayüze bağlanır ve ufw, genel arayüzden gelen tüm istekleri reddetmeye devam eder. Güvenlik duvarı, sadece içinde boşluklar bırakmayı bıraktığınızda işe yarar.

Claude Code tek seçenek değildir: VPS üzerinde bir kodlama yapay zeka ajanı çalıştırmak Aider ve Goose seçeneklerini de içerir.

FAQ

SSH bağlantısı koptuğunda Claude Code çalışmaya devam eder mi?

Yalnızca tmux içinde başlatıldıysa devam eder. Doğrudan SSH kabuğu üzerinden başlatılan bir süreç, o kabuğun alt sürecidir ve bağlantı koptuğunda pty ile birlikte sonlanır. tmux içinde kabuk, ayrılmış (detached) tmux sunucusuna aittir; bu nedenle ajan görev ortasında çalışmaya devam eder ve tmux attach sizi aynı geçmişe (scrollback) geri döndürür. Her oturum açışınızdan sonra tmux new -A -s <project> komutunu çalıştırırsanız sorun çözülür.

CLI, sudo npm install -g ile mi kurulmalıdır?

Hayır. Root yetkili global bir prefix, sonraki kurulumlarda EACCES hatalarına ve npm önbelleğinde root yetkili dosyalara neden olur. npm prefix değerini ~/.npm-global olarak ayarlayın (veya nvm gibi bir versiyon yöneticisi kullanın), yetkisiz agent kullanıcısı olarak kurulum yapın ve etkileşimli koruma üzerinde, ~/.bashrc üzerinden PATH üzerine ~/.npm-global/bin değerini export edin. Eğer daha önce sudo npm komutunu çalıştırdıysanız, önbelleği sudo chown -R $(id -u):$(id -g) ~/.npm ile onarın.

Bir ajan çalıştıran bir makinede ssh -A ajan yönlendirmesi güvenli midir?

Bu işlem, işin gereksinim duyduğundan çok daha fazla yetki verir. Yönlendirme, yerel SSH ajan soketinizi o kullanıcı olarak çalışan her sürece açar; bu nedenle bağlantı sürdüğü sürece makinedeki her şey, erişebildiği herhangi bir anahtar için anahtarınızı imzalama talebinde bulunabilir. Sunucuda bir ed25519 anahtarı oluşturun ve bunu, yalnızca ajan gerçekten push yapması gerekiyorsa yazma yetkisi olacak şekilde, depo başına (per-repository) bir deploy key olarak kaydedin.

Build işlemi neden sadece Killed yazdırıyor?

Yığın izi (stack trace) olmadan tek bir kelime görülüyorsa, bu kernel OOM killer'dır. Bunu sudo dmesg -T | grep -i -E 'out of memory|killed process' ile doğrulayın; Node üzerinden JavaScript heap out of memory hatası görebilirsiniz. Çözümleri sırayla uygulayın: bir swap dosyası ekleyin, test ve derleyici paralelliğini sınırlayın, NODE_OPTIONS=--max-old-space-size=... değerini artırın ve ardından VPS boyutunu yükseltin. OOM killer'ın build işlemi yerine tmux sunucusunu seçebileceğini ve tüm oturumunuzu kapatabileceğini unutmayın.

tmux mı yoksa systemd servisi mi?

tmux; bağlandığınız, izlediğiniz ve içine komut yazdığınız etkileşimli oturumlar için uygundur; bir ajan oturumu tam olarak budur. Kimsenin izlemediği ve belirli bir program dahilinde çalışan işler ise; günlük tutma (logging), yeniden başlatma politikası ve açılışta çalışma (boot survival) özelliklerinin hazır geldiği bir systemd ünitesi ve zamanlayıcısı (timer) içinde olmalıdır. Eğer cron benzeri bir işi çalıştırmak için tmux kullanmaya çalışıyorsanız, o iş bir servis olmalıdır.