Caddy ile Traefik Karşılaştırması ve Geçiş Rehberi

Modern web altyapısında reverse proxy ve web sunucusu seçimi, günlük operasyonlarını doğrudan etkileyen kritik bir karar. Traefik yıllardır Kubernetes ve Docker ekosisteminde neredeyse standart haline geldi, ancak Caddy son iki yılda ciddi bir ivme kazandı. Her ikisini de production ortamında kullanan biri olarak söyleyebilirim ki bu iki araç arasındaki seçim göründüğü kadar basit değil. Bu yazıda hem teknik karşılaştırma yapacağız hem de Traefik’ten Caddy’ye geçiş için adım adım pratik bir rehber sunacağız.

Temel Mimari Farklar

Traefik ve Caddy’nin tasarım felsefesi birbirinden oldukça farklı. Traefik, “infrastructure-aware” bir proxy olarak tasarlanmış. Docker, Kubernetes, Consul gibi orchestration sistemleriyle konuşuyor, servis discovery yapıyor ve konfigürasyonu dinamik olarak güncelliyor. Bu yaklaşım Kubernetes ortamlarında güçlü, ama basit bir VPS kurulumunda gereksiz karmaşıklık yaratıyor.

Caddy ise “simplicity first” felsefesiyle geliştiriliyor. Otomatik TLS yönetimi, minimal konfigürasyon sözdizimi ve yerleşik reverse proxy özellikleriyle öne çıkıyor. Go ile yazılmış olması her iki aracın da ortak noktası, ancak Caddy’nin binary’si çok daha küçük ve kaynak tüketimi genellikle daha düşük.

Konfigürasyon Yaklaşımı

Traefik’in konfigürasyonu iki katmanlı bir yapıya sahip. Statik konfigürasyon (traefik.yml veya CLI argümanları) ile dinamik konfigürasyon (file provider, Docker labels, Kubernetes CRD) ayrı ayrı yönetiliyor. Bu esneklik kazandırıyor ama yeni başlayanlar için kafaları karıştırabiliyor.

Caddy’nin Caddyfile sözdizimi ise çok daha okunabilir. Aynı işlevi gerçekleştiren bir Caddy konfigürasyonu genellikle Traefik’in üçte biri kadar satır içeriyor.

Traefik Yapılandırması Örneği

Tipik bir Traefik kurulumunu ele alalım. Docker Compose ile çalışan bir uygulama için standart Traefik konfigürasyonu şöyle görünüyor:

# traefik.yml (statik konfigürasyon)
cat > /etc/traefik/traefik.yml << 'EOF'
api:
  insecure: false
  dashboard: true

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: [email protected]
      storage: /etc/traefik/acme.json
      httpChallenge:
        entryPoint: web

providers:
  docker:
    endpoint: "unix:///var/run/docker.sock"
    exposedByDefault: false
  file:
    directory: /etc/traefik/dynamic
    watch: true
EOF

Traefik’te bir servisi expose etmek için Docker label’ları kullanıyorsunuz:

# docker-compose.yml içindeki label örnekleri
cat > /opt/myapp/docker-compose.yml << 'EOF'
version: '3.8'
services:
  webapp:
    image: myapp:latest
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
      - "traefik.http.routers.webapp.entrypoints=websecure"
      - "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
      - "traefik.http.middlewares.webapp-auth.basicauth.users=admin:$$2y$$10$$..."
      - "traefik.http.routers.webapp.middlewares=webapp-auth"
      - "traefik.http.services.webapp.loadbalancer.server.port=8080"
    networks:
      - traefik-public

networks:
  traefik-public:
    external: true
EOF

Bu yaklaşım Docker ekosisteminde güzel çalışıyor, ancak her servis için onlarca label yazmak zamanla bir yük haline gelebiliyor.

Caddy’nin Eşdeğer Konfigürasyonu

Aynı senaryoyu Caddy ile nasıl çözeriz? İşte burada fark net biçimde ortaya çıkıyor:

