Apache ile Let’s Encrypt Sertifika Sorunları ve Çözümleri

Let’s Encrypt ile Apache’yi birlikte kullanmak kulağa kolay gelir, ve çoğu zaman öyledir. Ama bir şeyler ters gittiğinde, özellikle sertifika yenileme sessizce başarısız olduğunda ve bunu üç ay sonra sitenin HTTPS’i düşünce fark ettiğinizde, o an gerçekten can sıkıcıdır. Bu yazıda Apache üzerinde karşılaşılan yaygın Let’s Encrypt sorunlarını, hata mesajlarının ne anlama geldiğini ve bunları nasıl çözeceğinizi adım adım ele alacağız.

Let’s Encrypt ve Certbot Nasıl Çalışır?

Sorunları çözmeden önce temel mekanizmayı anlamak işinizi çok kolaylaştırır. Let’s Encrypt, domain sahipliğini doğrulamak için birkaç farklı challenge (meydan okuma) yöntemi kullanır.

Apache ile en sık kullanılan yöntem HTTP-01 challenge‘dır. Bu yöntemde Certbot, web sunucunuzun /.well-known/acme-challenge/ dizinine geçici bir dosya koyar ve Let’s Encrypt sunucuları bu dosyaya HTTP üzerinden erişmeye çalışır. Erişim başarılıysa domain sahibi olduğunuz doğrulanır ve sertifika verilir.

DNS-01 challenge ise DNS kayıtlarınıza bir TXT kaydı ekleyerek çalışır. Wildcard sertifikalar için zorunludur ve web sunucusuna erişim gerektirmez.

Bu temel bilgiyi aklınızda tutun, çünkü hataların büyük çoğunluğu bu doğrulama adımında gerçekleşir.

Sık Karşılaşılan Hata Kategorileri

1. HTTP-01 Challenge Başarısız Oluyor

Bu en yaygın hata kategorisidir. Hata mesajı genellikle şu şekilde görünür:

Challenge failed for domain example.com
http-01 challenge for example.com
Waiting for verification...
Challenge failed for domain example.com
IMPORTANT NOTES:
- The following errors were found:
  Domain: example.com
  Type: unauthorized
  Detail: Invalid response from http://example.com/.well-known/acme-challenge/...

Bu hatanın birkaç farklı nedeni olabilir. Önce .well-known/acme-challenge/ dizinine manuel erişim testi yaparak başlayın:

# Test dosyası oluştur
mkdir -p /var/www/html/.well-known/acme-challenge/
echo "test" > /var/www/html/.well-known/acme-challenge/testfile

# Dışarıdan erişimi test et (başka bir makineden veya curl ile)
curl -I http://example.com/.well-known/acme-challenge/testfile

# Test dosyasını temizle
rm /var/www/html/.well-known/acme-challenge/testfile

Eğer 403 Forbidden alıyorsanız, Apache konfigürasyonunuzda bu dizin için erişim engeli var demektir. Apache’nin bazı konfigürasyonlarında Options -Indexes veya Require all denied gibi direktifler tüm .well-known yolunu etkiliyor olabilir.

# /etc/apache2/conf-available/well-known.conf dosyası oluşturun
cat > /etc/apache2/conf-available/well-known.conf << 'EOF'
Alias /.well-known/acme-challenge/ /var/www/letsencrypt/.well-known/acme-challenge/

<Directory "/var/www/letsencrypt/.well-known/acme-challenge/">
    Options None
    AllowOverride None
    Require all granted
    ForceType text/plain
</Directory>
EOF

mkdir -p /var/www/letsencrypt/.well-known/acme-challenge/
a2enconf well-known
systemctl reload apache2

Bu yaklaşım, tüm virtual host’larınız için merkezi bir ACME challenge dizini tanımlar. Certbot’u da bu dizini kullanacak şekilde çalıştırmanız gerekir:

certbot certonly --webroot -w /var/www/letsencrypt -d example.com -d www.example.com

2. HTTPS’e Yönlendirme Sorunu

Birçok Apache konfigürasyonu HTTP trafiğini doğrudan HTTPS’e yönlendirir. Bu yönlendirme, Let’s Encrypt’in HTTP-01 doğrulamasını geçersiz kılar çünkü challenge URL’si önce HTTPS’e yönlenir, oradan da sertifika hatası alınır.

Tipik sorunlu konfigürasyon:

<VirtualHost *:80>
    ServerName example.com
    Redirect permanent / https://example.com/
</VirtualHost>

