Tarayıcıda "Bu site güvenli bir bağlantı sağlayamıyor" yazıyor, altında da ERR_SSL_PROTOCOL_ERROR. SSL protokol hatası, tarayıcı ile sunucunun güvenli bağlantı kurmak için yaptıkları el sıkışmanın (TLS handshake) ortada koptuğunu gösterir. Dikkat edin: bu, sertifikanın süresi dolduğunu ya da alan adının uyuşmadığını söyleyen bir uyarı değildir — o durumlarda tarayıcı size "Devam et" seçeneği sunar. Burada devam seçeneği bile yoktur, çünkü şifreli kanal hiç kurulamamıştır.
Türkçe kaynaklarda bu hata için verilen tavsiye hemen her zaman ziyaretçi tarafında kalıyor: önbelleği temizleyin, tarihi düzeltin, antivirüsün SSL taramasını kapatın. Bu adımlar tek bir kullanıcıda çıkan hata için işe yarar; ama siteniz hiç kimsede açılmıyorsa sunucu tarafında bakmanız gerekir ve orada bakılacak yerler bellidir: TLS sürüm uyumsuzluğu, şifre takımı uyuşmazlığı, SNI'siz sanal host yapılandırması ve 443 portunda yanlış servis. Bu yazıda openssl s_client ile el sıkışmayı adım adım okumayı ve her senaryoyu birbirinden ayırmayı göstereceğim.
ERR_SSL_PROTOCOL_ERROR Tam Olarak Neyi Söylüyor#
Bu hata, TCP bağlantısının kurulduğunu ama TLS el sıkışmasının tamamlanamadığını söyler. Yani sunucuya ulaşıldı, 443 portu açıktı, ancak iki taraf ortak bir protokol sürümü ve şifre takımında anlaşamadı ya da sunucudan gelen cevap geçerli bir TLS mesajı değildi.
El sıkışma kabaca şöyle işler: istemci ClientHello gönderir ve desteklediği TLS sürümlerini, şifre takımlarını ve bağlanmak istediği sunucu adını (SNI) bildirir. Sunucu ServerHello ile seçtiği sürümü ve şifre takımını, ardından sertifikasını gönderir. Bu adımlardan herhangi biri başarısız olursa bağlantı kapanır. Sürecin ayrıntısı tls handshake nasıl çalışır yazısında adım adım anlatılıyor.
Önemli bir ayrım: bu hata sertifikanın içeriğiyle ilgili değildir. Sertifikanın süresi dolmuşsa NET::ERR_CERT_DATE_INVALID, alan adı uyuşmuyorsa NET::ERR_CERT_COMMON_NAME_INVALID, zincir eksikse NET::ERR_CERT_AUTHORITY_INVALID görürsünüz. Bu kodları alıyorsanız bağlantınız gizli değil hatası yazısına geçin; buradaki senaryolar sizi ilgilendirmez.
Sunucu Tarafında İlk Test: openssl s_client#
Tahmin yürütmeyi bırakıp el sıkışmanın gerçekte nerede koptuğunu görmenin tek yolu budur. Sunucudan ya da herhangi bir Linux/macOS makinesinden çalıştırın:
openssl s_client -connect ornek.com:443 -servername ornek.com
-servername parametresi SNI uzantısını gönderir ve kritiktir; onsuz sunucu varsayılan sanal hostun sertifikasını verir ve yanlış teşhis koyarsınız. Başarılı bir çıktının başında şunu görmelisiniz:
CONNECTED(00000003)
depth=2 C = US, O = ..., CN = ...
---
Certificate chain
0 s:CN = ornek.com
i:C = US, O = Let's Encrypt, CN = R11
1 s:C = US, O = Let's Encrypt, CN = R11
i:C = US, O = Internet Security Research Group, CN = ISRG Root X1
---
SSL handshake has read 4321 bytes and written 401 bytes
Verify return code: 0 (ok)
Sorunlu çıktılar ve anlamları:
| openssl çıktısı | Neyi gösterir | Nereye bakılacak |
|---|---|---|
no protocols available | Ortak TLS sürümü yok | Sunucudaki ssl_protocols / SSLProtocol |
sslv3 alert handshake failure | Şifre takımı uyuşmazlığı | ssl_ciphers listesi |
wrong version number | 443'te TLS konuşmayan bir servis var | Servis/port yapılandırması |
unable to get local issuer certificate | Ara sertifika eksik | Zincir dosyası |
| Boş yanıt, bağlantı hemen kapanıyor | Güvenlik duvarı ya da IP engeli | Firewall, fail2ban |
| Sertifika CN'si başka alan adı | SNI yapılandırması hatalı | Sanal host tanımları |
Belirli bir sürümü zorlayarak sınırı bulabilirsiniz:
openssl s_client -connect ornek.com:443 -servername ornek.com -tls1_2
openssl s_client -connect ornek.com:443 -servername ornek.com -tls1_3
Hangi sürümlerin ve şifre takımlarının desteklendiğini toplu görmek için:
nmap --script ssl-enum-ciphers -p 443 ornek.com
openssl komutlarının genel kullanımını openssl komutları yazısında bulabilirsiniz.
TLS Sürüm Uyumsuzluğu ve Eski İstemcilerin Düşmesi#
En sık sunucu kaynaklı sebep budur ve genelde iyi niyetli bir güvenlik sıkılaştırmasından sonra ortaya çıkar. TLS 1.0 ve 1.1 artık güvenli kabul edilmediği için kapatılır; ama bu kapatma, o sürümlerden başkasını konuşamayan istemcileri tamamen dışarıda bırakır.
Pratikte kimler düşer:
- Çok eski Android sürümlerindeki yerleşik tarayıcılar ve uygulama içi WebView'lar
- Güncellenmemiş Windows kurulumlarındaki eski Internet Explorer sürümleri
- Ödeme terminalleri, kiosk cihazları, IP kameralar gibi gömülü sistemler
- Eski PHP kurulumlarındaki
cURL/OpenSSL kütüphaneleriyle sitenize istek atan diğer sunucular — ki bu, ödeme sağlayıcı ya da kargo entegrasyonlarının sessizce bozulmasının tipik sebebidir
Sunucuda geçerli yapılandırmayı okuyun. Nginx tarafında:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
Apache tarafında:
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
Değişiklikten önce sözdizimini doğrulayın (nginx -t ya da apachectl configtest), sonra servisi yeniden yükleyin. Yapılandırmanın tamamı için nginx ssl yapılandırma ve apache ssl yapılandırma yazılarına bakabilirsiniz. TLS 1.3'ün getirdikleri ise tls 1.3 nedir yazısında.
Geçiş kararını verirken şunu ölçün: erişim kayıtlarınızda TLS sürümünü loglayın, birkaç gün bekleyin ve gerçekten kaç isteğin eski sürüm kullandığını görün. Nginx'te log formatına $ssl_protocol ekleyerek bu veriyi toplayabilirsiniz:
log_format tlslog '$remote_addr $ssl_protocol $ssl_cipher "$request"';
access_log /var/log/nginx/tls.log tlslog;
Şifre Takımı Uyuşmazlığı#
TLS sürümü uyuşsa bile taraflar ortak bir şifre takımında anlaşamazsa el sıkışma handshake failure ile kopar. Bu, sıkılaştırma sırasında şifre listesini fazla daraltmaktan ya da sertifika tipiyle listeyi uyumsuz bırakmaktan kaynaklanır.
Klasik tuzak şudur: sertifikanız RSA anahtar kullanıyorken şifre listesinde yalnızca ECDSA takımlarını bırakmak. Sunucu sertifikasıyla eşleşen tek bir takım bile bulamaz ve bağlantı kopar. Sertifika tipi farkı için ecc vs rsa sertifika yazısına bakın.
Hangi takımın seçildiğini görmek için:
openssl s_client -connect ornek.com:443 -servername ornek.com 2>/dev/null | grep -E "Protocol|Cipher"
Listeyi daraltırken hem ECDSA hem RSA varyantlarını bırakmak en güvenli yaklaşımdır. Yapılandırmanın dış dünyadan nasıl göründüğünü doğrulamak isterseniz ssl labs testi yazısı testin nasıl okunacağını anlatıyor.
SNI Sorunu: Aynı IP'de Yanlış Sertifika Sunulması#
Bu, paylaşımlı ortamlarda ve tek IP üzerinde birden çok siteyi barındıran sunucularda en çok kafa karıştıran senaryodur. SNI (Server Name Indication), istemcinin el sıkışmanın en başında "ben şu alan adına bağlanmak istiyorum" demesini sağlayan TLS uzantısıdır. Sunucu bu bilgiye bakarak doğru sanal hostun sertifikasını sunar.
İki şekilde bozulur:
1. Sunucuda SNI'ye uygun sanal host tanımı yok. Alan adı için ayrı bir server / VirtualHost bloğu tanımlanmamışsa, sunucu 443 portundaki ilk bloğun sertifikasını sunar. Ziyaretçi başka bir siteye ait sertifikayı alır. Bunu şöyle kanıtlarsınız:
# SNI ile
openssl s_client -connect 185.0.0.1:443 -servername ornek.com 2>/dev/null | openssl x509 -noout -subject
# SNI olmadan
openssl s_client -connect 185.0.0.1:443 2>/dev/null | openssl x509 -noout -subject
İki çıktı farklıysa SNI çalışıyor demektir. Aynıysa ve gelen sertifika başka bir alan adına aitse, o alan adı için sanal host tanımı eksiktir. Apache'de sanal host kurulumu apache virtual host tanımlama yazısında.
2. İstemci SNI göndermiyor. Çok eski istemciler ve bazı gömülü kütüphaneler SNI uzantısını hiç göndermez. Bu istemciler paylaşımlı IP'deki bir siteye bağlanamaz; onlar için tek çözüm siteye ayrılmış (dedicated) bir IP tahsis etmektir. SNI'nin çalışma mantığı sni nedir yazısında ayrıntılı.
Nginx'te doğru yapı, her alan adı için server_name ve kendi sertifikasıyla ayrı bir blok tanımlamaktır:
server {
listen 443 ssl http2;
server_name ornek.com www.ornek.com;
ssl_certificate /etc/letsencrypt/live/ornek.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ornek.com/privkey.pem;
}
Eksik Ara Sertifika ve Zincir Sorunları#
Sertifika zinciri eksikse çoğu tarayıcı sertifika hatası verir, ancak bazı istemciler ve özellikle sunucudan sunucuya yapılan isteklerde bu durum protokol hatası gibi görünebilir. Zinciri doğrulayın:
openssl s_client -connect ornek.com:443 -servername ornek.com -showcerts 2>/dev/null | grep -E "^ [0-9] s:|^ [0-9] i:"
Çıktıda yalnızca 0 numaralı sertifika varsa ara sertifika sunulmuyor demektir. Çözüm, sunucuya sertifikayı tek başına değil tam zincir dosyasıyla (fullchain.pem) tanıtmaktır. Let's Encrypt kullanıyorsanız cert.pem yerine fullchain.pem gösterin. Konu ara sertifika hatası ve sertifika zinciri nedir yazılarında derinlemesine işleniyor.
Sertifika ile özel anahtarın eşleştiğini de doğrulayın; eşleşmeyen bir çift el sıkışmayı hemen düşürür:
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in privkey.pem | openssl md5
İki hash aynı olmalıdır. Farklıysa yanlış anahtar dosyasını yapılandırmışsınızdır.
443 Portunda HTTPS Konuşmayan Servis#
wrong version number hatası alıyorsanız neredeyse kesin sebep budur: 443 portunda dinleyen servis TLS değil düz HTTP konuşuyordur. En sık iki hâli vardır — sanal hosta SSLEngine on / ssl parametresi eklenmemiş olması, ya da bir ters vekilin arka uca yanlış portta bağlanması.
Portta ne olduğunu doğrudan test edin:
curl -v http://ornek.com:443 2>&1 | head -20
Bu komut düz HTTP isteği gönderir; sunucu anlamlı bir HTTP cevabı veriyorsa 443'te TLS yok demektir. Portun gerçekten dinlendiğini ve hangi süreç tarafından dinlendiğini görmek için:
ss -lntp | grep ':443'
Nginx'te blokta listen 443 ssl; yazdığından, Apache'de <VirtualHost *:443> içinde SSLEngine on bulunduğundan emin olun. Port ve servis eşleşmesini incelemek için açık portları listeleme yazısı yardımcı olur.
Paylaşımlı Hosting Kullanıyorsanız Neye Bakabilirsiniz#
Paylaşımlı hostingde ssl_protocols ya da SSLCipherSuite gibi sunucu geneli ayarlara erişiminiz yoktur; o katman sağlayıcının sorumluluğundadır. Ancak yine de kontrol edebileceğiniz üç şey var ve destek talebi açmadan önce bunlara bakmak çoğu vakayı kapatır.
Birincisi, alan adı için sertifikanın gerçekten kurulu olup olmadığıdır. cPanel'de Güvenlik → SSL/TLS → Manage SSL sites ekranında alan adınızın listede ve geçerli bir sertifikayla eşleşmiş olması gerekir. Yeni eklenen bir addon domain ya da alt alan adı için sertifika otomatik kurulmamış olabilir; o zaman 443 portundaki istek varsayılan sanal hosta düşer ve yukarıdaki SNI senaryosu devreye girer.
İkincisi, alan adının DNS'te doğru sunucuyu gösterdiğidir. Alan adı hâlâ eski sunucunuza çözümleniyorsa yeni sunucudaki sertifikanın hiçbir önemi yoktur; dig ornek.com A +short çıktısını hesabınızın IP'siyle karşılaştırın.
Üçüncüsü, alt alan adlarıdır. Wildcard olmayan bir sertifika ornek.com ve www.ornek.com için geçerliyken panel.ornek.com için geçerli değildir. Bu durumda ilgili alt alan adı için ayrı bir sertifika istemeniz gerekir.
Destek talebi açacaksanız openssl s_client çıktısının ilk yirmi satırını ve testi yaptığınız saati birlikte iletin; bu, teşhis süresini gözle görülür biçimde kısaltır.
Ziyaretçi Tarafı Nedenleri#
Hata sadece bir kullanıcıda çıkıyorsa — yani openssl s_client sunucudan temiz bir el sıkışma alıyorsa — sıra istemci tarafındadır:
- Sistem saati yanlış. Sertifika geçerlilik aralığı saatle karşılaştırılır; saat çok ileri ya da geride ise doğrulama başarısız olur. Saati otomatik eşitlemeye alın.
- Antivirüs / güvenlik yazılımı SSL taraması. Bu yazılımlar bağlantıyı araya girerek çözer ve kendi sertifikalarını sunar; uyumsuz yapılandırmalarda el sıkışmayı bozarlar. Geçici olarak "HTTPS taraması" özelliğini kapatıp test edin.
- Kurumsal proxy veya güvenlik duvarı. Şirket ağlarında TLS denetimi yapan cihazlar aynı etkiyi yaratır. Farklı bir ağdan (mobil veri) test etmek bu ihtimali dakikalar içinde eler.
- Eski tarayıcı. Güncellenmemiş bir tarayıcı, sunucunuzun desteklediği modern şifre takımlarını konuşamıyor olabilir.
- QUIC / HTTP-3 sorunu. Chrome'da
chrome://flagsüzerinden "Experimental QUIC protocol" seçeneğini devre dışı bırakıp test edin; ağ ekipmanı QUIC trafiğini bozuyorsa hata bu şekilde ortaya çıkabilir.
Sıkça Sorulan Sorular#
ERR_SSL_PROTOCOL_ERROR ile sertifika uyarısı arasındaki fark nedir#
Fark, hatanın hangi aşamada oluştuğudur. Sertifika uyarılarında güvenli kanal başarıyla kurulmuş, ancak sertifikanın süresi, alan adı ya da zinciri doğrulanamamıştır; bu yüzden tarayıcı size riski göze alıp devam etme seçeneği sunar. ERR_SSL_PROTOCOL_ERROR'da ise el sıkışma tamamlanamamıştır, ortada doğrulanacak bir kanal bile yoktur ve devam etme seçeneği görünmez. Bu ayrım teşhisi ikiye böler: birincisi sertifika içeriğine, ikincisi protokol ve şifre yapılandırmasına bakmayı gerektirir.
Hatanın sunucudan mı istemciden mi kaynaklandığını nasıl anlarım#
Sunucudan bağımsız bir makinede openssl s_client -connect ornek.com:443 -servername ornek.com komutunu çalıştırın. Komut temiz bir el sıkışma yapıp Verify return code: 0 (ok) döndürüyorsa sunucu tarafı sağlamdır ve sorun o kullanıcının bilgisayarında, ağında ya da güvenlik yazılımındadır. El sıkışma orada da kopuyorsa sorun sunucudadır ve çıktıdaki hata metni size hangi katmanda olduğunu doğrudan söyler. Ek doğrulama için mobil veri gibi tamamen farklı bir ağdan test edin.
TLS 1.0 ve 1.1 desteğini kapatırsam ne kaybederim#
Çok eski istemcilerin sitenize erişimini kaybedersiniz. Bunlar arasında güncellenmemiş Android cihazlardaki yerleşik tarayıcılar, eski Windows kurulumlarındaki Internet Explorer sürümleri, ödeme terminalleri gibi gömülü cihazlar ve eski OpenSSL kütüphanesiyle sitenize istek atan diğer sunucular bulunur. En sinsi etki bu sonuncusudur: entegrasyonlar sessizce bozulur ve kimse hemen fark etmez. Kapatmadan önce erişim kayıtlarınıza TLS sürümünü loglayıp birkaç gün gerçek trafiği ölçmek doğru karar için en sağlıklı yoldur.
openssl komutunda servername parametresi neden şart#
Çünkü bu parametre olmadan SNI uzantısı gönderilmez ve sunucu, o IP'deki varsayılan sanal hostun sertifikasını sunar. Paylaşımlı IP kullanan sunucularda bu, tamamen başka bir siteye ait sertifikayı görmenize ve yanlış teşhis koymanıza yol açar. Tarayıcılar SNI'yi her zaman gönderdiği için gerçek durumu ancak -servername ile test edebilirsiniz. Aynı komutu bir kez parametreyle bir kez parametresiz çalıştırıp çıktıları karşılaştırmak, SNI yapılandırmasının doğru olup olmadığını kesin biçimde gösterir.
Sertifika kurdum ama hata devam ediyor, neyi atladım#
Muhtemelen tam zincir dosyası yerine yalnızca sunucu sertifikasını tanıttınız ya da servisi yeniden yüklemediniz. Yapılandırmada cert.pem yerine fullchain.pem gösterildiğinden emin olun ve nginx -t veya apachectl configtest ile sözdizimini doğrulayıp servisi yeniden başlatın. Sertifika ile özel anahtarın modulus hash'lerini karşılaştırıp eşleştiklerini de doğrulayın. Ayrıca sanal host bloğunda listen 443 ssl ya da SSLEngine on satırının bulunduğunu kontrol edin.
Sitem Cloudflare arkasında, hata nereden gelir#
Cloudflare arkasındayken hata iki farklı katmandan gelebilir ve önce hangisi olduğunu ayırmanız gerekir. Ziyaretçi ile Cloudflare arasındaki bağlantı Cloudflare'ın sertifikasıyla kurulur; burada sorun çıkması nadirdir. Asıl olasılık, Cloudflare ile sizin sunucunuz arasındaki bağlantıdır: Full veya Full (strict) modundayken sunucuda geçerli bir sertifika yoksa ya da TLS yapılandırması bozuksa bağlantı kopar. DNS kaydını geçici olarak gri buluta çekip doğrudan sunucunuza bağlanarak hangi katmanın sorunlu olduğunu net biçimde ayırabilirsiniz.
Sadece mobil uygulamadan bağlanınca bu hatayı alıyorum#
Bu genellikle uygulamanın kullandığı TLS kütüphanesinin sunucunuzun desteklediği sürüm ya da şifre takımlarını konuşamamasından kaynaklanır. Mobil uygulamalar tarayıcıdan farklı bir TLS yığını kullanabilir ve eski cihazlarda bu yığın modern şifre takımlarını desteklemez. Ayrıca bazı uygulamalar sertifika sabitleme (certificate pinning) yapar; sertifikanız yenilendiğinde sabitlenen değer değiştiği için bağlantı reddedilir. nmap --script ssl-enum-ciphers çıktısıyla desteklenen takımları görüp uygulamanın minimum gereksinimleriyle karşılaştırmak doğru başlangıçtır.
Kapanış#
ERR_SSL_PROTOCOL_ERROR, ziyaretçi tarafında çözülmeye çalışıldığında en çok zaman kaybettiren hatalardan biridir; çünkü tavsiye edilen önbellek temizleme ve antivirüs kapatma adımları sunucu kaynaklı vakaların hiçbirini düzeltmez. Doğru yöntem tek bir komutla başlar: openssl s_client çıktısını okuyup el sıkışmanın hangi adımda koptuğunu görmek. Oradan sonra yol nettir — no protocols available sürüm yapılandırmasına, handshake failure şifre takımına, wrong version number 443 portundaki servise, yanlış sertifika ise SNI ve sanal host tanımlarına götürür.
Sertifika yenileme, zincir dosyası ve TLS yapılandırmasıyla her seferinde tek tek uğraşmak istemiyorsanız bu işi üstlenen bir ortam ciddi zaman kazandırır: SSL sertifikası tarafında kurulum ve yenileme sizin için yapılır, web hosting paketlerinde sertifika hesap açılışında otomatik kurulur ve tam zincir doğru biçimde tanıtılır. Kendi sunucusunu yöneten ekipler için sunucu yönetimi hizmeti Nginx/Apache TLS yapılandırmasını, şifre takımı listelerini ve eski sürüm kapatma geçişlerini gerçek trafik verisine bakarak planlar — böylece sıkılaştırma yaparken hangi entegrasyonun düşeceğini önceden bilirsiniz.