# /etc/caddy/Caddyfile
cat > /etc/caddy/Caddyfile << 'EOF'
app.example.com {
    reverse_proxy localhost:8080
    
    basicauth /* {
        admin $2y$10$...
    }
}

api.example.com {
    reverse_proxy localhost:3000 {
        health_uri /health
        health_interval 10s
        lb_policy round_robin
    }
    
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
    }
}
EOF

Caddy’nin otomatik HTTPS özelliği sayesinde TLS için ayrıca bir şey yapmanıza gerek yok. Domain adını belirttiğinizde Let’s Encrypt sertifikası otomatik alınıp yönetiliyor. Traefik’te bunu için certificateResolver tanımlamak, ACME storage ayarlamak ve her router’a tls direktifini eklemek gerekiyor.

Gerçek Dünya Senaryosu: Çoklu Uygulama Reverse Proxy

Bir SaaS şirketinde çalıştığınızı düşünün. Aynı sunucuda birden fazla müşteri uygulaması çalışıyor. Her birinin ayrı subdomain’i var ve bazılarının özel header’lara ihtiyacı var.

Traefik ile bu kurulum:

# /etc/traefik/dynamic/apps.yml
cat > /etc/traefik/dynamic/apps.yml << 'EOF'
http:
  routers:
    client-a:
      rule: "Host(`client-a.example.com`)"
      service: client-a-svc
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt
      middlewares:
        - security-headers
        - client-a-ratelimit

    client-b:
      rule: "Host(`client-b.example.com`)"
      service: client-b-svc
      entryPoints:
        - websecure
      tls:
        certResolver: letsencrypt

  services:
    client-a-svc:
      loadBalancer:
        servers:
          - url: "http://localhost:8081"
    client-b-svc:
      loadBalancer:
        servers:
          - url: "http://localhost:8082"

  middlewares:
    security-headers:
      headers:
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        contentTypeNosniff: true
        frameDeny: true
    client-a-ratelimit:
      rateLimit:
        average: 100
        burst: 50
EOF

Caddy ile aynı yapılandırma daha temiz ve kompakt:

# /etc/caddy/Caddyfile - Çoklu müşteri yapılandırması
cat > /etc/caddy/Caddyfile << 'EOF'
(security_headers) {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        -Server
    }
}

client-a.example.com {
    import security_headers
    
    rate_limit {
        zone client_a {
            key {remote_host}
            events 100
            window 1s
        }
    }
    
    reverse_proxy localhost:8081 {
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
    
    log {
        output file /var/log/caddy/client-a.log {
            roll_size 100mb
            roll_keep 7
        }
    }
}

client-b.example.com {
    import security_headers
    reverse_proxy localhost:8082
}
EOF

Caddy’deki import direktifi snippet’ları yeniden kullanmayı sağlıyor. Ortak güvenlik başlıklarını bir kez tanımlayıp her site bloğunda çağırabiliyorsunuz. Traefik’te middleware’ler için referans sistemi var ama sözdizimi çok daha verbose.

Caddy’nin API’si ve Dinamik Yönetim

Traefik kullanıcılarının sık sorduğu soru şu: “Caddy’de de dinamik konfigürasyon var mı?” Evet, var. Caddy’nin Admin API’si üzerinden çalışma zamanında konfigürasyon değiştirebilirsiniz:

# Caddy Admin API ile runtime konfigürasyon güncelleme
# Mevcut konfigürasyonu görüntüleme
curl -s localhost:2019/config/ | jq .

# Yeni bir route ekleme (JSON API kullanarak)
curl -X POST 
  -H "Content-Type: application/json" 
  localhost:2019/config/apps/http/servers/srv0/routes 
  -d '{
    "match": [{"host": ["newapp.example.com"]}],
    "handle": [{
      "handler": "reverse_proxy",
      "upstreams": [{"dial": "localhost:9090"}]
    }]
  }'

# Konfigürasyonu dosyadan yükleme
caddy reload --config /etc/caddy/Caddyfile

# Konfigürasyon geçerliliğini test etme
caddy validate --config /etc/caddy/Caddyfile

Bu API Kubernetes ortamlarında Caddy’yi programatik olarak yönetmek için kullanılıyor. Traefik’in service discovery kadar otomatik değil, ancak yeterince esnek.

Traefik’ten Caddy’ye Geçiş Adımları

Geçiş sürecini production’ı etkilemeden yapabilmek için aşamalı bir yaklaşım öneriyorum.

1. Aşama: Caddy Kurulumu ve Test Ortamı

# Ubuntu/Debian sistemlerde Caddy kurulumu
apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | 
  gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

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

apt update && apt install caddy

# Servis durumunu kontrol etme
systemctl status caddy

# Caddy versiyonu ve modülleri görüntüleme
caddy version
caddy list-modules

Kurulum sonrası Caddy, port 80 üzerinde default bir sayfa sunuyor. Traefik henüz aktifken Caddy’yi farklı bir port üzerinde test edebilirsiniz.

2. Aşama: Mevcut Traefik Konfigürasyonunu Analiz Etme

# Traefik'teki mevcut router'ları API üzerinden listele
curl -s http://localhost:8080/api/http/routers | jq '.[].rule'

# Aktif middleware'leri görüntüle
curl -s http://localhost:8080/api/http/middlewares | jq 'keys'

# Traefik access log'larından gerçek trafik analizi
awk '{print $7}' /var/log/traefik/access.log | 
  sort | uniq -c | sort -rn | head -20

Bu komutlarla mevcut Traefik yapınızı dokümante edin. Hangi middleware’ler kullanılıyor, hangi route’lar var, TLS konfigürasyonu nasıl, bunları not edin.

3. Aşama: Paralel Çalıştırma ve Traffic Switching

Production geçişinde en güvenli yöntem blue-green geçiş yapmak. Traefik’i 443’te bırakırken Caddy’yi test edin:

# Caddy'yi 8443 portunda test için başlatma
cat > /etc/caddy/Caddyfile.test << 'EOF'
{
    http_port 8080
    https_port 8443
    
    # Test sertifikaları için staging ACME kullan
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

app.example.com:8443 {
    tls internal
    reverse_proxy localhost:3000
    
    log {
        output file /var/log/caddy/test.log
    }
}
EOF

caddy run --config /etc/caddy/Caddyfile.test

4. Aşama: DNS ve Port Geçişi

Test başarılıysa tam geçişi yapalım:

# Traefik servisini durdur
systemctl stop traefik

# Caddy konfigürasyonunu production'a geçir
cp /etc/caddy/Caddyfile.test /etc/caddy/Caddyfile

# Staging ACME ve özel port ayarlarını kaldır
cat > /etc/caddy/Caddyfile << 'EOF'
{
    email [email protected]
    
    servers {
        timeouts {
            read_body   10s
            read_header 10s
            write       30s
            idle        2m
        }
    }
}

app.example.com {
    reverse_proxy localhost:3000 {
        health_uri /health
        health_interval 15s
        health_timeout 5s
        
        lb_policy least_conn
    }
}
EOF

# Konfigürasyonu doğrula ve başlat
caddy validate --config /etc/caddy/Caddyfile
systemctl start caddy
systemctl enable caddy

Performans Farklılıkları ve Kaynak Kullanımı

Production deneyimime göre Caddy genellikle daha az RAM tüketiyor. Traefik, service discovery mekanizmaları aktifken sürekli arka planda Docker socket’i veya Kubernetes API’yi poll ediyor. 50 Docker servisi olan bir ortamda Traefik’in memory kullanımı 150-200 MB civarında seyrederken, benzer bir Caddy kurulumu 50-80 MB aralığında kalıyor.

Ancak bu karşılaştırmayı abartmamak gerekiyor. Her iki araç da modern donanımda rahatlıkla çalışıyor. Asıl fark “cognitive load” tarafında yani konfigürasyonu anlama ve yönetme maliyetinde ortaya çıkıyor.

Docker Ortamlarında Caddy Kullanımı

Traefik’in en güçlü olduğu alan Docker ortamları. Caddy için Docker socket entegrasyonu yapmak mümkün, ancak resmi bir Docker provider yok. Bunun yerine caddy-docker-proxy eklentisini kullanabilirsiniz:

# xcaddy ile özel Caddy binary oluşturma (docker-proxy modülüyle)
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

xcaddy build 
    --with github.com/lucaslorentz/caddy-docker-proxy/v2

# Docker Compose ile caddy-docker-proxy kullanımı
cat > /opt/caddy/docker-compose.yml << 'EOF'
version: '3.8'
services:
  caddy:
    image: lucaslorentz/caddy-docker-proxy:ci-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - caddy_data:/data
    restart: unless-stopped
    labels:
      caddy.email: [email protected]

  webapp:
    image: myapp:latest
    labels:
      caddy: app.example.com
      caddy.reverse_proxy: "{{upstreams 8080}}"
      caddy.header: |
        Strict-Transport-Security "max-age=31536000"

volumes:
  caddy_data:
EOF

Bu yaklaşım Traefik label mantığına benziyor ve Docker ortamlarında geçişi kolaylaştırıyor.

Dikkat Edilmesi Gereken Geçiş Noktaları

Traefik’ten Caddy’ye geçerken bazı önemli farklılıklara dikkat etmek gerekiyor:

ACME sertifikaları: Traefik acme.json dosyasında saklarken Caddy, $XDG_DATA_HOME/caddy dizinini kullanıyor. Sertifikaları taşımak için Let’s Encrypt’ten yeniden istemek en temiz yol. Rate limit sorununa düşmemek için staging ortamında test etmeyin.

Middleware eşleştirmesi: Traefik middleware’lerinin Caddy direktiflerine karşılıkları:

  • traefik.http.middlewares.X.stripPrefix: Caddy’de uri strip_prefix /path
  • traefik.http.middlewares.X.basicAuth: Caddy’de basicauth
  • traefik.http.middlewares.X.rateLimit: Caddy’de rate_limit (eklenti gerektirir)
  • traefik.http.middlewares.X.headers: Caddy’de header direktifi
  • traefik.http.middlewares.X.compress: Caddy’de encode gzip zstd

Log formatı: Traefik’in access log formatı ile Caddy’nin log formatı farklı. Log analiz araçlarınızı güncelleменiz gerekebilir.

Health check davranışı: Traefik varsayılan olarak backend’in durumunu aktif kontrol etmez. Caddy’de health_uri tanımlamazsanız benzer davranış. Aktif health check isteniyorsa Caddy’de açıkça belirtmek gerekiyor.

Caddy’nin Öne Çıkan Özellikleri

Traefik’te olmayan veya daha karmaşık olan bazı Caddy özellikleri geçişi değerli kılıyor:

On-demand TLS: Çok sayıda subdomain için önceden sertifika almak yerine ilk istek anında sertifika oluşturma. Çok kiracılı (multi-tenant) uygulamalar için ideal.

Wildcard sertifika yönetimi: DNS challenge ile otomatik wildcard sertifika alma. Traefik’te de mevcut ama Caddy’de konfigürasyonu çok daha basit.

Yerleşik dosya sunucusu: Static dosyaları serve etmek için ayrı bir araça ihtiyaç duymuyorsunuz.

Şablon motoru: templates direktifi ile dinamik içerik üretebiliyorsunuz, küçük uygulamalar için ayrı bir uygulama sunucusuna gerek kalmayabiliyor.

Sonuç

Traefik ve Caddy arasındaki seçim temelde kullanım senaryonuza bağlı. Eğer ağırlıklı olarak Kubernetes üzerinde çalışıyorsanız ve servis sayınız 50’nin üzerindeyse Traefik’in service discovery yetenekleri hala avantajlı. Ancak birkaç düzine servis barındıran klasik VM veya bare-metal ortamlarında, özellikle ekibinizde Kubernetes uzmanı yoksa Caddy çok daha iyi bir seçenek.

Geçiş süreci ilk bakışta ürkütücü görünebilir ancak pratikte birkaç saatlik iş. Caddyfile sözdizimini öğrenmek Traefik YAML’larını anlamaktan genellikle daha kısa sürüyor. Test ortamında paralel çalıştırarak güvenli bir geçiş yapabilirsiniz.

En önemli tavsiye: Her iki araçla da küçük bir test ortamı kurun, kendi senaryolarınızı deneyin. Bir araçla ne kadar hızlı istediğiniz sonuca ulaşabildiğiniz, hangisini seçmeniz gerektiğini size söyleyecektir. Production’da çalışan sistem en iyi sistem olduğu için araç seçiminde pragmatik olmak her zaman kazandırıyor.

Yorum yapın