Telefondan Claude Code: Sıfırdan Kurulum Rehberi

iPhone'dan Apple Silicon bir Mac'teki Claude Code'a giden zincirin tamamı — Termius, Tailscale, sertleştirilmiş OpenSSH, mosh, tmux — kopyala-yapıştır, her adımın kontrolü ve çözümüyle.

Bu rehber, iPhone'dan Mac'teki Claude Code'u kullanmanı sağlayan zinciri sıfırdan kurar: Termius → Tailscale → OpenSSH → mosh → tmux → Claude Code. Neden böyle kurduğumu ve yolda düştüğüm tuzakları Cebimdeki Claude Code yazısında anlattım; burası yalnızca tarif. Her adımda ne yaptığın, komutlar, nasıl kontrol edeceğin ve ters giderse ne olduğu var. Hiçbir repoya ihtiyacın yok, her şey kopyala-yapıştır.

kuracağın zincir · sayılar adım numarası
iPhoneMactailnet · Tailscale · 2SSH · anahtarmosh · UDPbaşlatırtareddedilirTermiusSSH istemcisi · 6, 9sshdUzaktan Giriş · 7–8mosh-serverUDP · 3tmuxoturum: main · 4–5Claude Codeclaude · 10Kafedeki biritailnet dışıOturum2Kapı1İstemci2Ajan1

0. Başlamadan önce

Menü adları İngilizce arayüzden; Türkçe macOS'ta karşılıklarını bulursun.

1. Paketler

tmux oturumu Mac'te yaşatır, mosh bağlantıyı kopmaz yapar, Tailscale de telefonla Mac'i aynı özel ağa koyar.

brew install tmux mosh
brew install --cask tailscale-app

Kontrol: tmux -V ve mosh --version birer sürüm yazıyor.

2. Tailscale

Tailscale, cihazlarını nerede olurlarsa olsunlar aynı yerel ağdaymış gibi bağlayan bir VPN; bu özel ağa tailnet deniyor. Router'da port açmak gerekmez.

Uygulamanın komut satırı aracı PATH'te değil, tam yoluyla çağır:

/Applications/Tailscale.app/Contents/MacOS/Tailscale status
/Applications/Tailscale.app/Contents/MacOS/Tailscale ping <telefon>

İstersen ~/.zshrc'ye bir kısayol ekle: alias tailscale=/Applications/Tailscale.app/Contents/MacOS/Tailscale.

Termius'a yazacağın adres Mac'in tam MagicDNS adı. MagicDNS, Tailscale'in her cihaza verdiği <mac>.<tailnet>.ts.net biçimindeki isim:

/Applications/Tailscale.app/Contents/MacOS/Tailscale status --json \
  | python3 -c 'import json,sys; print(json.load(sys.stdin)["Self"]["DNSName"].rstrip("."))'

Kontrol: status iki cihazı da listeliyor, ping cevap veriyor. Cevapta via <ip>:<port> varsa bağlantı doğrudan, via DERP(...) varsa Tailscale'in aktarma sunucuları (DERP) üzerinden; ikisi de çalışır.

Ters giderse: tailscale: command not found → tam yolu kullan. Ping cevap vermiyorsa iki cihazın da aynı hesapla girdiğini ve iPhone'da VPN'in açık olduğunu kontrol et.

3. SSH oturumlarında PATH

Rehberin en sinsi adımı. mosh, mosh-server'ı etkileşimsiz bir SSH oturumunda başlatır; o oturum zsh ayarlarından yalnızca ~/.zshenv'i okur ve Homebrew'un /opt/homebrew/bin'i orada PATH'te değildir. Sonuç: Termius mosh-server not found der.

cat >> ~/.zshenv <<'EOF'
typeset -U path
path=(/opt/homebrew/bin /opt/homebrew/sbin $HOME/.local/bin $path)
export LANG="${LANG:-en_US.UTF-8}"
EOF

LANG satırı da şart: mosh-server UTF-8 bir locale olmadan çalışmayı reddeder. 'EOF' tırnaklı, yani $HOME ve $path dosyaya olduğu gibi yazılır ve her oturum açılışında çözülür. ~/.local/bin de bir sonraki adımdaki script için.

