SSL sertifikası süresi dolmuş bir sunucuyla karşılaşmak, özellikle gece yarısı production ortamında alarm alırken, hiç kimsenin başına gelmesini istemediği türden bir durumdur. Müşteriler sitene giremiyor, tarayıcılar korkutucu uyarılar gösteriyor ve sen de aceleyle bir şeyler yapmaya çalışıyorsun. Oysa bu sorunun çözümü aslında çok basit: doğru kurgulanmış bir cron job ve birkaç satır script.
Bu yazıda Let’s Encrypt ve Certbot kullanarak SSL sertifika yenileme sürecini tamamen otomatize etmeyi, cron job’larla nasıl yöneteceğini, hata durumlarında nasıl bildirim alabileceğini ve production ortamında güvenli bir şekilde nasıl çalıştırabileceğini ele alacağız.
Neden Manuel Yenileme Yapmaya Devam Ediyorsun?
Let’s Encrypt sertifikaları 90 günde bir süresi doluyor. Bu süreyi bilinçli bir tercih olarak kısa tutuyorlar, çünkü kısa süreli sertifikalar güvenlik açısından daha iyi. Ama bu, her 90 günde bir birinin oturup “ah, sertifikayı yenilemem gerekiyor” demesi anlamına gelmiyor. Eğer hala takvime hatırlatıcı koyarak manuel yenileme yapıyorsan, bu işi yanlış yapıyorsun demektir.
Certbot zaten --renew mekanizmasına sahip ve sertifikanın süresinin dolmasına 30 günden az kaldığında yenileme yapıyor. Bizim yapacağımız şey bu mekanizmanın düzenli olarak tetiklenmesini sağlamak ve her adımda ne olduğunu kontrol altında tutmak.
Temel Altyapıyı Hazırlamak
Başlamadan önce sisteminde şunların kurulu olduğundan emin olalım:
# Ubuntu/Debian için
apt update && apt install -y certbot
# Nginx kullanıyorsan
apt install -y python3-certbot-nginx
# Apache kullanıyorsan
apt install -y python3-certbot-apache
# Kurulumu doğrula
certbot --version
Eğer daha önce manuel olarak sertifika almışsan, mevcut sertifikalarını görmek için:
certbot certificates
Bu komut sana tüm sertifikaların listesini, hangi domainler için geçerli olduklarını ve ne zaman sürelerinin dolacağını gösterir. Buradaki çıktıyı iyi incele, çünkü otomasyon scriptimizi bu yapı üzerine kuracağız.
Basit Bir Yenileme Scripti Yazmak
Doğrudan cron’a certbot renew komutu eklemek işe yarar ama hata yönetimi, loglama ve bildirim gibi kritik özellikleri kaçırırsın. Bunun yerine işi düzgün yapan bir script yazalım.
#!/bin/bash
# /usr/local/bin/ssl-renew.sh
set -euo pipefail
# Değişkenler
LOG_FILE="/var/log/ssl-renewal.log"
ALERT_EMAIL="[email protected]"
WEBHOOK_URL="https://hooks.slack.com/services/XXXXX/XXXXX/XXXXX"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
RENEWED=0
FAILED=0
# Log fonksiyonu
log() {
echo "[$DATE] $1" | tee -a "$LOG_FILE"
}
# Bildirim fonksiyonu
notify() {
local message="$1"
local level="${2:-INFO}"
# Email bildirimi
if command -v mail &> /dev/null; then
echo "$message" | mail -s "[SSL Yenileme - $level] $(hostname)" "$ALERT_EMAIL"
fi
# Slack webhook bildirimi
if [ -n "$WEBHOOK_URL" ]; then
curl -s -X POST -H 'Content-type: application/json'
--data "{"text":"[$level] $(hostname): $message"}"
"$WEBHOOK_URL" > /dev/null 2>&1
fi
}
log "SSL yenileme süreci başlatıldı"
# Yenileme öncesi web sunucusu kontrolü
if ! systemctl is-active --quiet nginx; then
log "UYARI: Nginx çalışmıyor!"
notify "Nginx servisi aktif değil, yenileme atlandı" "WARNING"
exit 1
fi
# Sertifikaları yenile
if certbot renew --quiet --post-hook "systemctl reload nginx" >> "$LOG_FILE" 2>&1; then
RENEWED=1
log "Sertifika yenileme başarıyla tamamlandı"
notify "Sertifika yenileme başarıyla tamamlandı" "SUCCESS"
else
FAILED=1
log "HATA: Sertifika yenileme başarısız!"
notify "Sertifika yenileme BAŞARISIZ! Acil kontrol gerekiyor." "CRITICAL"
exit 1
fi
log "SSL yenileme süreci tamamlandı (Yenilendi: $RENEWED, Başarısız: $FAILED)"
Scripti oluşturduktan sonra çalıştırılabilir yapmalısın:
chmod +x /usr/local/bin/ssl-renew.sh
Cron Job’u Ayarlamak
Artık asıl konuya geldik. Cron job’u nasıl ayarlayacağız ve ne sıklıkla çalıştıracağız?
Let’s Encrypt’in resmi tavsiyesi günde iki kez çalıştırmak. Bu abartılı gibi görünse de sertifikanın süresine 30 günden az kalmışsa yenileme yapıldığı ve aksi halde hiçbir şey olmadığı düşünüldüğünde, günde iki kez çalıştırmak sistemin yükünü neredeyse hiç artırmıyor.
# Root crontab'ı düzenle
crontab -e -u root
Aşağıdaki satırı ekle:
# SSL Sertifika Yenileme - Her gün 03:00 ve 15:00'te çalışır
0 3,15 * * * /usr/local/bin/ssl-renew.sh >> /var/log/ssl-renewal-cron.log 2>&1
Neden 03:00 ve 15:00? Gece 3’te trafiğin en düşük olduğu saatte nginx reload yapıyoruz. 15:00 ise iş saatleri içinde ikinci bir kontrol fırsatı sunuyor. Let’s Encrypt sunucularının yoğun olduğu saatleri (tam saat başları ve yarımlar) da bu şekilde avoid etmiş oluyoruz.
Wildcard Sertifikalar için DNS Challenge
Eğer *.sirketin.com gibi wildcard bir sertifikan varsa, HTTP challenge yerine DNS challenge kullanman gerekiyor. Bu durumda otomasyon biraz daha karmaşıklaşıyor ama halledilebilir bir şey.
Cloudflare DNS kullanıyorsan:
# Cloudflare certbot eklentisini kur
apt install -y python3-certbot-dns-cloudflare
# Cloudflare kimlik bilgileri dosyasını 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
Wildcard sertifika almak için:
certbot certonly
--dns-cloudflare
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini
-d "sirketin.com"
-d "*.sirketin.com"
--preferred-challenges dns-01
Bu yöntemle yenileme de tamamen otomatik çalışır çünkü DNS kaydını da otomatik güncelliyor.
Çoklu Domain ve Sunucu Senaryosu
Gerçek dünyada genellikle tek bir sunucuda onlarca domain barındırılıyor ya da birden fazla sunucuda sertifika yönetimi yapılıyor. Bu senaryoyu ele alalım.
#!/bin/bash
# /usr/local/bin/ssl-bulk-check.sh
# Birden fazla domain için sertifika durumu kontrolü
DOMAINS=(
"sirketin.com"
"api.sirketin.com"
"panel.sirketin.com"
"blog.sirketin.com"
)
WARN_DAYS=30
CRITICAL_DAYS=14
ALERT_EMAIL="[email protected]"
check_cert_expiry() {
local domain="$1"
local expiry_date
local days_left
expiry_date=$(echo | openssl s_client -servername "$domain"
-connect "$domain:443" 2>/dev/null |
openssl x509 -noout -enddate 2>/dev/null |
cut -d= -f2)
if [ -z "$expiry_date" ]; then
echo "HATA: $domain için sertifika bilgisi alınamadı"
return 1
fi
days_left=$(( ($(date -d "$expiry_date" +%s) - $(date +%s)) / 86400 ))
if [ "$days_left" -lt "$CRITICAL_DAYS" ]; then
echo "KRITIK: $domain sertifikası $days_left gün içinde sona eriyor!"
echo "KRITIK: $domain - $days_left gün kaldı" |
mail -s "[KRITIK SSL] $domain" "$ALERT_EMAIL"
elif [ "$days_left" -lt "$WARN_DAYS" ]; then
echo "UYARI: $domain sertifikası $days_left gün içinde sona eriyor"
else
echo "OK: $domain sertifikası geçerli ($days_left gün kaldı)"
fi
}
for domain in "${DOMAINS[@]}"; do
check_cert_expiry "$domain"
done
Bu script doğrudan HTTPS bağlantısı kurarak sertifika durumunu kontrol ediyor. Certbot’un kendi kayıtlarına bakmak yerine gerçek dünya koşullarını test ettiği için daha güvenilir bir kontrol mekanizması sunuyor.
Nginx ile Post-Hook Entegrasyonu
Sertifika yenilendikten sonra web sunucusunu yeniden yüklemek kritik. Ama bunu yanlış yaparsanız, nginx bir hatayla reload edilemez ve siteniz çevrimdışı kalabilir.
Certbot’un hook sistemi burada devreye giriyor:
# /etc/letsencrypt/renewal-hooks/pre/check-nginx.sh
# Yenileme öncesinde nginx durumunu kontrol et
#!/bin/bash
if ! nginx -t 2>/dev/null; then
echo "Nginx konfigürasyon hatası var, yenileme iptal ediliyor"
exit 1
fi
# /etc/letsencrypt/renewal-hooks/post/reload-services.sh
# Yenileme sonrasında servisleri yeniden yükle
#!/bin/bash
LOG_FILE="/var/log/ssl-renewal.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$DATE] Post-hook tetiklendi, servisler yeniden yükleniyor" >> "$LOG_FILE"
# Nginx reload
if systemctl is-active --quiet nginx; then
if systemctl reload nginx; then
echo "[$DATE] Nginx başarıyla reload edildi" >> "$LOG_FILE"
else
echo "[$DATE] HATA: Nginx reload başarısız!" >> "$LOG_FILE"
systemctl restart nginx
fi
fi
# Eğer HAProxy da kullanıyorsan
if systemctl is-active --quiet haproxy; then
# HAProxy için sertifika formatını birleştir
cat /etc/letsencrypt/live/sirketin.com/fullchain.pem
/etc/letsencrypt/live/sirketin.com/privkey.pem
> /etc/haproxy/certs/sirketin.com.pem
systemctl reload haproxy
echo "[$DATE] HAProxy reload edildi" >> "$LOG_FILE"
fi
Bu hook dosyalarına çalıştırma izni vermeyi unutma:
chmod +x /etc/letsencrypt/renewal-hooks/pre/check-nginx.sh
chmod +x /etc/letsencrypt/renewal-hooks/post/reload-services.sh
Systemd Timer Alternatifi
Certbot zaten Ubuntu ve Debian sistemlerde kurulumla birlikte bir systemd timer oluşturuyor. Ama bunu özelleştirip daha iyi hale getirebilirsin. Bazı sysadminler cron yerine systemd timer tercih ediyor, çünkü systemd daha iyi loglama, bağımlılık yönetimi ve hata raporlama sunuyor.
Mevcut timer durumunu kontrol et:
systemctl status certbot.timer
systemctl list-timers | grep certbot
Eğer bu timer aktifse ve senin cron job’unla çakışacaksa, birini devre dışı bırakman gerekiyor:
# Certbot'un kendi timer'ını devre dışı bırak (kendi cron'unu kullanacaksan)
systemctl disable certbot.timer
systemctl stop certbot.timer
# Ya da kendi özel timer'ını oluştur
cat > /etc/systemd/system/ssl-renewal.service << EOF
[Unit]
Description=SSL Sertifika Yenileme Servisi
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/ssl-renew.sh
User=root
StandardOutput=journal
StandardError=journal
EOF
cat > /etc/systemd/system/ssl-renewal.timer << EOF
[Unit]
Description=SSL Sertifika Yenileme Zamanlayıcısı
Requires=ssl-renewal.service
[Timer]
OnCalendar=*-*-* 03,15:00:00
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable ssl-renewal.timer
systemctl start ssl-renewal.timer
RandomizedDelaySec=3600 parametresi, birçok sunucunun aynı anda Let’s Encrypt API’sine istek göndermesini önlemek için rastgele bir gecikme ekliyor. Bu özellikle çok sayıda sunucu yönetiyorsan önemli.
Log Yönetimi ve İzleme
Otomasyon kurduğunda işin yarısı log yönetimi. Aylarca biriken logları yönetmek için logrotate kullanmalısın:
cat > /etc/logrotate.d/ssl-renewal << EOF
/var/log/ssl-renewal.log {
weekly
rotate 12
compress
delaycompress
missingok
notifempty
create 640 root adm
}
EOF
Cron job’unun gerçekten çalışıp çalışmadığını kontrol etmek için:
# Son cron çalışmalarını görüntüle
grep ssl-renew /var/log/syslog | tail -20
# Yenileme loglarını takip et
tail -f /var/log/ssl-renewal.log
# Mevcut sertifika durumunu kontrol et
certbot certificates
# Dry-run ile yenileme simülasyonu yap
certbot renew --dry-run
--dry-run seçeneği gerçek bir yenileme yapmadan tüm süreci simüle eder. Yeni bir otomasyon kurduğunda her zaman önce bununla test et.
Gerçek Dünya Hatalarıyla Başa Çıkmak
Teoride her şey güzel görünüyor ama production’da işler nadiren teoride olduğu gibi gidiyor. Karşılaştığım yaygın sorunlar ve çözümleri:
Rate Limit Sorunu: Let’s Encrypt’in rate limitleri var. Aynı domain için haftalık 5 sertifika yenileme hakkın var. Bu limiti testler sırasında tüketebilirsin.
- Çözüm: Test sırasında her zaman
--dry-runkullan - Çözüm: Staging ortamı için
--stagingparametresi kullan - Çözüm: Cron job’unu yeterince seyrek ayarla (günde 2 kez yeterli)
Port 80 Engelli: HTTP challenge için port 80 açık olmalı. Güvenlik duvarı kuralları bunu engelliyor olabilir.
- Çözüm: DNS challenge’a geç
- Çözüm: Güvenlik duvarında certbot için geçici kural ekle
Nginx Reload Başarısız: Yenileme başarılı ama nginx düzgün reload edilemedi.
- Çözüm: Post-hook’ta reload yerine
nginx -t && systemctl reload nginxkullan - Çözüm: Reload başarısız olursa otomatik restart tetikle
Sertifika Yenilendi Ama Eski Sertifika Kullanılıyor: Nginx’in sertifikayı cache’lediği durumlar olabiliyor.
- Çözüm:
systemctl reload nginxdeğilsystemctl restart nginxkullan (dikkatli ol, kısa kesinti olabilir) - Çözüm: Nginx konfigürasyonunda
ssl_session_cacheayarlarını gözden geçir
Birden Fazla Sunucuyu Merkezi Yönetmek
Onlarca sunucu varsa, her birine gidip cron kurmanın mantıklı olmadığını söylemeden de geçemeyeceğim. Bu senaryoda tercih ettiğim yaklaşım sertifika yönetimini tek bir sunucuda toplamak ve diğer sunuculara dağıtmaktır.
#!/bin/bash
# /usr/local/bin/ssl-distribute.sh
# Sertifikaları diğer sunuculara dağıt
CERT_DIR="/etc/letsencrypt/live"
REMOTE_SERVERS=(
"web1.sirketin.com"
"web2.sirketin.com"
"web3.sirketin.com"
)
REMOTE_USER="certdeploy"
REMOTE_CERT_DIR="/etc/ssl/certs"
SSH_KEY="/root/.ssh/certdeploy_rsa"
deploy_certs() {
local server="$1"
local domain="$2"
echo "$(date): $server sunucusuna $domain sertifikası kopyalanıyor..."
# Sertifika dosyalarını kopyala
rsync -avz --delete
-e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no"
"$CERT_DIR/$domain/"
"$REMOTE_USER@$server:$REMOTE_CERT_DIR/$domain/"
# Uzak sunucuda nginx'i reload et
ssh -i "$SSH_KEY" -o StrictHostKeyChecking=no
"$REMOTE_USER@$server"
"sudo systemctl reload nginx"
echo "$(date): $server tamamlandı"
}
# Yenilenen sertifikaları bul ve dağıt
for domain_dir in "$CERT_DIR"/*/; do
domain=$(basename "$domain_dir")
cert_file="$domain_dir/cert.pem"
# Son 24 saatte yenilendi mi kontrol et
if [ -f "$cert_file" ] &&
[ "$(find "$cert_file" -mtime -1 2>/dev/null)" ]; then
echo "$(date): $domain yenilendi, dağıtım başlıyor..."
for server in "${REMOTE_SERVERS[@]}"; do
deploy_certs "$server" "$domain"
done
fi
done
Bu yaklaşım için uzak sunucularda certdeploy kullanıcısına nginx reload için sudo izni verilmesi gerekiyor. /etc/sudoers.d/certdeploy dosyasına şunu ekle:
certdeploy ALL=(ALL) NOPASSWD: /bin/systemctl reload nginx
Sonuç
SSL sertifika yenileme otomasyonu, kurulduktan sonra neredeyse hiç dokunmadan çalışan, ama kurulmadığında hayatını zindan eden türden bir işlem. Bu yazıda anlattıklarını adım adım uygularsan, artık “sertifikan süresi doldu” konusunda gece yarısı alarm almayacaksın.
Özetlemek gerekirse kritik noktalar şunlar: İlk olarak, basit certbot renew komutunu cron’a eklemek yerine hata yönetimi ve bildirim mekanizması olan bir script yaz. İkinci olarak, günde iki kez çalıştır ama rastgele bir gecikme ekle, böylece Let’s Encrypt’i gereğinden fazla zorlamazsın. Üçüncü olarak, post-hook ile web sunucunun sertifikayı hemen yüklemesini sağla. Dördüncü olarak, her değişiklikten sonra --dry-run ile test et ve loglarını düzenli kontrol et. Son olarak, birden fazla sunucu yönetiyorsan merkezi bir dağıtım mekanizması kur.
En iyi otomasyon, farkında bile olmadığın zamanlarda sessizce çalışan otomasyondur. Bu sistemi bir kez kurduğunda, sertifika yenileme diye bir derdin kalmayacak ve enerjini daha önemli işlere harcayabileceksin.