Bu konfigürasyonda /.well-known/acme-challenge/ yolu da HTTPS’e yönlenir. Çözüm, yönlendirmeyi challenge yolundan muaf tutmaktır:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com

    # ACME challenge yolunu yönlendirmeden muaf tut
    Alias /.well-known/acme-challenge/ /var/www/letsencrypt/.well-known/acme-challenge/
    
    <Directory "/var/www/letsencrypt/.well-known/acme-challenge/">
        Options None
        AllowOverride None
        Require all granted
    </Directory>

    # Geriye kalan her şeyi HTTPS'e yönlendir
    RewriteEngine On
    RewriteCond %{REQUEST_URI} !^/.well-known/acme-challenge/
    RewriteRule ^(.*)$ https://example.com$1 [R=301,L]
</VirtualHost>

3. Firewall ve Port Sorunu

Let’s Encrypt sunucuları sizin sunucunuza dışarıdan bağlanır. 80 numaralı port kapalıysa ya da firewall engelliyorsa doğrulama hiçbir zaman tamamlanamaz.

# Port 80'in dışarıdan erişilebilir olup olmadığını kontrol et
nmap -p 80 example.com

# UFW kullanıyorsanız
ufw status
ufw allow 80/tcp
ufw allow 443/tcp

# iptables kullanıyorsanız
iptables -L -n | grep -E "80|443"
iptables -I INPUT -p tcp --dport 80 -j ACCEPT
iptables -I INPUT -p tcp --dport 443 -j ACCEPT

# Firewalld kullanıyorsanız (CentOS/RHEL)
firewall-cmd --list-all
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

4. Sertifika Yenileme Sessizce Başarısız Oluyor

Bu belki de en tehlikeli senaryo. Certbot’un otomatik yenileme cron job’u veya systemd timer’ı çalışıyor gibi görünüyor ama sertifika gerçekte yenilenmiyor. Bunu fark ettiğinizde sertifikanın süresi dolmuş oluyor.

# Mevcut sertifikaların durumunu kontrol et
certbot certificates

# Yenileme simülasyonu yap (gerçek sertifika değiştirmez)
certbot renew --dry-run

# Yenileme loglarını incele
tail -100 /var/log/letsencrypt/letsencrypt.log

# Systemd timer durumunu kontrol et
systemctl status certbot.timer
systemctl list-timers | grep certbot

# Cron job'u kontrol et
cat /etc/cron.d/certbot

Yenileme loglarında dikkat etmeniz gereken satırlar:

# Başarılı yenileme
grep "Congratulations|renewed|no action taken" /var/log/letsencrypt/letsencrypt.log | tail -20

# Başarısız yenileme denemelerini bul
grep -i "error|failed|exception" /var/log/letsencrypt/letsencrypt.log | tail -30

5. Apache Reload Hatası

Sertifika başarıyla yenileniyor ama Apache’nin yeni sertifikayı yüklemesi için reload yapılmıyor. Bu durumda eski sertifika bellek üzerinde çalışmaya devam eder.

Certbot’un yenileme sonrası hook sistemi bu iş için var. Kontrol edin:

# Mevcut deploy hook'larını listele
ls -la /etc/letsencrypt/renewal-hooks/deploy/
ls -la /etc/letsencrypt/renewal-hooks/post/
ls -la /etc/letsencrypt/renewal-hooks/pre/

# Apache reload hook'u yoksa oluşturun
cat > /etc/letsencrypt/renewal-hooks/deploy/apache-reload.sh << 'EOF'
#!/bin/bash
systemctl reload apache2
EOF

chmod +x /etc/letsencrypt/renewal-hooks/deploy/apache-reload.sh

deploy hook’ları sadece sertifika gerçekten yenilendiğinde çalışır. post hook’ları ise yenileme girişiminden sonra her seferinde çalışır. Çoğu durumda deploy hook’u kullanmak daha doğrudur.

Apache Konfigürasyon Testleri

Sertifika sorunlarının bir kısmı aslında Apache konfigürasyon hatalarından kaynaklanır. Sertifika yüklendikten sonra Apache başlamıyorsa veya yanlış sertifikayı sunuyorsa şu kontrolleri yapın:

# Apache konfigürasyonunu test et
apachectl configtest
# veya
apache2ctl -t

# SSL konfigürasyonunu doğrula
openssl verify -CAfile /etc/letsencrypt/live/example.com/chain.pem 
    /etc/letsencrypt/live/example.com/cert.pem

# Sunucunun gerçekte hangi sertifikayı sunduğunu kontrol et
echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null 
    | openssl x509 -noout -dates -subject

