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
headerdirektifi - 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.