Kontrol: temiz, etkileşimsiz bir kabuk mosh-server'ı buluyor mu:

env -i HOME="$HOME" /bin/zsh -c 'command -v mosh-server'
# /opt/homebrew/bin/mosh-server

Ters giderse: Çıktı boşsa satırlar ~/.zshenv'e değil başka bir dosyaya gitmiştir (~/.zshrc etkileşimsiz oturumda okunmaz).

4. Tek komutla oturuma bağlan: ta

tmux, bağlantıdan bağımsız olarak Mac'te yaşayan bir terminal oturumu. ta, main adlı oturuma bağlanır, yoksa oluşturur (-A bunu yapar); telefondan her bağlandığında aynı ekrana düşersin.

mkdir -p ~/.local/bin
cat > ~/.local/bin/ta <<'EOF'
#!/bin/sh
exec tmux new-session -A -s main
EOF
chmod +x ~/.local/bin/ta

Kontrol: Yeni bir terminal aç, ta yaz: altta tmux'un yeşil durum çubuğu çıkar. Ctrl-b sonra d ile ayrıl; oturum arkada yaşamaya devam eder.

Ters giderse: ta: command not found → ~/.local/bin PATH'te değil; bkz. adım 3.

5. Telefon için tmux ayarları

cat >> ~/.tmux.conf <<'EOF'
set -g mouse on
setw -g aggressive-resize on
set -g history-limit 50000
set -s escape-time 10
set -g default-terminal "tmux-256color"
set -g set-clipboard on
EOF

Kontrol: Aşağıdaki komut hiçbir şey yazmıyorsa ayar dosyası hatasız:

tmux -L check -f /dev/null new -d \; source-file ~/.tmux.conf \; kill-server

Çalışan bir tmux oturumun varsa ayarları tmux source-file ~/.tmux.conf ile uygula.

Ters giderse: invalid option: … → o satırda yazım hatası var.

6. SSH anahtarı

Şifre yerine anahtar çifti: özel anahtar telefonda kalır, açık (public) anahtar Mac'e gider, Mac yalnızca o özel anahtarı taşıyanı içeri alır.

