TEKNİK YAZI / Backend Sistemleri

SCP Komutu: SSH Üzerinden Güvenli Dosya Kopyalama

SCP komutuyla SSH üzerinden dosya ve dizin kopyalama: OpenSSH 8.7 ve 9.0 değişiklikleri, port ve URI biçimi, anahtar kullanımı, rsync ve sftp ile farkları.

scp (secure copy), dosyaları SSH bağlantısı üzerinden yerel makine ile uzak sunucu arasında ya da iki uzak sunucu arasında kopyalayan OpenSSH aracıdır. Kimlik doğrulama ve şifreleme SSH’den gelir; SSH ile bağlanabildiğiniz her sunucuya ek bir servis kurmadan dosya gönderip alabilirsiniz.

Yazı scp’nin bugün nasıl çalıştığını, temel ve ileri kullanımını, farklı portlu sunucuları, iki uzak sunucu arasındaki kopyalamayı, sık hataları ve rsync ya da sftp’nin ne zaman daha uygun olduğunu ele alır. Sürüme bağlı davranışlar OpenSSH sürümüyle birlikte belirtilir; kendi sürümünüzü ssh -V ile görebilirsiniz.

scp nasıl çalışır

scp arka planda ssh istemcisini başlatır ve dosyayı bu bağlantı üzerinden taşır. Bu yüzden yalnız uzak tarafta bir SSH sunucusu, yani daemon olarak çalışan sshd gerekir; yerel makinede ssh istemcisi yeterlidir. Bağlantı ayarları (~/.ssh/config, anahtarlar, known_hosts) ssh ile ortaktır.

OpenSSH 9.0’a (Nisan 2022) kadar scp, eski SCP/RCP protokolünü kullanıyordu. Bu protokolde uzak tarafta bir scp süreci başlatılır, uzak dosya adları ve joker karakterler uzak kabukta yorumlanır. OpenSSH 8.0 sürüm notları bu protokolü eskimiş ve kolayca düzeltilemez olarak nitelendirip dosya aktarımı için sftp ve rsync önerdi. OpenSSH 9.0 ile scp istemcisi varsayılan olarak SFTP protokolüne geçti; komut satırı aynı kaldı. Bunun pratik sonuçları:

Temel kullanım

Genel biçim scp [seçenekler] kaynak... hedef şeklindedir. Uzak taraf [kullanıcı@]sunucu:[yol] olarak yazılır; / ile başlamayan uzak yol, uzak kullanıcının ev dizinine göre çözülür.

Yerelden uzağa:

# Tek dosya
scp rapor.pdf kullanici@192.0.2.10:/home/kullanici/belgeler/

# Birden fazla dosya; hedef yol ev dizinine göre
scp dosya1.txt dosya2.txt kullanici@sunucu.example.com:yedek/

# Standart dışı port: büyük harf -P
scp -P 2222 veri.zip yonetici@sunucu.example.com:/tmp/

Uzaktan yerele:

# Tek dosya
scp kullanici@sunucu.example.com:/var/log/app.log ./loglar/

# Belirli bir özel anahtarla
scp -i ~/.ssh/id_ed25519 kullanici@sunucu.example.com:/srv/uygulama/config.yml ./

Adında : geçen yerel bir dosyayı kopyalarken yolu ./ ile başlatın; aksi hâlde scp iki noktadan öncesini sunucu adı sanar.

Dizin kopyalama

# Dizini özyinelemeli kopyala
scp -r ./proje kullanici@sunucu.example.com:/srv/

# Değiştirilme ve erişim zamanlarını ve izin bitlerini koru
scp -rp ./proje kullanici@sunucu.example.com:/srv/

-p sahiplik bilgisini taşımaz; yalnız zaman damgaları ve izin bitleri korunur. -r dizin ağacındaki sembolik bağlantıları izler, yani bağlantının gösterdiği içeriği kopyalar. Bağlantıların bağlantı olarak taşınması gerekiyorsa rsync -a kullanın.

