Caddy ile Otomatik HTTPS ve Let’s Encrypt Yönetimi

Nginx veya Apache kullanırken SSL sertifika yönetimi için certbot kurup, cron job yazıp, renewal hook’larını ayarlayıp uğraşmayan sysadmin yoktur sanırım. Caddy tam olarak bu acıyı ortadan kaldırmak için tasarlandı. Tek bir binary, sıfır ekstra araç ve otomatik HTTPS. Bu yazıda Caddy’yi sıfırdan kuracağız, Let’s Encrypt entegrasyonunu anlayacağız ve gerçek dünya senaryolarında nasıl kullanacağımızı göreceğiz.

Caddy Neden Farklı?

Geleneksel web sunucularında HTTPS kurulumu şöyle işler: önce web sunucusunu kurarsın, sonra certbot’u kurarsın, certbot --nginx ya da certbot --apache komutunu çalıştırırsın, sertifika alırsın, renewal için cron job yazarsın. Her şey yolunda giderse güzel, ama bir şeyler ters giderse saatler harcarsın.

Caddy’de ise durum farklı. Caddyfile’a domain adını yazarsın, sunucuyu başlatırsın, bitti. Caddy arka planda ACME protokolünü kullanarak Let’s Encrypt’ten sertifika alır, sertifikayı otomatik yeniler ve tüm HTTP trafiğini otomatik olarak HTTPS’e yönlendirir. Bunu yapmak için ayrıca bir şey yapman gerekmez.

Caddy’nin temel avantajları:

  • Otomatik sertifika alma ve yenileme
  • HTTP/2 ve HTTP/3 desteği varsayılan olarak açık
  • Sıfır downtime ile sertifika yenileme
  • ZeroSSL dahil birden fazla CA desteği
  • Modern TLS standartları varsayılan
  • Tek binary, dependency yok

Kurulum

Linux’ta Kurulum

Caddy’yi resmi repository üzerinden kurmak en sağlıklı yol. Ubuntu/Debian için:

# Gerekli paketleri kur
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

# GPG anahtarını ekle
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

# Repository ekle
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list

# Kur
sudo apt update
sudo apt install caddy

RHEL/CentOS/Rocky Linux için:

# COPR repository ekle
dnf copr enable @caddy/caddy

# Kur
dnf install caddy

# Servisi başlat
systemctl enable --now caddy

Kurulumun başarılı olduğunu doğrulayalım:

caddy version
# Çıktı: v2.7.6 h1:...

# Caddy'nin systemd servis durumunu kontrol et
systemctl status caddy

Firewall Ayarları

Caddy HTTP challenge kullanacağı için 80 ve 443 portlarının açık olması şart:

# UFW kullanıyorsan
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 443/udp  # HTTP/3 için

# firewalld kullanıyorsan
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Caddyfile Sözdizimi

Caddy’nin yapılandırma dosyası olan Caddyfile, nginx.conf veya Apache’nin httpd.conf’una kıyasla çok daha okunabilir. Temel yapı şöyle:

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

İşte bu kadar. Bu üç satır; sertifika alımı, HTTP’den HTTPS’e yönlendirme ve statik dosya servisi için yeterli. Nginx’te bunun karşılığı onlarca satır config olurdu.

İlk Basit Yapılandırma

/etc/caddy/Caddyfile dosyasını açalım ve düzenleyelim:

sudo nano /etc/caddy/Caddyfile
# Blog sitesi
blog.ornek.com {
    root * /var/www/blog
    file_server
    encode gzip

    log {
        output file /var/log/caddy/blog.access.log
        format json
    }
}

# API servisi
api.ornek.com {
    reverse_proxy localhost:8080
}

Değişiklikleri uygulamak için:

# Syntax kontrolü
sudo caddy validate --config /etc/caddy/Caddyfile

# Reload (sıfır downtime)
sudo systemctl reload caddy

Caddy reload komutu çalıştırıldığında mevcut sertifika geçerliyse yeni sertifika almaz, sadece config değişikliklerini uygular. Yeni bir domain eklendiyse o domain için otomatik olarak sertifika alır.

Let’s Encrypt Sertifika Süreci