Termius'ta Keychain → + → Generate Key, tür ED25519, bir isim ver. Anahtarı açıp public key'i kopyala (Universal Clipboard ile doğrudan Mac'e gelir). Mac'te:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo 'ssh-ed25519 AAAA…anahtarın-tamamı… iphone' >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Anahtarı tek tırnağın içine düz metin olarak yapıştır ve sonuna iphone gibi bir cihaz adı ekle; telefon kaybolursa sileceğin satırı bu gösterir.

Kontrol:

ssh-keygen -l -f ~/.ssh/authorized_keys
# 256 SHA256:… iphone (ED25519)

Ters giderse: is not a public key file → cat ~/.ssh/authorized_keys ile bak, bozuk satırı nano ile düzelt. sshd, izinleri gevşek bir ~/.ssh ya da authorized_keys'i yok sayar; iki chmod'u atlama.

7. sshd'yi sertleştir

macOS'ta SSH sunucusu, OpenSSH'ın sshd servisi, System Settings'te Remote Login diye geçer. Onu açmadan önce kilitliyoruz: yalnızca anahtarla, yalnızca senin kullanıcınla, yalnızca tailnet'ten.

U=$(whoami)
sudo tee /etc/ssh/sshd_config.d/010-remote.conf >/dev/null <<EOF
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
AuthenticationMethods publickey
PermitEmptyPasswords no
PermitRootLogin no
AllowUsers $U@100.64.0.0/10 $U@fd7a:115c:a1e0::/48 $U@127.0.0.1 $U@::1
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 30
ClientAliveCountMax 4
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding local
EOF
sudo chmod 644 /etc/ssh/sshd_config.d/010-remote.conf

Bu sefer EOF tırnaksız: $U yazılırken senin kullanıcı adına dönüşsün diye. Dosyada $U görürsen tırnak kaçmıştır.

Hiç Remote Login açılmamış bir Mac'te host key, yani sunucunun kimliğini kanıtlayan anahtar yoktur ve test no hostkeys available der. Eksikleri üret (var olanlara dokunmaz), sonra test et:

sudo ssh-keygen -A
sudo /usr/sbin/sshd -t

Kontrol: sshd -t hiçbir şey yazmıyorsa sözdizimi doğru. Etkin değerlere bak:

sudo /usr/sbin/sshd -T | grep -iE '^(passwordauthentication|kbdinteractiveauthentication|permitrootlogin|authenticationmethods|allowusers)'
# permitrootlogin no
# passwordauthentication no
# kbdinteractiveauthentication no
# allowusers <kullanıcı>@100.64.0.0/10
# allowusers <kullanıcı>@fd7a:115c:a1e0::/48
# allowusers <kullanıcı>@127.0.0.1
# allowusers <kullanıcı>@::1
# authenticationmethods publickey

Ters giderse: Bad configuration option → dosyada yazım hatası. Değerler farklı çıkıyorsa grep Include /etc/ssh/sshd_config satırının durduğunu ve dosya adının 010- ile başladığını kontrol et.

8. Remote Login'i aç, öteki kapıları kapat

sudo systemsetup -setremotelogin on terminalin Full Disk Access iznine sahip olmasını ister; terminale bütün diski açmak yerine arayüzü kullan:

  1. System Settings → General → Sharing → Remote Login açık.
  2. Yanındaki (i): Allow full disk access for remote users kapalı; Allow access for → Only these users → yalnızca senin kullanıcın.
  3. Aynı ekranda Remote Management, Remote Application Scripting ve Screen Sharing açıksa kapat. Bunlar her ağ arayüzünde dinler, macOS giriş şifreni kabul eder ve 7. adımdaki sertleştirme onları kapsamaz.

sshd her bağlantıda yeniden başladığı için ayarlar hemen geçerli.

Kontrol: Uzaktan erişim portlarından yalnızca 22 açık olmalı:

netstat -an -p tcp | grep LISTEN | grep -E '\.(22|5900|3283|3031) '
# tcp4  0  0  *.22  *.*  LISTEN
# tcp6  0  0  *.22  *.*  LISTEN

*.22 her arayüzde dinlemek demek; bu beklenen, filtreyi AllowUsers yapıyor. Şifrenin gerçekten kapalı olduğunu da dene:

ssh -o BatchMode=yes -o PubkeyAuthentication=no \
  -o PreferredAuthentications=password,keyboard-interactive \
  -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
  "$(whoami)@127.0.0.1" true
# <kullanıcı>@127.0.0.1: Permission denied (publickey).

Ters giderse: Parantezde password ya da keyboard-interactive da görünüyorsa drop-in okunmuyor; 7. adımın kontrolüne dön.

9. Termius

Termius'ta yeni bir host:

mosh, SSH'ı yalnızca girişte ve mosh-server'ı başlatmak için kullanır; oturumun kendisi UDP üzerinden akar, bu yüzden Wi-Fi'dan 5G'ye geçmek ya da telefonun uyuması onu öldürmez.

Sonra Snippets → +: adı ta, komutu ta. Host ayarlarında Startup Snippet olarak ta'yı seç; her bağlantı doğrudan main oturumuna düşer.

İlk bağlantıda Termius, Mac'in host key parmak izini gösterip güvenip güvenmediğini sorar. Körlemesine kabul etme, Mac'teki değerle karşılaştır:

ssh-keygen -l -f /etc/ssh/ssh_host_ed25519_key.pub

Kontrol: Bağlan: tmux'un yeşil durum çubuğunu görüyorsan zincirin tamamı çalışıyor.

Ters giderse: Aşağıdaki sorun giderme tablosuna bak.

10. Claude Code

Telefondan bağlıyken claude yaz. Çoğu zaman olduğu gibi açılır.

SSH oturumunda macOS'un şifre kasası login keychain kilitli görünebilir ve Claude Code yeniden giriş isteyebilir. İki yol var. Her oturumda kilidi aç (Mac şifreni sorar):

security unlock-keychain ~/Library/Keychains/login.keychain-db

Ya da uzun ömürlü bir token üret ve yalnızca SSH oturumlarının okuduğu bir dosyaya koy:

claude setup-token
mkdir -p ~/.config/remote && chmod 700 ~/.config/remote
printf 'export CLAUDE_CODE_OAUTH_TOKEN=%s\n' '<token>' > ~/.config/remote/env
chmod 600 ~/.config/remote/env
echo '[[ -n "$SSH_CONNECTION" && -r ~/.config/remote/env ]] && source ~/.config/remote/env' >> ~/.zshenv

<token> yerine setup-token'ın verdiği değeri yaz. Bu bir sır: dosyayı kimseyle paylaşma, hiçbir repoya commit etme.

Kontrol: Yeni bir bağlantıda echo ${CLAUDE_CODE_OAUTH_TOKEN:+var} → var, ve claude giriş istemeden açılıyor.

11. İsteğe bağlı: şarjdayken uyuma

Uyuyan Mac'e hiçbir şey ulaşamaz. caffeinate, macOS'un uykuyu engelleyen komutu; -s ile yalnızca şarjdayken geçerli. Bir LaunchAgent, yani oturum açınca launchd'nin başlattığı arka plan görevi, onu hep çalışır tutar:

mkdir -p ~/Library/LaunchAgents
cat > ~/Library/LaunchAgents/local.keepawake.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>local.keepawake</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/caffeinate</string>
    <string>-s</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/>
</dict>
</plist>
EOF
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/local.keepawake.plist

Kontrol: Şarjdayken:

launchctl print gui/$(id -u)/local.keepawake | grep 'state ='
# state = running
pmset -g assertions | grep PreventSystemSleep
# PreventSystemSleep  1

Ters giderse: state = not running ise launchctl kickstart gui/$(id -u)/local.keepawake ile başlat. Pildeyken ve kapak kapalıyken Mac yine uyur; kapak kapalı çalışmanın tek yolu harici ekranla clamshell modu.

12. Son test

  1. Telefondan bağlan, claude başlat.
  2. Telefonu kilitle, iki dakikadan fazla bekle, geri dön: aynı ekran.
  3. Bağlantıyı Termius'ta tamamen kapat, yeniden bağlan: aynı, hâlâ çalışan oturum.

Sorun giderme

BelirtiSebepÇözüm
mosh-server not foundEtkileşimsiz SSH oturumu Homebrew'u görmüyor3. adım
needs a UTF-8 native localeLANG tanımlı değil3. adımdaki LANG satırı
Permission denied (publickey)Anahtar authorized_keys'te yok, izinler gevşek, kullanıcı adı yanlış ya da bağlantı tailnet'ten gelmiyor6. adım; Username = whoami; Hostname MagicDNS adı mı, iPhone'da Tailscale açık mı
Zaman aşımıiPhone'da Tailscale kapalı ya da Mac uyuyorTailscale'i aç; 11. adım
mosh bağlanıyor ama ekran gelmiyormacOS güvenlik duvarı mosh'un UDP'sini engelliyorsocketfilterfw ile mosh-server'a izin ver (aşağıda)
tailscale: command not foundUygulamanın CLI'ı PATH'te değilTam yol ya da alias, 2. adım
no hostkeys availableHost key hiç üretilmemişsudo ssh-keygen -A
Claude giriş istiyorSSH oturumunda keychain kilitli10. adım
ta: command not found~/.local/bin PATH'te değil3. adım

Güvenlik duvarı açıksa mosh-server'a izin vermek için:

sudo /usr/libexec/ApplicationFirewall/socketfilterfw --add "$(realpath /opt/homebrew/bin/mosh-server)"
sudo /usr/libexec/ApplicationFirewall/socketfilterfw --unblockapp "$(realpath /opt/homebrew/bin/mosh-server)"

Geri alma

sudo rm /etc/ssh/sshd_config.d/010-remote.conf
sed -i '' '/ iphone$/d' ~/.ssh/authorized_keys
launchctl bootout gui/$(id -u)/local.keepawake
rm ~/Library/LaunchAgents/local.keepawake.plist ~/.local/bin/ta
rm -r ~/.config/remote

Sonra System Settings → General → Sharing'de Remote Login'i kapat, ~/.zshenv ve ~/.tmux.conf'a eklediğin satırları elle sil ve telefonu Tailscale yönetim panelinden kaldır.

Güvenlik modeli

Bu kararların arkasındaki hikâye ve her birini nasıl öğrendiğim Cebimdeki Claude Code yazısında.