Kimlik doğrulama ve anahtarlar

scp, ssh’nin desteklediği yöntemlerin hepsini kullanır: parola, açık anahtar, sertifika, Kerberos (GSSAPI) ve klavye etkileşimli doğrulama (ör. tek kullanımlık kod). Sık kopyalama ve betikler için açık anahtar yöntemi pratiktir:

# Ed25519 anahtar çifti üretir (OpenSSH 9.5 ve sonrasında varsayılan tür)
ssh-keygen -t ed25519 -C "dizustu"

# Açık anahtarı sunucudaki ~/.ssh/authorized_keys dosyasına ekler
ssh-copy-id -i ~/.ssh/id_ed25519.pub kullanici@sunucu.example.com

Özel anahtarı bir parola (passphrase) ile koruyup ssh-agent’a eklemek, her kopyalamada parola yazmadan anahtarın diskte korumasız durmamasını sağlar. Cron job gibi etkileşimsiz ortamlarda -B (batch mode) parola ve passphrase sorularını kapatır; kimlik doğrulama başarısızsa komut beklemek yerine hatayla çıkar.

Diğer seçenekler

# Sıkıştırma: yavaş hatlarda ve metin, SQL dökümü gibi sıkıştırılabilir veride işe yarar
scp -C veritabani.sql kullanici@yedek.example.com:/yedekler/

# Bant genişliği sınırı Kbit/s cinsindendir: 4000 Kbit/s yaklaşık 500 KB/s eder
scp -l 4000 kalip.iso kullanici@sunucu.example.com:/veri/

# Hata ayıklama çıktısı: bağlantı, kimlik doğrulama ve yapılandırma sorunları için
scp -v config.tar.gz kullanici@sunucu.example.com:/tmp/

# Atlama sunucusu (bastion) üzerinden kopyalama
scp -J kullanici@bastion.example.com kullanici@ic-sunucu:/var/log/app.log ./

-v aktarım ilerlemesini değil, ssh’nin bağlantı adımlarını gösterir; ilerleme çubuğu terminalde zaten varsayılan olarak görünür. Zaten sıkıştırılmış dosyalarda (.zip, .gz, .jpg, video) -C kazanç getirmez, yalnız işlemci harcar.

Farklı portlar, ~/.ssh/config ve URI biçimi

-P komuttaki tüm uzak taraflara aynı portu uygular. Farklı portlu sunucularla çalışmanın iki temiz yolu vardır. Birincisi, ~/.ssh/config dosyasında sunucu başına ayar tanımlamaktır:

Host kaynak
    HostName server1.example.com
    User admin
    Port 2222

Host hedef
    HostName server2.example.com
    User admin
    Port 3333

Bu tanımdan sonra kısa adlar yeterlidir:

scp kaynak:/logs/app.log hedef:/archive/

İkincisi, portu komutun içinde taşıyan URI biçimidir: scp://[kullanıcı@]sunucu[:port][/yol].

scp scp://admin@server1.example.com:2222//logs/app.log scp://admin@server2.example.com:3333//archive/

URI’de sunucu ya da porttan sonraki ilk / yalnız ayırıcıdır ve yol ondan sonra başlar. Bu yüzden ev dizinine göre göreli bir yol için tek /, mutlak yol için // yazılır. admin@server1:2222:/logs/app.log gibi bir yazım ise geçersizdir: scp sunucu adından sonraki ilk :’dan sonrasını yol sayar ve ev dizininde 2222:/logs/app.log adlı bir dosya arar.

İki uzak sunucu arasında kopyalama

