Caddy ile ZeroSSL ve ACME Sertifika Sağlayıcı Değişimi

Varsayılan olarak Caddy, Let’s Encrypt üzerinden otomatik SSL sertifikası alır. Bu çoğu durumda mükemmel çalışır, ama bazı senaryolarda farklı bir ACME sağlayıcısına geçmek zorunlu hale gelir. Rate limit sorunları, kurumsal gereksinimler, Let’s Encrypt’e olan bağımlılığı azaltmak ya da ZeroSSL’in sunduğu ek özelliklerden yararlanmak bunların başında gelir. Bu yazıda Caddy üzerinde ZeroSSL ve diğer ACME sağlayıcılarını nasıl yapılandıracağını adım adım ele alacağız.

Neden Varsayılan Sağlayıcıyı Değiştirmelisiniz?

Let’s Encrypt harika bir hizmet, bunu kimse tartışamaz. Ama production ortamında karşılaşabileceğin bazı gerçek dünya sorunları var:

  • Rate Limit: Let’s Encrypt, aynı domain için haftada 5 sertifika sınırı koyar. Sık deployment yapan ortamlarda bu sınıra takılmak an meselesi
  • Wildcard Sertifika Yönetimi: Çok sayıda subdomain olan yapılarda wildcard daha pratik
  • Kurumsal Uyum: Bazı şirketlerin belirli CA’lardan sertifika alma zorunluluğu olabilir
  • Yedeklilik: Tek bir CA’ya bağımlı kalmak, o CA’nın yaşadığı kesintilerde tüm altyapını etkiler
  • ZeroSSL Avantajları: 90 günlük sertifikaların yanı sıra 1 yıllık sertifika seçeneği, merkezi dashboard ve daha geniş destek kanalları

ZeroSSL, ACME protokolünü tam destekleyen ve Let’s Encrypt’e gerçek bir alternatif olan bir CA. Caddy ile entegrasyonu da oldukça temiz.

Caddy’nin ACME Altyapısını Anlamak

Caddy’nin TLS yönetimi arka planda certmagic kütüphanesi üzerinde çalışır. Bu kütüphane ACME protokolünü implement eder ve birden fazla CA ile çalışabilecek şekilde tasarlanmıştır.

Caddy varsayılan olarak şu sırayla sertifika almaya çalışır:

  • Önce Let’s Encrypt üzerinden dener
  • Başarısız olursa ZeroSSL’e geçer (Caddy v2.4.0 sonrası)
  • Her iki CA da başarısız olursa sertifika alınamaz

Bu varsayılan davranışı değiştirmek için Caddyfile veya JSON API üzerinden açık yapılandırma yapmak gerekir.

ZeroSSL Hesabı ve EAB Credentials Hazırlamak

ZeroSSL, ACME protokolü üzerinden sertifika alabilmek için External Account Binding (EAB) kullanır. Bu, Let’s Encrypt’ten farklı bir adım ve atlanmaması gereken bir nokta.

Adımlar:

  • ZeroSSL.com adresine git ve ücretsiz hesap oluştur
  • Dashboard’da “Developer” sekmesine geç
  • “EAB Credentials” bölümünden yeni bir credential seti oluştur
  • Sana bir EAB KID (Key ID) ve EAB HMAC Key verilecek
  • Bu değerleri güvenli bir yere kaydet, HMAC key bir daha gösterilmez

EAB credentials olmadan ZeroSSL ACME endpoint’ine istek atarsan urn:ietf:params:acme:error:externalAccountRequired hatasını alırsın. Bu hata oldukça yaygın ve çözümü basit: EAB bilgilerini doğru yapılandırmak.

Caddyfile ile ZeroSSL Yapılandırması

En basit senaryodan başlayalım. Tek bir domain için ZeroSSL kullanmak istiyorsan:

# /etc/caddy/Caddyfile

{
    acme_ca https://acme.zerossl.com/v2/DV90
    acme_eab {
        key_id EAB_KID_BURAYA_YAZ
        mac_key EAB_HMAC_KEY_BURAYA_YAZ
    }
    email [email protected]
}

