SSH Tünel Rehberi: Local, Remote ve Dynamic Forwarding

SSH tünel kurmak için -L, -R ve -D bayraklarıyla veritabanına güvenli erişimi, NAT arkasını paylaşmayı ve SOCKS proxy kurmayı gerçek komutlarla anlatıyorum.

Linux
SSH Tünel Rehberi: Local, Remote ve Dynamic Forwarding

Bir veritabanı sadece localhosttan bağlantı kabul ediyor, ama siz ofisten erişmek istiyorsunuz. Ya da halka açık bir WiFi'de şifresiz bir servise güvenli erişmeniz gerekiyor. İki durumun da çözümü aynı: SSH tünel ve port yönlendirme. Bu yazıda -L, -R ve -D bayraklarının ne işe yaradığını, hangi durumda hangisini seçeceğinizi ve gerçek komutlarla nasıl kullanılacağını anlatıyorum.

Local forwarding (-L) ne zaman kullanılır?

-L bayrağı, yerel makinenizdeki bir portu SSH sunucusu üzerinden uzaktaki bir servise bağlar. En yaygın senaryo şu: sunucuda sadece localhost:5432den dinleyen bir PostgreSQL veritabanına, kendi makinenizden erişmek istersiniz.

ssh -L 5433:localhost:5432 kullanici@sunucu-ip

Bu komut kendi makinenizin 5433 portunu, sunucu-ip üzerinden sunucunun localhost:5432 adresine tünelliyor. Artık psql -h localhost -p 5433 yazarak veritabanına bağlanabilirsiniz, tıpkı yerel bir veritabanıymış gibi. Trafik yine de SSH şifrelemesinden geçer. Sözdizimi ilk bakışta kafa karıştırıcı gelebilir; üç parça olarak okuyun: [yerel-port]:[hedef-host]:[hedef-port].

Hedef host burada SSH sunucusunun bakış açısından "localhost" demektir, sizin makinenizin değil. Bu ayrım, üçüncü bir sunucuya tünel açarken kritik hâle gelir. Örneğin sunucu-A üzerinden sunucu-Bdeki bir servise ulaşmak isterseniz, hedef host kısmına sunucu-Bnin adresini yazarsınız, sunucu-Ayı değil.

Bir web uygulamasının yönetim panelini güvenlik gerekçesiyle sadece sunucu içinden erişilebilir bıraktıysanız da aynı mantık işler:

ssh -L 8080:localhost:3000 kullanici@sunucu-ip

Tarayıcınızda http://localhost:8080 adresine gittiğinizde aslında sunucudaki 3000 portunu görürsünüz. Tüneli arka planda çalıştırıp terminali meşgul etmemek için -f ve -N bayraklarını ekleyin:

ssh -f -N -L 8080:localhost:3000 kullanici@sunucu-ip

-N uzak komut çalıştırmaz, sadece yönlendirme yapar. -f ise işlemi arka plana atar. Tüneli kapatmak için ps aux | grep ssh ile PID'i bulup kill ile sonlandırmanız gerekir, çünkü artık önde çalışan bir terminal yoktur.

Birden fazla portu tek komutta yönlendirmek de mümkün. -L bayrağını istediğiniz kadar tekrarlayabilirsiniz:

ssh -L 5433:localhost:5432 -L 8080:localhost:3000 kullanici@sunucu-ip

Bu tek komut hem veritabanı hem de web panel tünelini aynı SSH oturumunda açar; iki ayrı terminal penceresi yönetmekten daha pratiktir. Yerel port zaten kullanımdaysa SSH size "bind: Address already in use" hatası verir. Bu durumda lsof -i :5433 ile o portu hangi sürecin tuttuğunu bulabilir, gerekirse farklı bir yerel port seçebilirsiniz. 1024'ün altındaki portları yerel makinede açmak da yönetici yetkisi ister; bu yüzden pratikte yerel tarafta genelde 1024 üzeri numaralar tercih edilir.