ACME Challenge Türleri

Caddy varsayılan olarak HTTP-01 challenge kullanır. Bu challenge’da Let’s Encrypt sunucusu 80. portu dinleyen Caddy’ye bir token gönderir ve Caddy bu tokeni belirli bir URL’de sunar. Let’s Encrypt bu URL’e erişebildiyse domain sahipliği doğrulanmış olur.

DNS-01 challenge ise wildcard sertifikalar için gerekli. Bu durumda DNS provider’ınızın API’sini kullanarak bir DNS TXT kaydı eklemeniz lazım.

Cloudflare DNS kullanıyorsan wildcard sertifika için:

# Önce xcaddy ile Cloudflare DNS plugin'ini derle
# Ya da apt ile caddy-l4 gibi ek paket kur
# Daha kolay yol: xcaddy kullanmak

go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
xcaddy build --with github.com/caddy-dns/cloudflare

Cloudflare API token’ını environment variable olarak tanımla:

# /etc/caddy/caddy.env dosyası oluştur
echo "CLOUDFLARE_API_TOKEN=your_token_here" | sudo tee /etc/caddy/caddy.env
sudo chmod 600 /etc/caddy/caddy.env

Systemd servis dosyasını düzenle:

sudo systemctl edit caddy
[Service]
EnvironmentFile=/etc/caddy/caddy.env

Wildcard sertifikalı Caddyfile:

*.ornek.com, ornek.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }

    @blog host blog.ornek.com
    handle @blog {
        root * /var/www/blog
        file_server
    }

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

    handle {
        abort
    }
}

Gerçek Dünya Senaryoları

Senaryo 1: WordPress Sitesi

Bir müşterinin WordPress sitesini Caddy ile ayağa kaldıralım. PHP-FPM kullandığımızı varsayıyoruz:

# Dizin yapısını oluştur
sudo mkdir -p /var/www/wordpress
sudo chown caddy:caddy /var/www/wordpress
wp.musteri.com {
    root * /var/www/wordpress

    # PHP dosyaları için FastCGI
    php_fastcgi unix//run/php/php8.2-fpm.sock

    # Gzip sıkıştırma
    encode gzip

    # Statik dosyaları sun
    file_server

    # WordPress güvenlik başlıkları
    header {
        X-Frame-Options SAMEORIGIN
        X-Content-Type-Options nosniff
        X-XSS-Protection "1; mode=block"
        Referrer-Policy strict-origin-when-cross-origin
        -Server
    }

    # WordPress kalıcı bağlantılar için
    @notFound {
        not file
        not path /wp-admin/*
    }
    rewrite @notFound /index.php

    # xmlrpc.php'yi engelle
    @xmlrpc path /xmlrpc.php
    respond @xmlrpc 403

    log {
        output file /var/log/caddy/wp.access.log
        format json
    }
}

Senaryo 2: Node.js / Docker Reverse Proxy

Birden fazla Docker container’ı tek bir sunucuda çalıştıran bir geliştirici ortamı düşünelim:

# Ana site
ornek.com, www.ornek.com {
    redir https://ornek.com{uri} permanent

    reverse_proxy localhost:3000 {
        header_up Host {host}
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }

    # Health check endpoint'i için timeout ayarı
    @health path /health
    handle @health {
        reverse_proxy localhost:3000 {
            fail_duration 5s
        }
    }
}

# Grafana dashboard
monitor.ornek.com {
    reverse_proxy localhost:3001

    # Sadece belirli IP'lerden erişim izni ver
    @allowed remote_ip 10.0.0.0/8 192.168.0.0/16
    handle @allowed {
        reverse_proxy localhost:3001
    }

    handle {
        respond "Yetkisiz erişim" 403
    }
}

# Staging ortamı
staging.ornek.com {
    reverse_proxy localhost:3002

    # Basic auth ekle
    basicauth {
        developer $2a$14$...hashed_password...
    }
}

Basic auth için hash oluşturmak:

caddy hash-password --plaintext "guclu_sifre_buraya"
# Çıktıyı basicauth bloğuna yapıştır

Senaryo 3: Yük Dengeleme

Birden fazla backend sunucusu arasında load balancing:

app.ornek.com {
    reverse_proxy {
        to backend1.internal:8080
        to backend2.internal:8080
        to backend3.internal:8080

        # Round-robin varsayılan, least_conn da kullanabilirsin
        lb_policy least_conn

        # Sağlık kontrolü
        health_uri /health
        health_interval 30s
        health_timeout 5s
        health_status 200

        # Arıza toleransı
        fail_duration 30s
        max_fails 3
        unhealthy_latency 10s

        # Sticky sessions
        lb_try_duration 5s
        lb_try_interval 250ms
    }
}

Sertifika Yönetimi ve İzleme

Sertifika Durumunu Kontrol Etme

Caddy sertifikaları ~/.local/share/caddy/certificates/ ya da systemd servisi olarak çalışıyorsa /var/lib/caddy/.local/share/caddy/certificates/ altında saklar:

# Caddy API üzerinden sertifika durumunu kontrol et
curl http://localhost:2019/config/

# Ya da doğrudan sertifika dosyalarına bak
sudo ls -la /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/

# Sertifika bitiş tarihini kontrol et
sudo openssl x509 -in /var/lib/caddy/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/ornek.com/ornek.com.crt -noout -dates

Caddy Admin API

Caddy’nin varsayılan olarak localhost:2019 üzerinde dinleyen bir admin API’si var. Bu API üzerinden runtime’da config değiştirebilirsin:

# Mevcut konfigürasyonu al
curl -s http://localhost:2019/config/ | python3 -m json.tool

# Belirli bir route ekle (runtime'da, dosya değiştirmeden)
curl -X POST http://localhost:2019/config/apps/http/servers/srv0/routes 
    -H "Content-Type: application/json" 
    -d '{
        "match": [{"host": ["yeni.ornek.com"]}],
        "handle": [{"handler": "static_response", "body": "Merhaba!"}]
    }'

Bu API özellikle CI/CD pipeline’larında veya dynamic routing gerektiren senaryolarda çok işe yarıyor.

TLS Özelleştirme

Güvenlik Ayarları

Caddy varsayılan TLS ayarları zaten oldukça güvenli. Ama daha fazla kontrol istiyorsan:

ornek.com {
    tls {
        # Minimum TLS versiyonu
        protocols tls1.2 tls1.3

        # Cipher suite'leri kısıtla
        ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

        # OCSP stapling otomatik aktif, ama zorlayabilirsin
        alpn h2 http/1.1
    }

    reverse_proxy localhost:8080
}

Staging ve Test Ortamı

Let’s Encrypt’in rate limit’lerine takılmamak için test ortamında staging CA kullan:

# Caddyfile'da global seçenekler bloğu ekle
{
    # Test ortamı için staging CA
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory

    # Admin API sadece localhost'ta dinlesin
    admin localhost:2019

    # Email adresi (sertifika bildirimleri için)
    email [email protected]
}

test.ornek.com {
    respond "Test ortamı çalışıyor"
}

Staging sertifikası tarayıcıda güvenilir değil ama sertifika alım sürecini test etmek için ideal. Production’a geçerken acme_ca satırını kaldır ya da yorum satırına al.

Kendi Sertifikanı Getir (BYOC)

Let’s Encrypt yerine kendi sertifikanı kullanmak istiyorsan:

ornek.com {
    tls /etc/ssl/certs/ornek.com.crt /etc/ssl/private/ornek.com.key

    reverse_proxy localhost:8080
}

Bu yaklaşım kurumsal ortamlarda internal CA kullanıyorsan işe yarıyor.

Monitoring ve Log Yönetimi

Structured Logging

Caddy JSON formatında log tutabiliyor, bu da ELK stack ya da Grafana Loki ile entegrasyonu kolaylaştırıyor:

{
    log {
        output file /var/log/caddy/caddy.log {
            roll_size 50mb
            roll_keep 10
            roll_keep_for 720h
        }
        format json
        level INFO
    }
}

ornek.com {
    log {
        output file /var/log/caddy/ornek.access.log
        format json
        level INFO
    }

    reverse_proxy localhost:8080
}

Log’ları gerçek zamanlı izlemek için:

# Tüm Caddy loglarını izle
sudo journalctl -u caddy -f

# Access log'ları izle ve JSON'ı güzel göster
sudo tail -f /var/log/caddy/ornek.access.log | python3 -m json.tool

# Hata loglarını filtrele
sudo journalctl -u caddy -f | grep -i error

Prometheus Metrics

Caddy’nin Prometheus metriklerini açmak için:

{
    servers {
        metrics
    }
}

Bu yapılandırmayla /metrics endpoint’i aktif hale gelir ve Prometheus ile scrape edebilirsin.

Sık Karşılaşılan Sorunlar

Port 80 Kullanımda

Eğer Caddy başlamıyorsa ve 80 portu zaten kullanımdaysa:

# Hangi process 80 portunu kullanıyor?
sudo ss -tlnp | grep :80
# veya
sudo lsof -i :80

# Nginx varsa durdur
sudo systemctl stop nginx
sudo systemctl disable nginx

Rate Limit Sorunları

Let’s Encrypt’in rate limit’leri şunlar:

  • Certificates per Registered Domain: Haftada 50
  • Failed Validations: Saatte 5
  • Duplicate Certificate: Haftada 5

Rate limit’e takılırsanız önce staging ortamında test edin, sonra production’a geçin.

Sertifika Yenileme Sorunları

# Caddy'nin sertifika önbelleğini temizle (dikkatli kullan!)
sudo systemctl stop caddy
sudo rm -rf /var/lib/caddy/.local/share/caddy/certificates/
sudo systemctl start caddy

# Log'larda ACME hatalarını ara
sudo journalctl -u caddy | grep -i "acme|certificate|tls" | tail -50

Permissions Sorunu

Caddy caddy kullanıcısı olarak çalışır. Dizin izinlerini kontrol et:

# Web root dizinin sahibini düzelt
sudo chown -R caddy:caddy /var/www/ornek.com

# Log dizinini oluştur ve izinleri ayarla
sudo mkdir -p /var/log/caddy
sudo chown -R caddy:caddy /var/log/caddy

Performans Optimizasyonu

{
    # Global sıkıştırma ayarları
    servers {
        protocol {
            experimental_http3
        }
    }
}

ornek.com {
    encode {
        gzip 6
        zstd
        minimum_length 1024
    }

    # Cache header'ları ekle
    header /static/* {
        Cache-Control "public, max-age=31536000, immutable"
    }

    header /*.html {
        Cache-Control "no-cache"
    }

    root * /var/www/ornek.com
    file_server
}

Sonuç

Caddy, HTTPS yönetimini gerçek anlamda “set and forget” haline getiriyor. Nginx veya Apache’den geçiş yapıyorsan ilk günlerde sözdizimini alışmak biraz zaman alabilir ama bir kez alıştıktan sonra geriye dönmek istemiyorsun.

Caddy ne zaman tercih edilmeli:

  • Sertifika yönetimiyle uğraşmak istemiyorsan
  • Hızlı kurulum ve minimal bakım istiyorsan
  • Modern web standartları (HTTP/2, HTTP/3, TLS 1.3) önemliyse
  • Birden fazla domain ve subdomain yönetiyorsan
  • Küçük-orta ölçekli projelerde ya da startup ortamlarında

Caddy’nin limitleri:

  • Çok büyük ve karmaşık load balancing senaryolarında nginx kadar olgunlaşmamış
  • ModSecurity gibi WAF entegrasyonu için ek efor gerekiyor
  • Bazı gelişmiş Nginx modülleri için alternatif bulamayabilirsin

Pratik tavsiyem şu: Yeni bir proje kuruyorsan veya mevcut bir nginx kurulumunu basitleştirmek istiyorsan Caddy’yi dene. Özellikle birden fazla subdomain yönetiyorsan ve her biri için ayrı ayrı certbot koşturmaktan bıktıysan, Caddy’nin getireceği zaman tasarrufu çok belirgin olacak. İlk kurulumda “bu kadar mı kolay?” diye iki kez kontrol ettiğini garanti edebilirim.

Yorum yapın