example.com {
    root * /var/www/html
    file_server
    encode gzip
}

Bu yapılandırma tüm global TLS ayarlarını etkiler. Yani Caddyfile’daki tüm site blokları ZeroSSL üzerinden sertifika almaya başlar.

Yapılandırmayı test etmek için:

caddy validate --config /etc/caddy/Caddyfile
caddy reload --config /etc/caddy/Caddyfile

Caddy’nin sertifika alım sürecini canlı izlemek istiyorsan log seviyesini yükseltebilirsin:

caddy run --config /etc/caddy/Caddyfile --watch 2>&1 | grep -i "tls|cert|acme|zerossl"

Belirli Domain için Farklı CA Kullanmak

Gerçek senaryolarda tüm domainleri aynı CA’ya bağlamak her zaman doğru değil. Örneğin ana production domainlerin için ZeroSSL kullanırken, dahili test domainlerin için Let’s Encrypt’te kalabilirsin. Caddy bunu tls direktifi ile site bloğu bazında yapılandırmanı sağlar:

# /etc/caddy/Caddyfile

{
    email [email protected]
}

# Bu domain ZeroSSL kullanacak
api.sirketiniz.com {
    tls {
        ca https://acme.zerossl.com/v2/DV90
        eab {
            key_id EAB_KID_BURAYA_YAZ
            mac_key EAB_HMAC_KEY_BURAYA_YAZ
        }
    }
    reverse_proxy localhost:8080
}

# Bu domain varsayılan (Let's Encrypt) kullanacak
staging.sirketiniz.com {
    root * /var/www/staging
    file_server
}

# Bu domain Let's Encrypt staging ortamı kullanacak (test için)
test.sirketiniz.com {
    tls {
        ca https://acme-staging-v02.api.letsencrypt.org/directory
    }
    respond "Test ortami calisiyor" 200
}

Bu esnek yapı, büyük altyapılarda sertifika yönetimini domain bazında kontrol etmeni sağlar.

EAB Bilgilerini Environment Variable ile Yönetmek

Caddyfile’a doğrudan credential yazmak güvenlik açısından kötü bir pratik. Production ortamında bu bilgileri environment variable olarak saklamak çok daha doğru:

# /etc/caddy/caddy.env
ZEROSSL_EAB_KID=your_kid_value_here
ZEROSSL_EAB_HMAC=your_hmac_value_here
[email protected]

Dosya izinlerini kısıtla:

chmod 600 /etc/caddy/caddy.env
chown caddy:caddy /etc/caddy/caddy.env

Systemd service dosyasını bu env dosyasını okuyacak şekilde güncelle:

# /etc/systemd/system/caddy.service.d/override.conf
[Service]
EnvironmentFile=/etc/caddy/caddy.env

Ardından Caddyfile’da bu değişkenleri kullan:

# /etc/caddy/Caddyfile

{
    email {$ADMIN_EMAIL}
    acme_ca https://acme.zerossl.com/v2/DV90
    acme_eab {
        key_id {$ZEROSSL_EAB_KID}
        mac_key {$ZEROSSL_EAB_HMAC}
    }
}

sirketiniz.com, www.sirketiniz.com {
    root * /var/www/html
    file_server
    encode gzip zstd

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
    }
}

Systemd’yi yeniden yükle ve Caddy’yi yeniden başlat:

systemctl daemon-reload
systemctl restart caddy
systemctl status caddy

JSON API ile Programatik Yapılandırma

Caddy’nin JSON API’si, Caddyfile’dan çok daha detaylı kontrol sağlar. CI/CD pipeline’larında veya otomatik provisioning scriptlerinde bu yöntemi tercih etmek mantıklı:

# zerossl-config.json
cat > /tmp/caddy-tls-config.json << 'EOF'
{
  "apps": {
    "tls": {
      "automation": {
        "policies": [
          {
            "subjects": ["api.sirketiniz.com", "app.sirketiniz.com"],
            "issuers": [
              {
                "module": "acme",
                "ca": "https://acme.zerossl.com/v2/DV90",
                "email": "[email protected]",
                "external_account": {
                  "key_id": "EAB_KID_BURAYA",
                  "hmac": "EAB_HMAC_BURAYA"
                }
              }
            ]
          }
        ]
      }
    }
  }
}
EOF

# API üzerinden yapılandırmayı uygula
curl -X POST "http://localhost:2019/load" 
  -H "Content-Type: application/json" 
  -d @/tmp/caddy-tls-config.json

Mevcut TLS yapılandırmasını sorgulamak için:

curl -s http://localhost:2019/config/apps/tls | python3 -m json.tool

Mevcut Sertifikaları Temizlemek ve Yeniden Almak

CA değiştirdiğinde eski sertifikaların cache’de kalması sorun çıkarabilir. Caddy sertifikaları varsayılan olarak şu dizinde saklar:

  • Linux: /var/lib/caddy/.local/share/caddy/certificates/
  • macOS: ~/Library/Application Support/Caddy/certificates/

Belirli bir domain için sertifikayı temizleyip yeniden almak:

# Caddy'yi durdur
systemctl stop caddy

# Eski sertifikaları temizle (dikkatli ol, tüm sertifikalar silinir)
rm -rf /var/lib/caddy/.local/share/caddy/certificates/

# Caddy'yi yeniden başlat, sertifikaları yeniden alacak
systemctl start caddy

# Sertifika alma sürecini izle
journalctl -u caddy -f | grep -i "cert|tls|acme"

Sadece belirli bir CA’nın sertifikalarını temizlemek istiyorsan:

# Let's Encrypt sertifikalarını temizle, ZeroSSL'inkini koru
rm -rf /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org/

# ZeroSSL sertifikalarını temizle
rm -rf /var/lib/caddy/.local/share/caddy/certificates/acme.zerossl.com/

Wildcard Sertifika ve DNS Challenge

ZeroSSL’in avantajlarından biri wildcard sertifika desteği. Wildcard sertifika için HTTP-01 challenge çalışmaz, DNS-01 challenge kullanman gerekir. Caddy’de bu dns modülü gerektiriyor.

Cloudflare DNS kullanıyorsan:

# Önce xcaddy ile dns modülünü dahil ederek Caddy'yi derle
xcaddy build 
  --with github.com/caddy-dns/cloudflare

Ardından yapılandırma:

# /etc/caddy/Caddyfile

{
    email [email protected]
    acme_ca https://acme.zerossl.com/v2/DV90
    acme_eab {
        key_id {$ZEROSSL_EAB_KID}
        mac_key {$ZEROSSL_EAB_HMAC}
    }
}

*.sirketiniz.com, sirketiniz.com {
    tls {
        dns cloudflare {$CLOUDFLARE_API_TOKEN}
    }

    @api host api.sirketiniz.com
    handle @api {
        reverse_proxy localhost:8080
    }

    @app host app.sirketiniz.com
    handle @app {
        reverse_proxy localhost:3000
    }

    handle {
        root * /var/www/html
        file_server
    }
}

Bu yapıyla tek bir wildcard sertifika alıp tüm subdomainleri yönetebilirsin.

Sertifika Durumunu ve Yenileme Sürecini İzlemek

Production ortamında sertifika durumunu düzenli kontrol etmek kritik. Caddy Admin API üzerinden bunu yapabilirsin:

#!/bin/bash
# /usr/local/bin/check-caddy-certs.sh

CADDY_API="http://localhost:2019"
ALERT_DAYS=14

echo "=== Caddy Sertifika Durum Raporu ==="
echo "Tarih: $(date)"
echo ""

# Tüm yönetilen sertifikaları listele
CERTS=$(curl -s "$CADDY_API/config/apps/tls")

# certmagic üzerinden sertifika bilgilerini al
for CERT_DIR in /var/lib/caddy/.local/share/caddy/certificates/acme.zerossl.com/*/; do
    DOMAIN=$(basename "$CERT_DIR")
    CERT_FILE="$CERT_DIR/$DOMAIN.crt"

    if [ -f "$CERT_FILE" ]; then
        EXPIRY=$(openssl x509 -enddate -noout -in "$CERT_FILE" | cut -d= -f2)
        EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
        NOW_EPOCH=$(date +%s)
        DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

        if [ $DAYS_LEFT -lt $ALERT_DAYS ]; then
            echo "UYARI: $DOMAIN - $DAYS_LEFT gun kaldi (Son: $EXPIRY)"
        else
            echo "OK: $DOMAIN - $DAYS_LEFT gun kaldi"
        fi
    fi
done
chmod +x /usr/local/bin/check-caddy-certs.sh

# Cron ile her gün çalıştır
echo "0 9 * * * root /usr/local/bin/check-caddy-certs.sh | mail -s 'Caddy Sertifika Raporu' [email protected]" >> /etc/cron.d/caddy-cert-check

Troubleshooting: Yaygın Hatalar ve Çözümleri

EAB Required Hatası

# Hata: urn:ietf:params:acme:error:externalAccountRequired
# Çözüm: EAB bilgilerini doğru yapılandırdığından emin ol
journalctl -u caddy --since "10 minutes ago" | grep -i "eab|external"

Rate Limit Sorunu

ZeroSSL’de de rate limit var, ama Let’s Encrypt’e göre daha cömert. Sorunla karşılaşırsan:

# Caddy'nin mevcut durumunu kontrol et
curl -s http://localhost:2019/config/ | python3 -m json.tool | grep -A5 "automation"

# Log detaylarını artır
caddy run --config /etc/caddy/Caddyfile 2>&1 | grep -i "rate|limit|retry"

DNS Propagation Bekleme

DNS challenge kullanıyorsan propagation süresi önemli:

# DNS propagation kontrolü
dig +short TXT _acme-challenge.sirketiniz.com @8.8.8.8
dig +short TXT _acme-challenge.sirketiniz.com @1.1.1.1

# Propagation tamamlanana kadar bekle
while ! dig +short TXT _acme-challenge.sirketiniz.com @8.8.8.8 | grep -q "."; do
    echo "DNS henuz propagate olmadi, 30 saniye bekleniyor..."
    sleep 30
done
echo "DNS propagation tamamlandi"

Firewall ve Port Kontrolü

# ACME HTTP challenge için 80 portunu kontrol et
ss -tlnp | grep :80
ufw status | grep 80

# Caddy'nin dışarıya HTTPS bağlantısı yapabildiğini test et
curl -v https://acme.zerossl.com/v2/DV90/directory 2>&1 | head -20

Sonuç

Caddy ile ZeroSSL entegrasyonu, ilk bakışta karmaşık görünse de birkaç temel adımdan ibaret: EAB credentials almak, Caddyfile’da global veya site bazlı yapılandırma yapmak ve environment variable ile credential güvenliğini sağlamak. Bu üç adımı doğru atarsan geri kalan her şey otomatik çalışır.

Gerçek production senaryolarında en iyi strateji şu: Kritik domainlerin için ZeroSSL’i birincil CA olarak yapılandır, Let’s Encrypt’i fallback olarak bırak. Bu sayede herhangi bir CA tarafında yaşanacak kesintide diğeri devreye girer ve sertifika süreçlerin kesintisiz devam eder. Caddy’nin certmagic altyapısı bu failover senaryosunu neredeyse hiç müdahale gerektirmeden yönetir.

Wildcard sertifika ihtiyacın varsa DNS-01 challenge ile birlikte ZeroSSL kombinasyonu gerçekten güçlü bir seçenek. Tek sertifikayla onlarca subdomain yönetmek, hem operasyonel yükü hem de yenileme karmaşıklığını ciddi ölçüde azaltır.

Son olarak, sertifika izleme scriptini mutlaka kur. Caddy otomatik yenileme yapar ama bir şeyler ters gittiğinde 14 gün önceden uyarı almak, saat 03:00’te panikle çalışmaktan çok daha iyidir.

Yorum yapın