Remote forwarding (-R) local forwarding'den nasıl farklı?

-L uzaktaki bir portu size getirirken -R tam tersini yapar: yerel makinenizdeki bir servisi uzak sunucu üzerinden erişilebilir kılar. NAT arkasında, kendine ait genel IP'si olmayan bir geliştirme makinesini dışarıya açmak istediğinizde işe yarar.

SSH local ve remote forwarding yönlerini gösteren karşılaştırma şeması
ssh -R 8080:localhost:3000 kullanici@genel-sunucu

Bu komut kendi makinenizde 3000 portunda çalışan bir uygulamayı, genel-sunucunun 8080 portu üzerinden erişilebilir yapar. Sunucudaki başka biri curl localhost:8080 çalıştırdığında aslında sizin makinenizdeki uygulamaya ulaşır. Bu, ev ağınızdaki bir geliştirme sunucusunu router'da port yönlendirmesi (NAT ayarı) yapmadan geçici olarak paylaşmanın en hızlı yolu.

Güvenlik açısından -R bayrağını dikkatli kullanmak gerekir. Sunucudaki portu açtığınız anda, o sunucuya erişimi olan herkes potansiyel olarak sizin makinenizdeki servise de ulaşabilir. Geçici bir demo için bu sorun değildir, ama uzun süreli bir paylaşım düşünüyorsanız hedef serviste kendi kimlik doğrulamasının olduğundan emin olun. SSH tüneli sadece ağ katmanını korur, uygulama seviyesinde yetkilendirme yapmaz.

Bu teknik özellikle CGNAT (Carrier-Grade NAT) arkasındaki bağlantılarda değerlidir. Birçok mobil operatör ve bazı ev interneti sağlayıcıları size gerçek bir genel IP vermez, bu yüzden klasik router port yönlendirmesi hiç işe yaramaz. Genel IP'si olan ucuz bir VPS üzerinden -R tüneli açmak, bu kısıtlamayı aşmanın en pratik yolu.

Varsayılan olarak SSH sunucusu -R ile açılan portu sadece localhosttan dinler. Dışarıdan erişilebilir yapmak için sunucu tarafında sshd_config içinde GatewayPorts yes ayarlanmalıdır. Bu ayarı sadece güvendiğiniz sunucularda açın; çünkü herhangi bir tünel sahibinin portunu dışarıya açmasına izin verir.

Yaygın bir kullanım senaryosu bir müşteriye demo göstermektir. Geliştirme sunucunuzda çalışan bir uygulamayı dakikalar içinde geçici bir genel adresten erişilebilir yapabilirsiniz. ngrok gibi ticari araçlar aynı işi yapar, ama zaten bir SSH sunucunuz varsa -R bayrağı ek bir bağımlılık gerektirmeden aynı sonucu verir.

Dynamic forwarding (-D) bir SOCKS proxy nasıl kurar?

-D tek bir portu değil, SSH sunucusu üzerinden genel bir SOCKS proxy açar. Halka açık bir WiFi'de tüm tarayıcı trafiğinizi şifreli tünelden geçirmek istediğinizde en pratik çözüm budur. SSH'ın tüm yönlendirme seçeneklerini OpenSSH'ın resmi kılavuzlarında bulabilirsiniz.

Terminalde autossh ile kalıcı SSH tünelinin başlatılması
ssh -D 1080 kullanici@sunucu-ip

Bu komutu çalıştırdıktan sonra tarayıcınızın ağ ayarlarından SOCKS5 proxy'yi localhost:1080 olarak yapılandırın. Firefox'ta bu ayar about:preferences altında "Ağ Ayarları" bölümünde bulunur. Chrome ise sistem proxy ayarlarını kullanır, bu yüzden --proxy-server bayrağıyla başlatmak daha pratiktir:

google-chrome --proxy-server="socks5://localhost:1080"