# Sertifika zincirini doğrula
echo | openssl s_client -connect example.com:443 2>/dev/null | openssl x509 -noout -text | grep -A 2 "Issuer"

Apache SSL sanal host konfigürasyonunuzun doğru dosyaları gösterdiğinden emin olun:

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html

    SSLEngine on
    # fullchain.pem kullanın, sadece cert.pem değil
    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem

    # Eski Apache sürümleri için (2.4.8 öncesi)
    # SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

    # Modern TLS ayarları
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...
    SSLHonorCipherOrder off
</VirtualHost>

Kritik nokta: SSLCertificateFile için her zaman fullchain.pem kullanın. Sadece cert.pem kullandığınızda bazı tarayıcılar ve istemciler sertifika zincirini doğrulayamaz.

Rate Limit Sorunları

Let’s Encrypt’in rate limit’leri gerçek bir sorun olabilir, özellikle test ortamlarında veya sık sık yeniden kurulum yaptığınızda.

Mevcut limitler:

  • Certificates per Registered Domain: Haftada 50 sertifika
  • Duplicate Certificate: Haftada 5 aynı sertifika
  • Failed Validations: Saatte 5 başarısız doğrulama girişimi

Rate limit’e takıldığınızda şu hatayı alırsınız:

Error: urn:ietf:params:acme:error:rateLimited :: There were too many requests of a given type :: Error creating new order :: too many certificates already issued for exact set of domains
# Rate limit durumunu kontrol etmek için
# https://crt.sh adresini kullanabilirsiniz
curl "https://crt.sh/?q=example.com&output=json" | python3 -m json.tool | grep "not_before" | head -20

# Staging ortamını kullanarak test edin (rate limit yok)
certbot certonly --staging -d example.com -d www.example.com 
    --webroot -w /var/www/letsencrypt

# Staging sertifikasını kaldır ve gerçek sertifika al
certbot delete --cert-name example.com
certbot certonly -d example.com -d www.example.com 
    --webroot -w /var/www/letsencrypt

Altın kural: Yeni bir konfigürasyonu test ederken her zaman --staging ve --dry-run flag’lerini kullanın. Rate limit’e takılmak ve birkaç gün beklemek zorunda kalmak gereksiz bir acı.

Wildcard Sertifika Sorunları

Apache üzerinde *.example.com gibi wildcard sertifika kullanmak istiyorsanız DNS-01 challenge zorunludur. Bu da DNS sağlayıcınızın API’sini destekleyen bir Certbot plugin’i gerektiriyor.

# DNS plugin'ini yükle (örnek: Cloudflare için)
apt install python3-certbot-dns-cloudflare

# Cloudflare API token dosyasını oluştur
cat > /root/.cloudflare.ini << 'EOF'
dns_cloudflare_api_token = your_api_token_here
EOF
chmod 600 /root/.cloudflare.ini

# Wildcard sertifika al
certbot certonly 
    --dns-cloudflare 
    --dns-cloudflare-credentials /root/.cloudflare.ini 
    -d example.com 
    -d "*.example.com"

DNS propagasyonu beklemek için --dns-cloudflare-propagation-seconds parametresini artırmanız gerekebilir:

certbot certonly 
    --dns-cloudflare 
    --dns-cloudflare-credentials /root/.cloudflare.ini 
    --dns-cloudflare-propagation-seconds 60 
    -d example.com 
    -d "*.example.com"

Sertifika İzleme ve Proaktif Yönetim

Sorunları önceden yakalamak için izleme mekanizmaları kurun. İşte basit ama etkili bir script:

#!/bin/bash
# /usr/local/bin/check-ssl-expiry.sh

DOMAIN=$1
WARN_DAYS=30
CRITICAL_DAYS=14

if [ -z "$DOMAIN" ]; then
    echo "Kullanim: $0 domain.com"
    exit 1
fi

EXPIRY=$(echo | openssl s_client -connect ${DOMAIN}:443 -servername ${DOMAIN} 2>/dev/null 
    | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

if [ -z "$EXPIRY" ]; then
    echo "HATA: ${DOMAIN} adresine baglanilamiyor veya sertifika alinamiyor"
    exit 2
fi

EXPIRY_EPOCH=$(date -d "${EXPIRY}" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))

echo "${DOMAIN}: Sertifika ${DAYS_LEFT} gun sonra sona eriyor (${EXPIRY})"

if [ ${DAYS_LEFT} -lt ${CRITICAL_DAYS} ]; then
    echo "KRITIK: Hemen yenileyin!"
    exit 2
