00 SSH mental modeli
SSH (Secure Shell) şifreli bir tünel açar ve bu tünelden hem komut çalıştırır hem dosya aktarır.
İstemci Sunucu
─────────────────────────────────────────────────────
ssh kullanıcı@host
1. TCP bağlantısı kur (port 22)
2. SSH versiyon handshake
3. Anahtar değişimi (DH/ECDH) → oturum anahtarı
4. Sunucu kimliği doğrula (known_hosts)
5. İstemci kimlik doğrula:
a. public key auth → tercih edilen
b. password auth → daha zayıf
6. Şifreli kanal kuruldu
7. Kabuk veya komut çalıştır
SSH bağlantısı kurulduktan sonra her şey şifrelenir. SCP ve rsync da aynı SSH tünelini kullanır — ayrıca şifreleme yapmaz, SSH'ı kullanır.
Parola ile giriş brute-force saldırısına açık. Public key auth'ta sunucu sadece ortak anahtarın kimliğini doğrular; özel anahtar asla ağdan geçmez. Prodüksiyonda parola auth'u devre dışı bırak: PasswordAuthentication no (sshd_config).
01 ssh-keygen — anahtar üret
Bir anahtar çifti oluştur: özel anahtar sende kalır, ortak anahtar sunucuya gider.
# Modern ve önerilen: ed25519
ssh-keygen -t ed25519 -C "ali@work-laptop"
# RSA (geriye dönük uyumluluk gerektiriyorsa 4096 bit)
ssh-keygen -t rsa -b 4096 -C "ali@legacy-server"
# Farklı dosyaya kaydet (birden fazla anahtar yönetmek için)
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github -C "github"
ed25519 (modern, kısa), rsa (eski uyumluluk), ecdsa, dsa (kullanma).-N "". Parola koyarsan özel anahtarı şifreler — çalıntı anahtara karşı ek koruma.# Oluşan dosyalar
~/.ssh/id_ed25519 ← özel anahtar (600 izni, kimseye verme)
~/.ssh/id_ed25519.pub ← ortak anahtar (sunucuya kopyalanır)
# Ortak anahtarı göster
cat ~/.ssh/id_ed25519.pub
# → ssh-ed25519 AAAA...uzun_baz64... ali@work-laptop
~/.ssh/id_ed25519 — bu dosya bilgisayarından çıkmamalı. Parolasız bir özel anahtara sahip olan biri, sunucularına erişebilir. Güvenli yedek alıyorsan şifreli arşivle (veya parola koy).
ssh-agent — passphrase'i bir kez gir
# Agent'i başlat (zaten çalışıyorsa atla)
eval "$(ssh-agent -s)"
# Anahtarı agent'e ekle (bir kez passphrase sorar)
ssh-add ~/.ssh/id_ed25519
# Yüklü anahtarları listele
ssh-add -l
02 Anahtarı sunucuya kopyala
Ortak anahtarın sunucudaki ~/.ssh/authorized_keys dosyasına eklenmesi gerekir.
# En kolay yol — ssh-copy-id
ssh-copy-id kullanici@sunucu
# Belirli anahtar dosyası ile
ssh-copy-id -i ~/.ssh/id_ed25519.pub kullanici@sunucu
# ssh-copy-id yoksa (macOS, bazı sistemler) elle kopyala
cat ~/.ssh/id_ed25519.pub | ssh kullanici@sunucu \
'mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
ssh-copy-id ortak anahtarı (.pub) alır ve sunucudaki ~/.ssh/authorized_keys dosyasına ekler. Bir sonraki ssh bağlantısında sunucu bu dosyayı okur, özel anahtarınla kriptografik olarak eşleşiyor mu diye kontrol eder. Eşleşiyorsa parola sormadan girer.
authorized_keys dosyası
# Her satır bir ortak anahtar
ssh-ed25519 AAAA...abc... ali@laptop
ssh-ed25519 AAAA...xyz... ali@work-desktop
# Kısıtlama: sadece belirli bir komut çalıştırabilsin
command="rsync --server ..." ssh-ed25519 AAAA...ghi... rsync-backup-key
~/.ssh/ dizini 700, authorized_keys dosyası 600 olmalı. Aksi halde sshd bu dosyaları güvensiz sayarak yok sayar. chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
03 ~/.ssh/config — alias ve seçenekler
Her sunucu için ayrı ayrı flag yazmak yerine config dosyasında bir kez tanımla.
# Genel ayarlar (tüm host'lar için)
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
AddKeysToAgent yes
# Üretim sunucusu alias'ı
Host prod
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519_prod
Port 2222
# Bastion üzerinden erişim (ProxyJump)
Host internal
HostName 10.0.0.50
User alice
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Host bastion
HostName 203.0.113.1
User alice
IdentityFile ~/.ssh/id_ed25519
# Bağlantı tekrar kullanımı (ControlMaster)
Host dev-server
HostName dev.example.com
User dev
ControlMaster auto
ControlPath ~/.ssh/cm_%r@%h:%p
ControlPersist 10m
ssh prod dediğinde bu bloğun ayarları uygulanır.ssh user@host yazmana gerek yok.-J flag'inin config karşılığı.# Artık kısa kullanım
ssh prod # → deploy@203.0.113.10:2222
ssh internal # → bastion üzerinden 10.0.0.50
scp dosya.txt prod:~/ # → alias çalışır
04 ssh ile komut çalıştırma
ssh sadece interaktif kabuk açmaz — uzakta tek bir komut veya pipeline çalıştırabilir.
# Uzakta komut çalıştır, çıktı yerel stdout'a gelir
ssh prod 'df -h'
ssh prod 'systemctl status nginx'
# Uzakta pipeline
ssh prod 'tail -n 100 /var/log/app.log | grep ERROR'
# -t: interaktif TTY gerekiyorsa (sudo, vi, top gibi)
ssh -t prod 'sudo journalctl -f'
# -N: komut çalıştırma, sadece tünel aç (port forwarding için)
ssh -N -L 8080:localhost:80 prod
# Uzaktaki komutu yerel pipe'a bağla
ssh prod 'cat /var/log/app.log' | grep 'ERROR' | tail -20
# Yerel dosyayı uzak komuta gönder
cat yerel.sql | ssh prod 'mysql -u root mydb'
ssh -fN -L ...Uzak komutun stderr'i de yerel stderr'e akar: ssh prod 'komut' 2>&1 | grep ... ile uzak stderr'i de pipeline'a dahil edebilirsin.
05 Port yönlendirme — -L, -R, -D
SSH tüneli ağ bağlantısı da taşıyabilir. Üç yön: local, remote, dynamic (SOCKS).
-L (Local port forward) — uzak servise yerel eriş
# Yerel 8080'i, prod üzerindeki localhost:80'e yönlendir
ssh -L 8080:localhost:80 prod
# Sonra: http://localhost:8080 → prod'daki nginx
# Üçüncü bir sunucuya yönlendirme
ssh -L 5432:db-internal:5432 bastion
# Yerel 5432 → bastion → db-internal:5432 (yerel psql bağlanabilir)
-R (Remote port forward) — yerel servise uzaktan eriş
# Sunucudaki 9000 portunu, yereldeki localhost:3000'e yönlendir
ssh -R 9000:localhost:3000 prod
# Sonra: prod'da curl http://localhost:9000 → senin yerel dev sunucun
# Webhook test etmek için idealdir
-D (Dynamic SOCKS proxy)
# SOCKS5 proxy: tüm trafiği SSH tünelinden geçir
ssh -D 1080 prod
# Sonra: tarayıcı veya curl'de SOCKS5 proxy = localhost:1080 ayarla
curl --socks5 localhost:1080 http://internal-only-site/
# Arka planda çalıştır
ssh -fND 1080 prod
| Flag | Yön | Kullanım |
|---|---|---|
| -L yerel:uzak_host:uzak_port | Yerel → Uzak | Uzaktaki servise yerel erişim (DB, admin UI) |
| -R uzak_port:yerel_host:yerel_port | Uzak → Yerel | Dev sunucunu dışarıya aç, webhook test |
| -D yerel_port | SOCKS proxy | Tüm trafiği tünellemek, kısıtlı ağdan çıkmak |
06 scp — dosya kopyalama
scp (Secure Copy) SSH üzerinden dosya kopyalar. Sözdizimi cp'ye benzer, kaynak veya hedef uzak olabilir.
# Yerelden uzağa
scp dosya.txt kullanici@sunucu:/hedef/yol/
scp dosya.txt prod:~/ # config alias
# Uzaktan yerele
scp kullanici@sunucu:/log/app.log ./
scp prod:/etc/nginx/nginx.conf ./nginx.conf # config alias
# Dizin kopyala (-r)
scp -r ./dist/ prod:/var/www/html/
# Farklı port (-P büyük harf!)
scp -P 2222 dosya.txt kullanici@sunucu:/tmp/
# Uzaktan uzağa
scp sunucu1:/data/dump.sql sunucu2:/restore/
-l 1000 → 1 Mbit/s.scp büyük dizinlerde yavaş ve güvenilmezdir: resume (devam) desteği yok, kısmi dosyada kesilirse baştan başlar. Büyük ya da artımlı aktarımlarda rsync kullan.
07 rsync — artımlı eşitleme
rsync sadece değişen parçaları gönderir. Büyük dizinler, kesintili bağlantılar ve yedekleme için doğal tercih.
# -a (archive): -rlptgoD kısaltması
# -r: recursive -l: symlink -p: izinler
# -t: timestamp -g: grup -o: sahip -D: device
rsync -av ./src/ kullanici@sunucu:/dest/
# -v: verbose (ne gönderildiğini göster)
# -z: sıkıştır (WAN için yardımcı, LAN'da ekstra yük)
# --progress: her dosyanın ilerlemesini göster
rsync -avz --progress ./büyük-dizin/ prod:/backup/
# --delete: hedefte kaynak'ta olmayan dosyaları sil (mirror)
rsync -av --delete ./site/ prod:/var/www/html/
# --dry-run (-n): gerçekten yapma, sadece ne olacağını göster
rsync -av --delete --dry-run ./site/ prod:/var/www/html/
# --exclude: belirli dosyaları atla
rsync -av --exclude '*.log' --exclude '.git' ./proje/ prod:/deploy/
# --exclude-from: exclude listesi dosyadan oku
rsync -av --exclude-from .rsyncignore ./proje/ prod:/deploy/
--bwlimit=5000 → 5 MB/s.Trailing slash kuralı
# src/ SONUNDA / VAR → dizin içeriğini kopyala
rsync -av src/ sunucu:/dest/
# Sonuç: /dest/dosya1 /dest/dosya2 …
# src SONUNDA / YOK → dizinin kendisini kopyala
rsync -av src sunucu:/dest/
# Sonuç: /dest/src/dosya1 /dest/src/dosya2 …
rsync'in en sık karşılaşılan hatası budur. rsync -av src/ dest/ ile rsync -av src dest/ farklı sonuçlar verir. Kuralı: kaynak sonundaki / "dizinin kendisi değil içeriği" anlamına gelir.
08 rsync vs scp — ne zaman hangisi
İkisi de SSH kullanır ama farklı güçleri var.
| Kriter | scp | rsync |
|---|---|---|
| Tek dosya kopyalama | Hızlı ve basit | Fazla |
| Büyük dizin aktarımı | Yavaş, tüm dosyaları gönderir | Sadece değişeni gönderir |
| Kesinti sonrası devam | Baştan başlar | Kaldığı yerden devam eder |
| Mirror (--delete) | Yok | Var |
| Dosya öznitelikleri | -p ile kısmi | -a ile tam (-r -l -p -t -g -o) |
| Bant genişliği kontrolü | -l ile sınırlı | --bwlimit ile hassas |
| Exclude/filter | Yok | Var |
| Dry-run | Yok | --dry-run |
Tek bir dosya veya küçük bir şey mi? → scp. Dizin, büyük veri, yedekleme, deployment, ya da tekrar çalışacak bir şey mi? → rsync. Şüphe durumunda rsync.
09 Debug ve yaygın hatalar
SSH bağlantısı kurulmuyorsa adım adım teşhis.
-v ile verbose
ssh -v kullanici@sunucu # verbose (1 seviye)
ssh -vvv kullanici@sunucu # maksimum debug çıktısı
known_hosts temizleme
# "REMOTE HOST IDENTIFICATION HAS CHANGED" hatası aldığında
# (sunucu yeniden kurulduysa, IP değiştiyse normaldir)
ssh-keygen -R sunucu_ip_veya_hostname
# Ya da elle düzenle
nano ~/.ssh/known_hosts # ilgili satırı sil
İzin sorunları
# Sunucuda şunları kontrol et
ls -la ~/.ssh/
# drwx------ ~/.ssh/ (700 olmalı)
# -rw------- ~/.ssh/authorized_keys (600 olmalı)
# Düzelt
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
# Yerel özel anahtar izni de önemli
chmod 600 ~/.ssh/id_ed25519
sshd_config debug (sunucu tarafında)
# Sunucudan auth logunu izle
sudo journalctl -fu ssh
# veya
sudo tail -f /var/log/auth.log
# PubkeyAuthentication açık mı? (sshd_config kontrol)
grep 'PubkeyAuth' /etc/ssh/sshd_config
Hatırlanacaklar
- Anahtar tipi:
ssh-keygen -t ed25519 -C "yorum"— modern ve kısa - Ortak anahtarı sunucuya kopyala:
ssh-copy-id user@host - ~/.ssh/config ile alias:
Host prodbloğu,ssh prodkısalığı - ProxyJump: bastion üzerinden iç ağa ulaşmak için
- ControlMaster: aynı host'a çoklu bağlantıda yeniden handshake yapmaz
- scp: tek dosya, hızlı. rsync: dizin, artımlı, mirror, devam
- rsync trailing slash:
src/içeriği,srcdizinin kendisi - rsync --dry-run: tehlikeli işlemden önce her zaman
- İzinler: ~/.ssh 700, authorized_keys 600, özel anahtar 600
Güvenli bağlantı kurulduktan sonra mTLS ile nasıl sertifika tabanlı kimlik doğrulama yapılacağını merak ediyorsan: Sıfırdan mTLS rehberi.