-D ile açılan tünelden geçen tüm trafik SSH sunucunuzun IP'sinden çıkmış gibi görünür ve şifrelenir. Bu, halka açık ağlarda paket dinleme (sniffing) saldırılarına karşı etkili bir korumadır. Ticari bir VPN'e göre tek dezavantajı sadece SOCKS destekleyen uygulamaları kapsamasıdır; sistem genelinde tüm trafiği yönlendirmek isterseniz tun2socks gibi ek bir araçla işletim sistemi seviyesinde yönlendirme kurmanız gerekir. DNS sorgularının da tünelden geçtiğinden emin olun, aksi hâlde ziyaret ettiğiniz siteler DNS seviyesinde hâlâ görülebilir. Firefox'ta network.proxy.socks_remote_dns ayarını true yapmak bunu sağlar.

Sunucu tarafında bant genişliği veya CPU sınırlaması yoksa -D ile açılan proxy pratik olarak tüm masaüstü trafiğinizi taşıyabilir. Tünel kapandığında tarayıcının proxy ayarını unutup normal bağlantıyla devam etmediğinden emin olun; aksi hâlde şifresiz ağda çıplak trafiğe geri dönmüş olursunuz.

Tüneli kalıcı ve otomatik yeniden bağlanır hale nasıl getirirsiniz?

Bir tünel ağ kesintisinde kopar ve elle yeniden başlatmanız gerekir. Bunu otomatikleştirmek için autossh kullanışlıdır.

sudo apt install autossh
autossh -M 0 -f -N -L 5433:localhost:5432 kullanici@sunucu-ip

-M 0, eski izleme portunu devre dışı bırakır ve bunun yerine SSH'in kendi ServerAliveInterval mekanizmasına güvenir; günümüz autossh kurulumlarında önerilen yöntem budur. ServerAliveInterval ve ServerAliveCountMax ayarlarını ~/.ssh/config dosyasına eklemek, kopan bağlantıların daha hızlı tespit edilmesini sağlar:

Host sunucu-ip
    ServerAliveInterval 30
    ServerAliveCountMax 3

Bu yapılandırma 30 saniyede bir sunucuya canlılık sinyali gönderir. Üç deneme başarısız olursa bağlantıyı kopmuş sayar ve autossh yeniden bağlanır.

Kalıcı tüneller için systemd servisi olarak tanımlamak, sunucu yeniden başladığında tünelin otomatik ayağa kalkmasını sağlar ve elle başlatmayı unutma riskini ortadan kaldırır:

[Unit]
Description=SSH tunnel - veritabani
After=network.target

[Service]
ExecStart=/usr/bin/autossh -M 0 -N -L 5433:localhost:5432 kullanici@sunucu-ip
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

Bu dosyayı /etc/systemd/system/ssh-tunnel-db.service olarak kaydedip sudo systemctl enable --now ssh-tunnel-db çalıştırmak, tüneli sıradan bir sistem servisi gibi yönetmenizi sağlar. Durumunu systemctl status ile, loglarını journalctl -u ssh-tunnel-db ile görebilirsiniz. Restart=always satırı tünel herhangi bir sebeple kapanırsa systemdnin onu otomatik yeniden başlatmasını garanti eder; bu da autosshin kendi izleme mekanizmasına ikinci bir güvence katmanı ekler.

SSH config dosyası tünelleri nasıl basitleştirir?

Uzun komutları her seferinde yazmak yerine ~/.ssh/config dosyasında takma adlar tanımlayabilirsiniz.

Jump host üzerinden iki katmanlı SSH bağlantı zinciri şeması
Host db-tunnel
    HostName sunucu-ip
    User kullanici
    LocalForward 5433 localhost:5432
    ServerAliveInterval 30

Bu tanımdan sonra sadece ssh db-tunnel yazmak hem bağlantıyı kurar hem de yönlendirmeyi otomatik uygular. Birden fazla portu aynı anda yönlendirmek isterseniz LocalForward satırını tekrarlayabilirsiniz; her tünel için ayrı bir satır yeterlidir. IdentityFile satırıyla belirli bir SSH anahtarını da bu tanıma bağlayabilirsiniz. Birden fazla sunucu için farklı anahtarlar kullanıyorsanız bu, doğru anahtarı elle belirtmeyi unutma riskini ortadan kaldırır.

BayrakYönTipik kullanım
-LUzak servisi yerel porta getirirUzak veritabanına/panele erişim
-RYerel servisi uzağa açarNAT arkasındaki makineyi paylaşma
-DGenel SOCKS proxy kurarGüvensiz ağda tüm trafiği şifreleme

Jump host üzerinden çok katmanlı tünel nasıl kurulur?

Bazı ağlarda hedef sunucuya doğrudan erişemezsiniz, önce bir ara sunucudan (jump host / bastion) geçmeniz gerekir. -J bayrağı bunu tek satırda çözer:

ssh -J bastion-kullanici@bastion-ip hedef-kullanici@ic-sunucu-ip

Bu komut önce bastion-ipye bağlanır, oradan ic-sunucu-ipye SSH açar; aradaki tüm trafik iki ayrı SSH oturumu üzerinden şifreli akar. Eskiden bu işi ProxyCommand ile yapmak gerekiyordu; -J bayrağı OpenSSH 7.3'ten beri aynı işi çok daha okunur bir sözdizimiyle yapıyor. Birden fazla bastion üzerinden geçmeniz gerekiyorsa virgülle ayırarak zincirleyebilirsiniz: ssh -J bastion1,bastion2 hedef-sunucu. Bu durumda her adım kendi kimlik doğrulamasını ayrı ayrı ister. ~/.ssh/config içinde de tanımlanabilir:

Host ic-sunucu
    HostName ic-sunucu-ip
    User hedef-kullanici
    ProxyJump bastion-kullanici@bastion-ip

Bu tanım sayesinde ssh ic-sunucu yazmak, jump host üzerinden otomatik geçiş yapar. Port yönlendirme satırlarını da aynı bloğa ekleyip iç ağdaki bir veritabanına bastion üzerinden tek adımda tünel açabilirsiniz.

Çok katmanlı bir tünelde her sıçrama noktası ayrı bir SSH oturumu açar, bu da gecikmeyi (latency) biraz artırır. Üç dört sunucu üzerinden geçen bir tünelde bu fark hissedilir hâle gelebilir. Düşük gecikme gerektiren kritik işler için jump host sayısını mümkün olduğunca az tutmak, tünelin pratik kullanılabilirliğini korur.

Hangi yöntemi seçeceğinize karar verirken basit bir soru sorun: veriyi kendinize mi getiriyorsunuz, kendinizi mi dışarı açıyorsunuz, yoksa tüm trafiği mi şifrelemek istiyorsunuz? Cevap sırasıyla -L, -R ve -Dye işaret eder. Çoğu gündelik ihtiyaç bu üç bayraktan biriyle, ek araç kurmadan çözülür. Bir seçeneğin tam davranışından emin değilseniz man ssh_config kılavuz sayfası tüm bu ayarların listesini ve varsayılan değerlerini içerir.

Celil Uyanikoglu

Yazan Celil Uyanikoglu

Bilgisayar mühendisiyim; 25 yılı aşkın süredir bilgi işlem sektörünün içindeyim. Bu blogu 2020'de, işimde her gün karşılaştığım sorunların çözümlerini bir yere yazmak için açtım: Linux, güvenlik, tarayıcılar, yapay zeka araçları. Yazdığım her rehberi önce kendi bilgisayarımda ya da sunucumda deniyorum; çalıştığını görmediğim adımı yayınlamam. Hatalı ya da eskimiş bir şey görürsen iletişim sayfasından yaz — düzeltirim.

Yorum

Henüz yorum yok.

Sohbete katıl. Yorumlar yayınlanmadan önce moderasyondan geçer.

Yorum yap

E-posta adresin yayınlanmaz. Yorumlar moderasyondan sonra yayınlanır.

Sırada

İlgili notlar

jekcms 61602b0e6293b42004a1