elif [ ${DAYS_LEFT} -lt ${WARN_DAYS} ]; then
    echo "UYARI: Sertifika yakinda sona erecek"
    exit 1
else
    echo "OK: Sertifika gecerli"
    exit 0
fi

Bu scripti cron’a ekleyin ve e-posta bildirimi ayarlayın:

chmod +x /usr/local/bin/check-ssl-expiry.sh

# Crontab'a ekle
echo "0 9 * * * root /usr/local/bin/check-ssl-expiry.sh example.com | mail -s 'SSL Check' [email protected]" 
    >> /etc/cron.d/ssl-check

Gerçek Dünya Senaryosu: Yenileme Sessizce Başarısız Oldu

Geçen ay bir müşterinin sunucusunda tam bu durum yaşandı. Apache çalışıyordu, site erişilebilirdi ama sertifika 2 gün önce dolmuştu. Certbot’un systemd timer’ı çalışıyordu ama yenileme başarısız oluyordu. Sorunun kaynağını bulmak için attığımız adımlar:

# 1. Adım: Sertifika durumunu kontrol et
certbot certificates
# Çıktı: EXPIRED olarak görünüyordu

# 2. Adım: Son yenileme logunu incele
tail -200 /var/log/letsencrypt/letsencrypt.log | grep -A 5 "renewal"

# 3. Adım: Dry-run ile test et
certbot renew --dry-run 2>&1 | tee /tmp/certbot-debug.log
cat /tmp/certbot-debug.log

# 4. Adım: Sorunu bulduk - .htaccess dosyası challenge yolunu engelliyordu
cat /var/www/html/.htaccess | grep -i "deny|redirect|rewrite"

.htaccess dosyasında şöyle bir satır vardı:

RewriteRule ^(.*)$ https://example.com/$1 [R=301,L,NE]

Bu rewrite kuralı koşulsuz olarak her şeyi HTTPS’e yönlendiriyordu. Düzeltme:

RewriteEngine On
RewriteCond %{REQUEST_URI} !^/.well-known/
RewriteRule ^(.*)$ https://example.com/$1 [R=301,L,NE]

Bu değişiklikten sonra certbot renew --dry-run başarıyla tamamlandı ve sertifika hemen yenilendi.

Faydalı Diagnostic Komutları Özeti

Herhangi bir sorunla karşılaştığınızda sırayla çalıştırabileceğiniz kontrol listesi:

# 1. Certbot sürümü ve kurulum durumu
certbot --version
which certbot

# 2. Mevcut sertifikaların listesi ve geçerlilik süresi
certbot certificates

# 3. Renewal konfigürasyon dosyalarını incele
ls /etc/letsencrypt/renewal/
cat /etc/letsencrypt/renewal/example.com.conf

# 4. Dry-run ile yenileme testi
certbot renew --dry-run --cert-name example.com

# 5. Apache'nin sertifika dosyalarını okuduğunu doğrula
apache2ctl -t -D DUMP_VHOSTS

# 6. TLS bağlantısını dışarıdan test et
curl -vI https://example.com 2>&1 | grep -E "SSL|TLS|certificate|expire"

# 7. Sertifika detaylarını görüntüle
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -noout -text 
    | grep -E "Subject|Issuer|Not Before|Not After|DNS"

Sonuç

Let’s Encrypt ve Apache kombinasyonu, doğru kurulduğunda neredeyse hiç bakım gerektirmez. Sorunların büyük çoğunluğu birkaç ana kategoride toplanır: HTTP-01 challenge’ın engellenmiş olması, yenileme sonrası Apache’nin reload edilmemesi ve sessiz başarısızlıkların fark edilmemesi.

En önemli önerilerim şunlardır: Her şeyden önce staging ortamında test edin ve rate limit’e takılmayın. Sertifika yenileme hook’larınızın doğru kurulduğundan emin olun ve bir izleme mekanizması kurun. Sertifika dolmadan en az 30 gün önce uyarı almanız, panik içinde iş yapmak zorunda kalmanızı engeller.

Certbot logları /var/log/letsencrypt/letsencrypt.log dosyasında oldukça detaylıdır. Bir sorunla karşılaştığınızda bu logu okumaktan kaçınmayın, çoğu zaman tam olarak neyin yanlış gittiğini söyler. Deneyimlerime göre sorunu logda bulmak, çözmekten daha uzun sürüyor, o yüzden log okuma alışkanlığı edinmek uzun vadede çok büyük zaman kazandırıyor.

Benzer Konular

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir