Caddy ile Let’s Encrypt Wildcard Sertifika Kurulumu

Wildcard sertifikalar, özellikle çok sayıda subdomain yöneten sistem yöneticileri için büyük bir nimet. Her subdomain için ayrı ayrı sertifika almak, yönetmek ve yenilemek yerine tek bir *.example.com sertifikasıyla tüm subdomainleri kapsamak hem operasyonel yükü azaltıyor hem de konfigürasyonu sadeleştiriyor. Caddy bu konuda oldukça yetenekli, ancak wildcard sertifikalar Let’s Encrypt’in DNS-01 challenge mekanizmasını gerektirdiğinden biraz farklı bir kurulum süreci izliyoruz. Hadi adım adım bakalım.

Wildcard Sertifika Neden Farklı?

Let’s Encrypt’in standart HTTP-01 challenge’ı, domainin sahibi olduğunuzu kanıtlamak için web sunucunuzun belirli bir URL’e erişilebilir olmasını gerektirir. Wildcard sertifikalar içinse bu yöntem çalışmaz. *.example.com için hangi IP’yi kontrol edecek? Bu yüzden DNS-01 challenge devreye girer.

DNS-01 challenge’da Let’s Encrypt size özel bir TXT kaydı değeri verir, siz bunu DNS’e yazarsınız, Let’s Encrypt kontrol eder ve sertifikayı imzalar. Bu sürecin otomatik çalışması için Caddy’nin DNS sağlayıcınızın API’sine erişmesi gerekir.

Bu süreçte dikkat etmeniz gereken birkaç nokak var:

  • DNS sağlayıcısı desteği: Cloudflare, Route53, DigitalOcean gibi popüler sağlayıcıların Caddy eklentileri mevcut
  • API token güvenliği: DNS değişikliği yapabilecek bir token üretip güvenli saklamanız gerekiyor
  • Propagasyon süresi: DNS değişikliklerinin yayılması birkaç dakika alabilir, bu normal

Ortam Hazırlığı

Bu yazıda Cloudflare’i kullanacağız çünkü en yaygın tercih bu. Ancak mantık tüm sağlayıcılar için aynı, sadece eklenti adı ve konfigürasyon parametreleri değişiyor.

Sisteminizde Caddy’nin standart paket yöneticisi sürümü kurulu olsa bile wildcard sertifika için DNS eklentisi içeren özel bir Caddy binary’sine ihtiyacınız var. Varsayılan Caddy kurulumu bu eklentileri içermiyor.

xcaddy ile Özel Caddy Binary Derleme

xcaddy aracı, Caddy’yi istediğiniz eklentilerle birlikte derlemenizi sağlar. Önce Go kurulu olmalı:

# Go kurulumu (1.21+ gerekli)
wget https://go.dev/dl/go1.21.5.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.21.5.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc

# Go sürümünü doğrula
go version

Ardından xcaddy’yi kurup özel binary’yi derleyelim:

# xcaddy kurulumu
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
export PATH=$PATH:$(go env GOPATH)/bin

# Cloudflare DNS eklentisiyle Caddy derle
xcaddy build 
  --with github.com/caddy-dns/cloudflare

# Derlenen binary'yi sistem dizinine taşı
sudo mv caddy /usr/bin/caddy
sudo chmod +x /usr/bin/caddy

# Doğrula
caddy version
caddy list-modules | grep cloudflare

Eğer Route53 veya başka bir sağlayıcı kullanıyorsanız eklenti adını değiştirmeniz yeterli:

# Route53 için
xcaddy build --with github.com/caddy-dns/route53

# DigitalOcean için
xcaddy build --with github.com/caddy-dns/digitalocean

# Bunları aynı anda da ekleyebilirsiniz
xcaddy build 
  --with github.com/caddy-dns/cloudflare 
  --with github.com/caddy-dns/route53

Cloudflare API Token Oluşturma

Cloudflare paneline gidip My Profile > API Tokens > Create Token yolunu izleyin. “Edit zone DNS” şablonunu kullanın ve şu yetkileri verin:

  • Zone > DNS > Edit: DNS kayıtlarını düzenleyebilmek için
  • Zone > Zone > Read: Zone bilgisini okuyabilmek için
  • Zone Resources: Sadece ilgili domain’e kısıtlayın, tüm hesaba izin vermeyin

Token’ı oluşturduktan sonra güvenli bir yere kaydedin, bir daha göremezsiniz.

Caddyfile ile Wildcard Konfigürasyonu

Şimdi asıl konfigürasyona gelelim. Caddy’nin konfigürasyon dosyası genellikle /etc/caddy/Caddyfile konumunda bulunur:

# Önce dizin yapısını oluşturalım
sudo mkdir -p /etc/caddy
sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddy

Temel wildcard konfigürasyonu şöyle görünür:

# /etc/caddy/Caddyfile

{
    # Global seçenekler
    email [email protected]
    
    # Staging ortamı için (test ederken rate limit'e takılmamak için)
    # acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

*.example.com, example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    
    # Subdomain bazlı yönlendirme
    @app host app.example.com
    @api host api.example.com
    @blog host blog.example.com
    @admin host admin.example.com
    
    handle @app {
        reverse_proxy localhost:3000
    }
    
    handle @api {
        reverse_proxy localhost:8080
    }
    
    handle @blog {
        reverse_proxy localhost:4000
    }
    
    handle @admin {
        reverse_proxy localhost:9000
    }
    
    # Varsayılan (eşleşmeyen subdomain'ler için)
    handle {
        respond "Bu subdomain henüz yapılandırılmamış." 404
    }
}

Bu konfigürasyonda dikkat edin: hem *.example.com hem de example.com yazdık. Wildcard sertifika yalnızca subdomainleri kapsar, ana domain’i kapsamaz. İkisini birlikte listeleyerek tek sertifikada her ikisini de dahil ediyoruz.

Environment Variable ile API Token Yönetimi

API token’ı doğrudan Caddyfile’a yazmak güvenlik açısından kötü bir pratik. Environment variable kullanmak çok daha sağlıklı:

# /etc/caddy/caddy.env dosyası oluştur
sudo tee /etc/caddy/caddy.env > /dev/null << 'EOF'
CLOUDFLARE_API_TOKEN=your_cloudflare_api_token_here
EOF

# Dosya izinlerini güvenli hale getir
sudo chmod 600 /etc/caddy/caddy.env
sudo chown caddy:caddy /etc/caddy/caddy.env

Systemd servis dosyasını bu environment dosyasını okuyacak şekilde güncelle:

# Override dosyası oluştur
sudo systemctl edit caddy

Açılan editöre şunu yazın:

[Service]
EnvironmentFile=/etc/caddy/caddy.env

Kaydedip çıkın, ardından:

sudo systemctl daemon-reload
sudo systemctl restart caddy

Gerçek Dünya Senaryosu: Mikroservis Altyapısı

Diyelim ki bir startup için altyapı yönetiyorsunuz ve onlarca mikroservis var. Her biri farklı bir subdomain üzerinden erişilebilir olacak. Bu senaryoda wildcard sertifika hayat kurtarır:

{
    email [email protected]
    
    # Caddy'nin otomatik HTTPS'ini tüm siteler için etkinleştir
    auto_https on
}

*.startup.com, startup.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
        # Sertifika yenileme için DNS propagasyon bekleme süresi
        propagation_timeout 2m
    }
    
    # Ana site
    @root host startup.com, www.startup.com
    handle @root {
        reverse_proxy localhost:3000
    }
    
    # Kullanıcı dashboard
    @dashboard host dashboard.startup.com
    handle @dashboard {
        reverse_proxy localhost:3001
    }
    
    # Kimlik doğrulama servisi
    @auth host auth.startup.com
    handle @auth {
        reverse_proxy localhost:3002
        
        # CORS header'ları
        header {
            Access-Control-Allow-Origin "https://dashboard.startup.com"
            Access-Control-Allow-Methods "GET, POST, OPTIONS"
        }
    }
    
    # Dosya yükleme servisi
    @uploads host uploads.startup.com
    handle @uploads {
        reverse_proxy localhost:3003
        
        # Büyük dosyalar için timeout artır
        request_body {
            max_size 500MB
        }
    }
    
    # Webhook endpoint'leri
    @webhooks host webhooks.startup.com
    handle @webhooks {
        reverse_proxy localhost:3004
    }
    
    # Status sayfası
    @status host status.startup.com
    handle @status {
        root * /var/www/status
        file_server
    }
    
    # Tanımsız subdomain'lere yönlendirme
    handle {
        redir https://startup.com{uri} permanent
    }
}

Sertifika Yönetimi ve Takibi

Caddy sertifika yenilemeyi tamamen otomatik yapıyor ancak bu sürecin düzgün çalıştığını takip etmek iyi bir pratik:

# Mevcut sertifikalara bak
sudo caddy certificates

# Sertifika dizinini kontrol et
sudo ls -la /var/lib/caddy/.local/share/caddy/certificates/

# Caddy log'larını izle
sudo journalctl -u caddy -f

# Belirli bir zaman dilimine ait log'lara bak
sudo journalctl -u caddy --since "2024-01-01" --until "2024-01-02"

Sertifika durumunu izlemek için basit bir script yazabilirsiniz:

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

DOMAIN="example.com"
WARN_DAYS=14
CERT_DIR="/var/lib/caddy/.local/share/caddy/certificates"

# Wildcard sertifika dosyasını bul
CERT_FILE=$(find $CERT_DIR -name "*.crt" | xargs grep -l "*.${DOMAIN}" 2>/dev/null | head -1)

if [ -z "$CERT_FILE" ]; then
    echo "HATA: $DOMAIN için sertifika bulunamadı"
    exit 2
fi

# Sona erme tarihini al
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 ))

echo "Sertifika: $DOMAIN"
echo "Son geçerlilik: $EXPIRY"
echo "Kalan gün: $DAYS_LEFT"

if [ $DAYS_LEFT -lt $WARN_DAYS ]; then
    echo "UYARI: Sertifika $DAYS_LEFT gün içinde sona eriyor!"
    exit 1
fi

echo "Durum: OK"
exit 0
# Script'i çalıştırılabilir yap ve test et
sudo chmod +x /usr/local/bin/check-caddy-cert.sh
/usr/local/bin/check-caddy-cert.sh

Çoklu Domain için Wildcard Sertifika

Birden fazla domain yönetiyorsanız her biri için ayrı wildcard bloku tanımlayabilirsiniz:

{
    email [email protected]
}

# Birinci domain
*.example.com, example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    
    @shop host shop.example.com
    handle @shop {
        reverse_proxy localhost:3000
    }
    
    handle {
        reverse_proxy localhost:8080
    }
}

# İkinci domain (farklı Cloudflare hesabı veya token)
*.seconddomain.com, seconddomain.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN_SECOND}
    }
    
    @app host app.seconddomain.com
    handle @app {
        reverse_proxy localhost:4000
    }
    
    handle {
        root * /var/www/seconddomain
        file_server
    }
}

Sorun Giderme

Wildcard sertifika kurulumunda en sık karşılaşılan sorunlara bakalım.

DNS propagasyon sorunu: Challenge TXT kaydı oluşturulup doğrulanmadan önce DNS’te yayılmamış olabilir. Varsayılan bekleme süresi kısa geliyorsa:

tls {
    dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    propagation_timeout 5m
    propagation_delay 30s
}

API token yetkisi yetersiz: Caddy log’larında “forbidden” veya “authentication error” görüyorsanız token’ın doğru zone’a erişim iznine sahip olduğunu kontrol edin.

Rate limit: Let’s Encrypt’in üretim ortamında haftalık sertifika limitleri var. Test sırasında mutlaka staging ortamını kullanın:

# Staging sertifikası oluşturmak için geçici test
caddy run --config /etc/caddy/Caddyfile.staging

Staging Caddyfile’da global options bloğuna şunu ekleyin:

{
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

Eski sertifika önbelleği: Bazen Caddy eski sertifika bilgilerini önbellekte tutuyor. Temizlemek için:

# Caddy'yi durdur
sudo systemctl stop caddy

# Sertifika önbelleğini temizle (dikkatli olun, yeniden alınacak)
sudo rm -rf /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/

# Caddy'yi yeniden başlat
sudo systemctl start caddy

# Log'ları izle
sudo journalctl -u caddy -f

Güvenlik Sertleştirmesi

Wildcard sertifika kullandığınızda tüm subdomainlerin aynı sertifika altında olduğunu unutmayın. Bu nedenle ek güvenlik katmanları eklemek önemli:

*.example.com, example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
        # Minimum TLS sürümü
        protocols tls1.2 tls1.3
        # Güvenli cipher suite'ler
        ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
    }
    
    # Güvenlik header'ları (tüm subdomain'ler için geçerli)
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        Referrer-Policy strict-origin-when-cross-origin
        # Sunucu bilgisini gizle
        -Server
    }
    
    # Admin panel'e IP kısıtlaması
    @admin host admin.example.com
    handle @admin {
        @allowed_ips remote_ip 192.168.1.0/24 10.0.0.0/8
        handle @allowed_ips {
            reverse_proxy localhost:9000
        }
        handle {
            respond "Erişim reddedildi." 403
        }
    }
}

Caddy’yi Systemd ile Yönetme

Caddy servisinin doğru şekilde yapılandırıldığından emin olun:

# Servis durumunu kontrol et
sudo systemctl status caddy

# Konfigürasyonu test et (syntax hatası var mı?)
sudo caddy validate --config /etc/caddy/Caddyfile

# Konfigürasyonu yeniden yükle (downtime olmadan)
sudo systemctl reload caddy

# Veya Caddy'nin kendi komutuyla
sudo caddy reload --config /etc/caddy/Caddyfile

# Boot'ta otomatik başlat
sudo systemctl enable caddy

Önemli bir not: systemctl reload ile systemctl restart arasındaki fark önemli. reload Caddy’nin yeni konfigürasyonu kesintisiz yüklemesini sağlar, restart ise kısa süreli downtime yaratır. Wildcard sertifika konfigürasyonu değişikliklerinde reload tercih edin.

Sonuç

Caddy ile wildcard sertifika yönetimi, ilk kurulum aşamasında biraz daha fazla efor gerektiriyor: özel binary derleme, DNS eklentisi ekleme, API token yönetimi. Ancak bu efor karşılığını kısa sürede veriyor. Onlarca subdomain yönetirken her biri için ayrı sertifika takip etmek yerine tek bir wildcard sertifikanın otomatik yenilendiğini bilmek gerçekten rahatlık verici.

Üretim ortamına geçmeden önce mutlaka staging ortamında test edin, API token’larınızı minimum yetki prensibiyle oluşturun ve sertifika durumunu izleyen basit scriptler çalıştırın. Caddy’nin otomatik yenileme mekanizması güvenilir olsa da “güven ama doğrula” prensibiyle hareket etmek sysadmin’in değişmeyen kurallarından biri.

DNS-01 challenge’ın güzel yanlarından biri de sunucunuzun 80/443 portlarının dışarıya açık olmasını gerektirmemesi. İç ağdaki ya da firewall arkasındaki sunucular için bile geçerli bir sertifika alabiliyorsunuz, bu da wildcard sertifikaları bazı senaryolarda HTTP-01’e göre çok daha esnek kılıyor.

Bir yanıt yazın

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