Nginx ve Cloudflare SSL Sorunları: Tanılama ve Çözüm Rehberi
Üretim ortamında Nginx arkasında Cloudflare kullanan bir sunucuyu yönetiyorsanız, eninde sonunda o meşhur SSL sorunlarıyla karşılaşırsınız. Kimi zaman tarayıcı “ERR_TOO_MANY_REDIRECTS” hatasıyla çıldırır, kimi zaman sertifika uyuşmazlığı yaşarsınız, kimi zaman da Cloudflare’den gelen trafik Nginx tarafında düzgün işlenmez. Bu yazıda bu sorunların neden kaynaklandığını, nasıl teşhis edileceğini ve nasıl düzeltileceğini gerçek senaryolar üzerinden anlatacağım.
Temel Mimariyi Anlamak
Sorunları çözmeden önce trafiğin nasıl aktığını kafada netleştirmek gerekiyor. Cloudflare kullandığınızda iki ayrı SSL katmanı var:
- Ziyaretçi -> Cloudflare: Bu bağlantı Cloudflare’in sertifikasıyla şifreleniyor
- Cloudflare -> Nginx sunucunuz: Bu bağlantı ise sizin sunucunuzda ne yapılandırdığınıza göre değişiyor
Cloudflare’in SSL/TLS ayarlarında dört mod var:
- Off: Şifreleme yok, her şey HTTP
- Flexible: Ziyaretçi ile Cloudflare arası HTTPS, Cloudflare ile sunucu arası HTTP
- Full: Her iki taraf da HTTPS, ama sunucu sertifikası doğrulanmıyor
- Full (Strict): Her iki taraf da HTTPS ve sunucu sertifikası geçerli olmalı
İşte sorunların büyük çoğunluğu bu modların yanlış yapılandırılmasından ya da Nginx konfigürasyonuyla uyumsuzluğundan çıkıyor.
En Sık Karşılaşılan Sorun: Sonsuz Yönlendirme Döngüsü
Bu sorun genellikle şu senaryoda ortaya çıkıyor: Cloudflare SSL modu Flexible ayarlanmış, Nginx de HTTP trafiğini HTTPS’e yönlendiriyor. Ne oluyor? Cloudflare sunucunuza HTTP olarak bağlanıyor, Nginx bunu HTTPS’e yönlendiriyor, Cloudflare tekrar HTTP olarak bağlanıyor… Döngü başladı.
Nginx loglarına baktığınızda şunu görürsünüz:
tail -f /var/log/nginx/access.log | grep "301|302"
Çıktıda aynı IP’den (Cloudflare IP’leri) sürekli 301 yönlendirmesi göreceksiniz:
2024-01-15 14:23:45 103.21.244.0 - GET / HTTP/1.1 301
2024-01-15 14:23:45 103.21.244.0 - GET / HTTP/1.1 301
2024-01-15 14:23:45 103.21.244.0 - GET / HTTP/1.1 301
Çözüm 1: Cloudflare SSL Modunu Değiştir
En basit çözüm Cloudflare panelinden SSL/TLS modunu Full veya Full (Strict) olarak ayarlamak. Ama sunucunuzda geçerli bir SSL sertifikası yoksa Full (Strict) çalışmaz.
Çözüm 2: Nginx’te HTTP’den HTTPS Yönlendirmesini Cloudflare’e Göre Ayarla
Eğer Flexible mod kullanmak zorundaysanız (örneğin sunucuda sertifika kuramıyorsunuz), Nginx’teki HTTPS yönlendirmesini Cloudflare trafiği için devre dışı bırakmanız gerekiyor. Bunun için X-Forwarded-Proto header’ını kullanabilirsiniz:
server {
listen 80;
server_name example.com www.example.com;
# Cloudflare Flexible mod için: X-Forwarded-Proto kontrolü
if ($http_x_forwarded_proto = "http") {
return 301 https://$host$request_uri;
}
# Geri kalan konfigürasyon buraya
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Ama dürüst olalım: Production ortamında Full (Strict) modunu kullanmanızı şiddetle tavsiye ederim. Bunun için Let’s Encrypt ile ücretsiz sertifika alabilirsiniz.
Cloudflare Origin Certificate Kullanımı
Full (Strict) modunu kullanacaksanız iki seçeneğiniz var: Let’s Encrypt sertifikası ya da Cloudflare Origin Certificate. Origin Certificate’ın avantajı 15 yıla kadar geçerli olması ve yenileme zahmetiyle uğraşmamanız. Dezavantajı ise sadece Cloudflare üzerinden gelen trafikte geçerli olması.
Cloudflare panelinden Origin Certificate oluşturduktan sonra:
# Sertifika dosyalarını oluştur
mkdir -p /etc/nginx/ssl/cloudflare
nano /etc/nginx/ssl/cloudflare/origin.crt
# Cloudflare'den kopyaladığınız sertifikayı yapıştırın
nano /etc/nginx/ssl/cloudflare/origin.key
# Private key'i yapıştırın
# Dosya izinlerini ayarla
chmod 600 /etc/nginx/ssl/cloudflare/origin.key
chmod 644 /etc/nginx/ssl/cloudflare/origin.crt
Nginx konfigürasyonu:
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/cloudflare/origin.crt;
ssl_certificate_key /etc/nginx/ssl/cloudflare/origin.key;
# Güvenli SSL ayarları
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
# HSTS (Cloudflare zaten ekliyor ama yine de koymakta fayda var)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Gerçek IP Adresini Almak: CF-Connecting-IP Sorunu
Cloudflare kullandığınızda Nginx loglarında tüm istekler Cloudflare IP adreslerinden geliyormuş gibi görünür. Bu hem log analizi için hem de IP bazlı rate limiting için sorun yaratır.
Log dosyanıza bakın:
grep -E "^[0-9]" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20
Tüm istekler muhtemelen 103.x.x.x veya 172.x.x.x gibi Cloudflare IP aralıklarından geliyor olacak.
ngx_http_realip_module ile Gerçek IP Alımı
# Modülün yüklü olup olmadığını kontrol et
nginx -V 2>&1 | grep real_ip
Nginx konfigürasyonuna ekleyin:
# /etc/nginx/conf.d/cloudflare-realip.conf
# Cloudflare IPv4 aralıkları
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
# Cloudflare IPv6 aralıkları
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
# CF-Connecting-IP header'ını kullan
real_ip_header CF-Connecting-IP;
Değişiklikleri uygulayın:
nginx -t && systemctl reload nginx
Artık loglarınızda gerçek ziyaretçi IP adresleri görünecek.
SSL Handshake Hatalarını Teşhis Etmek
Bazen Cloudflare ile Nginx arasında SSL handshake başarısız olur. Bu durumda Cloudflare size 502 ya da 525 hata kodları döner. 525 hata kodu özellikle “SSL Handshake Failed” anlamına gelir.
Nginx error logunu inceleyin:
tail -n 100 /var/log/nginx/error.log | grep -i "ssl|handshake|certificate"
Tipik hata satırları şöyle görünür:
2024/01/15 14:30:22 [warn] 12345#0: *1 SSL_do_handshake() failed
(SSL: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate)
while SSL handshaking, client: 103.21.244.15, server: 0.0.0.0:443
Bu hatanın en sık nedeni sertifika dosyasının bozuk olması ya da private key ile sertifikanın eşleşmemesidir. Kontrol etmek için:
# Sertifika ve key'in eşleşip eşleşmediğini kontrol et
openssl x509 -noout -modulus -in /etc/nginx/ssl/cloudflare/origin.crt | md5sum
openssl rsa -noout -modulus -in /etc/nginx/ssl/cloudflare/origin.key | md5sum
# İkisi de aynı MD5 hash'ini vermeliydi, farklıysa eşleşmiyorlar demektir
Sertifika geçerlilik tarihini kontrol etmek için:
openssl x509 -noout -dates -in /etc/nginx/ssl/cloudflare/origin.crt
Authenticated Origin Pulls ile Güvenliği Artırmak
Cloudflare kullanıyorsunuz ama birisi Cloudflare’i bypass edip doğrudan sunucu IP’nize bağlanabilir. Bu hem güvenlik açığı hem de Cloudflare’in sağladığı DDoS korumасını devre dışı bırakır.
Cloudflare’in Authenticated Origin Pulls özelliği, sunucunuza sadece Cloudflare’den gelen isteklerin ulaşmasını sağlar. Bunu Nginx’te mTLS (mutual TLS) ile yapılandırabilirsiniz.
Önce Cloudflare’in CA sertifikasını indirin:
curl -o /etc/nginx/ssl/cloudflare-ca.pem
https://developers.cloudflare.com/ssl/static/authenticated_origin_pull_ca.pem
Nginx konfigürasyonuna ekleyin:
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/nginx/ssl/cloudflare/origin.crt;
ssl_certificate_key /etc/nginx/ssl/cloudflare/origin.key;
# Authenticated Origin Pulls
ssl_client_certificate /etc/nginx/ssl/cloudflare-ca.pem;
ssl_verify_client on;
# Client certificate doğrulaması başarısız olursa 403 dön
if ($ssl_client_verify != SUCCESS) {
return 403;
}
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Cloudflare panelinden SSL/TLS > Origin Server sekmesinde “Authenticated Origin Pulls” özelliğini etkinleştirmeyi unutmayın.
Test etmek için:
# Cloudflare üzerinden gelen istek (başarılı olmalı)
curl -I https://example.com
# Doğrudan sunucu IP'sine istek (403 vermeli veya bağlantı reddedilmeli)
curl -I https://SUNUCU_IP --resolve example.com:443:SUNUCU_IP
Nginx’te SSL Sertifika Yenileme Sorunları
Let’s Encrypt kullanıyorsanız ve Cloudflare proxy arkasındaysanız, certbot’un HTTP-01 challenge’ı geçmesi bazen sorun çıkarır. Çünkü .well-known/acme-challenge/ yoluna gelen istek Cloudflare üzerinden gelir.
Çözüm, bu path için Cloudflare proxy’sini atlatmak ya da DNS-01 challenge kullanmaktır. Ama en pratik yol Nginx konfigürasyonunda bu path için özel bir ayar yapmak:
server {
listen 80;
server_name example.com;
# Let's Encrypt için bu location'ı Cloudflare proxy'sinden geçirme
location /.well-known/acme-challenge/ {
root /var/www/certbot;
allow all;
}
location / {
return 301 https://$host$request_uri;
}
}
Certbot’u çalıştırmadan önce Cloudflare’de o domain için SSL modunu geçici olarak Flexible‘a alın ya da DNS kaydını “DNS only” (gri bulut) moduna alın. Sertifikayı aldıktan sonra tekrar proxy moduna geçirin.
Alternatif olarak Certbot DNS plugin’ini kullanabilirsiniz:
# Cloudflare DNS plugin'ini kur
pip3 install certbot-dns-cloudflare
# Cloudflare API credentials dosyası oluştur
mkdir -p /etc/letsencrypt/cloudflare
cat > /etc/letsencrypt/cloudflare/credentials.ini << EOF
dns_cloudflare_api_token = CLOUDFLARE_API_TOKEN_BURAYA
EOF
chmod 600 /etc/letsencrypt/cloudflare/credentials.ini
# Sertifika al
certbot certonly
--dns-cloudflare
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini
-d example.com
-d www.example.com
Bu yöntemle Nginx’te herhangi bir değişiklik yapmadan, doğrudan DNS üzerinden doğrulama yapılır. Cloudflare proxy açık olsa bile çalışır.
Log Analiziyle Sorun Tespiti
SSL sorunlarını teşhis ederken Nginx loglarını iyi okumak çok önemli. Debug level log açmak için:
# /etc/nginx/nginx.conf içinde
error_log /var/log/nginx/error.log debug;
Dikkat: Debug log çok fazla veri üretir, sadece sorun tespiti sırasında açın.
Cloudflare kaynaklı istekleri filtrelemek için:
# Cloudflare IP aralığından gelen 5xx hatalarını bul
awk '$1 ~ /^(173.245.|103.21.|103.22.)/ && ($9 ~ /^5/)'
/var/log/nginx/access.log | tail -50
SSL ile ilgili hataları error log’dan çekmek için:
# Son 1 saatteki SSL hatalarını görüntüle
awk -v d="$(date -d '1 hour ago' '+%Y/%m/%d %H:%M')"
'$0 >= d' /var/log/nginx/error.log | grep -i ssl
Cloudflare’in sunucunuza hangi SSL protokolüyle bağlandığını kontrol etmek için:
# Nginx loglarına SSL protokolü ve cipher bilgisi ekle
log_format cloudflare_ssl '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'ssl_protocol=$ssl_protocol '
'ssl_cipher=$ssl_cipher '
'cf_ray=$http_cf_ray '
'cf_connecting_ip=$http_cf_connecting_ip';
Mixed Content Sorunu
HTTPS’e geçtikten sonra sayfada bazı kaynaklar hala HTTP üzerinden yükleniyorsa tarayıcı “Mixed Content” uyarısı verir. Cloudflare’in Automatic HTTPS Rewrites özelliği bunu kısmen çözer ama Nginx tarafında da önlem almak gerekebilir.
Nginx üzerinde bunu yakalamak için:
# HTTP kaynak içeren sayfaları tespit et (CSP report)
grep "Content-Security-Policy" /var/log/nginx/access.log | head -20
Nginx konfigürasyonunda tüm HTTP referanslarını HTTPS’e çevirmek için header ekleyebilirsiniz:
server {
listen 443 ssl http2;
server_name example.com;
# Mixed content sorunlarını Cloudflare'in çözmesine izin ver
# Aynı zamanda upgrade-insecure-requests ekle
add_header Content-Security-Policy "upgrade-insecure-requests" always;
# Ek güvenlik headerları
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options SAMEORIGIN always;
add_header Referrer-Policy strict-origin-when-cross-origin always;
location / {
proxy_pass http://localhost:3000;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
Yaygın Hataların Hızlı Referans Listesi
Cloudflare hata kodlarını ve Nginx tarafındaki karşılıklarını bilmek sorun tespitini hızlandırır:
- Cloudflare 520: Nginx’ten beklenmedik yanıt. Nginx’in çöktüğü ya da bağlantıyı reset ettiği durumlarda olur.
systemctl status nginxve error loglarını kontrol edin.
- Cloudflare 521: Nginx’e bağlantı kurulamıyor. Port 443 dinlenmiyor ya da firewall engelliyor.
ss -tlnp | grep :443ile kontrol edin.
- Cloudflare 522: Bağlantı zaman aşımı. Nginx yavaş mı, upstream yavaş mı?
proxy_connect_timeoutveproxy_read_timeoutdeğerlerini artırın.
- Cloudflare 524: Uzun süren istek zaman aşımına uğradı. Nginx tarafında timeout değerlerini artırın.
- Cloudflare 525: SSL handshake başarısız. Sertifika geçerli mi, cipher uyumlu mu kontrol edin.
- Cloudflare 526: Geçersiz SSL sertifikası. Full (Strict) moddaysanız sertifikanın geçerli ve imzalı olması gerekiyor.
- ERR_TOO_MANY_REDIRECTS: Döngüsel yönlendirme. Cloudflare SSL modu ve Nginx redirect ayarlarını kontrol edin.
Sonuç
Nginx ile Cloudflare kombinasyonu doğru kurulduğunda son derece güçlü ve güvenli bir altyapı oluşturuyor. Sorunların büyük çoğunluğu iki katmanlı SSL mimarisinin yeterince anlaşılmamasından kaynaklanıyor. Özetle dikkat etmeniz gereken ana noktalar:
Cloudflare SSL modunu gerçekten ihtiyacınıza göre seçin, mümkünse Full (Strict) kullanın. Origin Certificate ya da Let’s Encrypt ile geçerli bir sertifika kurun. Sonsuz yönlendirme döngüsü yaşıyorsanız ilk bakacağınız yer Cloudflare SSL modu ve Nginx redirect konfigürasyonu olmalı. Gerçek IP alımı için ngx_http_realip_module‘ü mutlaka yapılandırın, yoksa log analizi ve rate limiting düzgün çalışmaz. Authenticated Origin Pulls ile doğrudan sunucu IP’nize gelen trafiği engelleyin. Log analizini ihmal etmeyin: Hem Nginx error log hem de access log, sorunların nerede olduğunu size açıkça söylüyor.
Bu adımları uyguladığınızda Cloudflare ile Nginx arasındaki SSL sorunlarının büyük çoğunluğunu çözebilir ve daha sağlam bir yapıya kavuşabilirsiniz.