OpenSSH 8.7’den beri iki uzak sunucu arasındaki kopyalama varsayılan olarak yerel makine üzerinden yapılır; eskiden bunun için -3 seçeneği gerekiyordu. Bu kipte yerel makine iki sunucuya ayrı ayrı bağlanır ve kimlik doğrular, kimlik bilgilerinin kaynak sunucuya taşınması gerekmez. Eski doğrudan davranış -R ile seçilir: scp kaynak sunucuya bağlanıp kopyayı orada başlatır, bu yüzden kaynak sunucunun hedefe parola sormadan kimlik doğrulayabilmesi gerekir.

# Varsayılan (OpenSSH 8.7+): veri yerel makine üzerinden akar
scp kaynak:/data/arsiv.zip hedef:/backup/

# Doğrudan aktarım: kaynak sunucu hedefe kendisi bağlanır
scp -R kaynak:/data/arsiv.zip hedef:/backup/

Varsayılan kipte veri yerel makinenin bağlantısından iki kez geçer. İki sunucu aynı ağdaysa ve kaynak sunucunun hedefe erişimi zaten tanımlıysa -R daha hızlı olabilir; kimlik bilgilerinin nerede durduğunu bu kararla birlikte düşünün.

Güvenlik notları

scp -o StrictHostKeyChecking=yes dosya.txt kullanici@sunucu.example.com:/tmp/

Şifreleme ve hız

scp’nin varsayılan olarak 3DES kullandığı bilgisi eskidir: OpenSSH 7.4 (Aralık 2016) 3des-cbc’yi istemcinin varsayılan listesinden çıkardı. OpenSSH 10.0 ile varsayılan sıra ChaCha20-Poly1305, AES-GCM (128/256) ve ardından AES-CTR oldu. Bu yüzden -c ile şifre seçmek çoğu kullanımda gerekmez. İstemcinin kullanacağı listeyi ve bağlantıda seçilen şifreyi şöyle görebilirsiniz:

# İstemcinin bu sunucu için önereceği şifre listesi
ssh -G sunucu.example.com | grep '^ciphers'

# Bağlantıda anlaşılan şifre (hata ayıklama çıktısındaki kex satırları)
scp -v dosya.txt kullanici@sunucu.example.com:/tmp/ 2>&1 | grep 'cipher:'

Aktarım yavaşsa önce darboğazı belirleyin: hat hızı, disk ya da çok sayıda küçük dosya. -C yalnız yavaş hatta ve sıkıştırılabilir veride fark yaratır; hızlı bir yerel ağda kazanç getirmeyebilir.

Pratik örnekler

Birden fazla sunucudan günlük toplamak:

for sunucu in web1 web2 web3; do
  scp "kullanici@${sunucu}:/var/log/app.log" "./loglar/${sunucu}-app.log"
done

Veritabanı dökümünü sunucuda dosya olarak tutmadan almak için scp yerine doğrudan bir ssh boru hattı kullanılabilir:

# Dökümü uzakta sıkıştırıp yerel dosyaya akıtır
ssh yedek@db.example.com 'mysqldump --single-transaction uygulama_db | gzip' > uygulama_db.sql.gz

# Başarılı bir döküm "-- Dump completed" satırıyla biter
gzip -dc uygulama_db.sql.gz | tail -n 1

Veritabanı kimlik bilgileri komut satırına yazılmaz; uzaktaki yedek kullanıcısının yalnız kendisinin okuyabildiği (chmod 600) ~/.my.cnf dosyasında, yalnız gereken yetkilere sahip bir veritabanı hesabıyla tanımlanır. --single-transaction, InnoDB tablolarında uygulamaları kilitlemeden tutarlı bir anlık görüntü alır. Uzak boru hattında mysqldump başarısız olsa bile gzip başarılı çıkabileceği için son satır kontrolü önemlidir.

Bir web sitesini dağıtırken scp, hedefte artık kaynakta olmayan dosyaları silmez ve eski dosyalar birikir. Hedefi kaynakla eşitlemek için rsync daha uygundur; --delete hedefte dosya sildiği için önce --dry-run ile deneyin:

rsync -a --delete --dry-run ./dist/ kullanici@sunucu.example.com:/var/www/site/

Sorun giderme

Bağlantı kurulamıyor: Connection refused veya zaman aşımı

Connection refused, sunucuya ulaşıldığını ama o portta dinleyen bir süreç olmadığını gösterir. Zaman aşımı ise paketlerin yolda, çoğunlukla bir güvenlik duvarında düştüğünü düşündürür. İki durumda da ssh ile sunucuya giremeyeceğiniz için kontrolü istemciden yapın:

# Port erişilebilir mi
nc -vz sunucu.example.com 22

# Bağlantı adımlarını ayrıntılı göster
ssh -v kullanici@sunucu.example.com

Port kapalıysa sağlayıcınızın web konsolundan sunucuya girip SSH servisini kontrol edin. Servis adı dağıtıma göre değişir:

sudo systemctl status ssh    # Debian, Ubuntu
sudo systemctl status sshd   # RHEL, Fedora

Ubuntu 22.10 ve sonrasında SSH varsayılan olarak soket etkinleştirmeyle başlar: portu ssh.socket birimi dinler, sshd ilk bağlantı geldiğinde başlatılır (Ubuntu duyurusu). Bu sistemlerde ssh servisi inactive görünse bile SSH çalışıyor olabilir; dinlenen portu soket biriminin durumu gösterir:

sudo systemctl status ssh.socket

Yetki hatası: Permission denied

İki farklı hata aynı kelimeyle görünür. Permission denied (publickey) kimlik doğrulama hatasıdır: ssh -v hangi anahtarların denendiğini gösterir; sunucuda ~/.ssh dizini ve authorized_keys dosyası başkalarınca yazılabilir olmamalıdır (önerilen izinler 700 ve 600). scp: /yol: Permission denied ise dosya sistemi iznidir; hedef dizinin sahibini ve izinlerini kontrol edin:

ssh kullanici@sunucu.example.com 'ls -ld /hedef/dizin'

Eski sunucular ve dosya adı sorunları

OpenSSH 9.0 öncesi bir sunucuya ya da SFTP alt sistemi kapalı bir sunucuya kopyalama başarısız oluyorsa -O ile eski protokolü deneyin. Joker karakterli uzak yolları tek tırnakla yazmak, yerel kabuğun onları genişletmesini önler: scp 'kullanici@sunucu.example.com:/var/log/*.log' ./loglar/.

scp, rsync ve sftp: hangisi ne zaman

İhtiyaçUygun araç
Tek seferlik dosya veya dizin kopyalamascp
Tekrarlanan eşitleme, yalnız değişen dosyaları göndermekrsync
Hedefte kaynakta olmayan dosyaları silmekrsync --delete
Kesilen aktarımı sürdürmeksftp (reget, reput), rsync --partial
Sunucuda dosya gezmek, listelemek, etkileşimli çalışmaksftp
Sembolik bağlantıları ve izinleri olduğu gibi taşımakrsync -a

rsync, SSH üzerinden karşı tarafta da bir rsync süreci başlattığı için iki makinede de kurulu olmalıdır; scp ve sftp için uzak tarafta sshd yeterlidir. FTP ise kimlik bilgilerini ve içeriği şifrelemeden taşır; SSH erişimi olan bir sunucuda FTP’ye ihtiyaç yoktur.

Sonuç

scp, SSH erişimi olan bir sunucuya tek seferlik dosya veya dizin göndermenin en kısa yoludur ve OpenSSH 9.0’dan beri arka planda SFTP protokolünü kullanır. Tekrarlanan eşitleme, hedefte silme, kesilen aktarımı sürdürme ya da sembolik bağlantıları koruma gerektiğinde rsync veya sftp daha uygundur. Hangi araç seçilirse seçilsin güvenlik SSH yapılandırmasından gelir: anahtar tabanlı giriş, doğrulanmış sunucu anahtarı ve güvenlik duvarıyla sınırlanmış SSH portu.

Birincil kaynaklar