Microservice mimarisine geçiş kararı aldığınızda, aklınızdaki ilk sorulardan biri genellikle şu olur: “Bu servislerin önüne ne koyacağım?” Nginx reverse proxy olarak yıllardır bu görevi görüyor, ancak Caddy’nin otomatik HTTPS, sade konfigürasyon syntaxı ve modern özellikleriyle birlikte API gateway rolünü üstlenmesi giderek daha cazip hale geliyor. Bu yazıda Caddy’yi gerçek bir microservice ortamında API gateway olarak nasıl kullanacağınızı, rate limiting’den load balancing’e, circuit breaker kavramından health check’lere kadar pratik örneklerle ele alacağız.
Neden Caddy ile API Gateway?
Geleneksel API gateway çözümleri (Kong, AWS API Gateway, Apigee) güçlüdür ama kurulum ve operasyon yükü ciddidir. Küçük ve orta ölçekli microservice mimarileri için bu ağırlık çoğu zaman gereksizdir.
Caddy bu boşluğu dolduruyor çünkü:
- Otomatik TLS: Let’s Encrypt ile sertifika yönetimini tamamen üstleniyor
- Caddyfile syntax: Nginx’in karmaşık direktif yapısına kıyasla çok daha okunabilir
- JSON API: Konfigürasyonu dinamik olarak değiştirme imkanı sunuyor
- Modüler yapı: Plugin sistemiyle ihtiyaç duyduğunuz özellikleri ekleyebiliyorsunuz
Gerçek dünya senaryomuz şu şekilde olacak: Bir e-ticaret platformu, kullanıcı servisi, ürün servisi, sipariş servisi ve bildirim servisinden oluşuyor. Bu servislerin hepsini tek bir Caddy instance’ı üzerinden yönetecek ve dış dünyaya açacağız.
Temel Kurulum ve Ortam Hazırlığı
Önce Caddy’yi sisteme kuralım. Ubuntu/Debian için:
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
Caddy’nin plugin desteğiyle birlikte kurulumu için xcaddy kullanmak daha esneklik sağlar:
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
xcaddy build
--with github.com/caddy-dns/cloudflare
--with github.com/mholt/caddy-ratelimit
--with github.com/greenpau/caddy-security
Microservice’lerimizi simüle etmek için basit bir Docker Compose dosyası hazırlayalım:
cat > docker-compose.yml << 'EOF'
version: '3.8'
services:
user-service:
image: hashicorp/http-echo
command: ["-text=user-service response", "-listen=:8081"]
ports:
- "8081:8081"
product-service:
image: hashicorp/http-echo
command: ["-text=product-service response", "-listen=:8082"]
ports:
- "8082:8082"
order-service:
image: hashicorp/http-echo
command: ["-text=order-service response", "-listen=:8083"]
ports:
- "8083:8083"
notification-service:
image: hashicorp/http-echo
command: ["-text=notification-service response", "-listen=:8084"]
ports:
- "8084:8084"
networks:
default:
name: microservices-net
EOF
docker-compose up -d
Temel Routing Yapılandırması
Caddyfile’ın gücü burada ortaya çıkıyor. Tüm servislerinizi mantıklı path’ler altında toplayın:
cat > /etc/caddy/Caddyfile << 'EOF'
# API Gateway ana konfigürasyonu
api.sirketiniz.com {
# Access log
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 10
}
format json
}
# Kullanici servisi
handle /api/v1/users* {
reverse_proxy localhost:8081 {
header_up X-Forwarded-For {remote_host}
header_up X-Request-ID {http.request.uuid}
header_up X-Service-Name "user-service"
}
}
# Urun servisi
handle /api/v1/products* {
reverse_proxy localhost:8082 {
header_up X-Forwarded-For {remote_host}
header_up X-Request-ID {http.request.uuid}
header_up X-Service-Name "product-service"
}
}
# Siparis servisi
handle /api/v1/orders* {
reverse_proxy localhost:8083 {
header_up X-Forwarded-For {remote_host}
header_up X-Request-ID {http.request.uuid}
header_up X-Service-Name "order-service"
}
}
# Bildirim servisi
handle /api/v1/notifications* {
reverse_proxy localhost:8084 {
header_up X-Forwarded-For {remote_host}
header_up X-Request-ID {http.request.uuid}
header_up X-Service-Name "notification-service"
}
}
# Tanimlanmamis rotalar icin 404
handle {
respond "Service not found" 404
}
}
EOF
caddy validate --config /etc/caddy/Caddyfile
caddy reload --config /etc/caddy/Caddyfile
Load Balancing ve Health Checks
Üretim ortamında her servisin birden fazla instance’ı çalışır. Caddy’nin load balancing özelliği bu durumu zarif bir şekilde yönetir:
cat > /etc/caddy/Caddyfile << 'EOF'
api.sirketiniz.com {
# Urun servisi - 3 instance ile load balancing
handle /api/v1/products* {
reverse_proxy {
# Backend sunucular
to localhost:8082 localhost:8092 localhost:8102
# Load balancing politikasi
lb_policy least_conn
# Health check konfigurasyonu
health_uri /health
health_interval 10s
health_timeout 5s
health_status 200
# Passive health check
fail_duration 30s
max_fails 3
unhealthy_status 5xx
unhealthy_latency 2s
# Retry mekanizmasi
lb_retries 2
lb_try_duration 5s
lb_try_interval 250ms
header_up X-Request-ID {http.request.uuid}
}
}
# Siparis servisi - sticky session ile
handle /api/v1/orders* {
reverse_proxy {
to localhost:8083 localhost:8093
# Cookie tabanli sticky session
lb_policy cookie order_session_id
health_uri /health
health_interval 15s
health_timeout 3s
fail_duration 60s
max_fails 5
}
}
}
EOF
Health check endpoint’leri için her servise basit bir /health route eklendiğini varsayıyoruz. Gerçek bir Node.js servisinde bu şöyle görünür:
# Servis health check endpoint ornegi (Node.js Express)
cat > health-check-test.sh << 'EOF'
#!/bin/bash
# Her servis icin health check testi
SERVICES=("localhost:8081" "localhost:8082" "localhost:8083" "localhost:8084")
for service in "${SERVICES[@]}"; do
response=$(curl -s -o /dev/null -w "%{http_code}" http://$service/health --max-time 3)
if [ "$response" = "200" ]; then
echo "[OK] $service - Health check passed"
else
echo "[FAIL] $service - Health check failed (HTTP $response)"
fi
done
EOF
chmod +x health-check-test.sh
./health-check-test.sh
Rate Limiting
API gateway’in en kritik görevlerinden biri rate limiting’dir. Caddy, caddy-ratelimit modülüyle bu işi yapabilir ancak built-in olarak da temel rate limiting desteği sunar:
cat > /etc/caddy/Caddyfile << 'EOF'
api.sirketiniz.com {
# Global rate limiting - tum istemciler icin
rate_limit {
zone global {
key {remote_host}
events 1000
window 1m
}
zone api_key {
key {http.request.header.X-API-Key}
events 5000
window 1m
}
}
# Authentication middleware
handle /api/v1/* {
# API key kontrolu
@missing_api_key not header X-API-Key *
handle @missing_api_key {
respond "API key required" 401
}
# Rate limit - authenticated kullanicilar icin daha yuksek limit
@premium_user header X-User-Tier premium
handle @premium_user {
rate_limit {
zone premium {
key {http.request.header.X-API-Key}
events 10000
window 1m
}
}
}
}
# Public endpoint - daha dusuk limit
handle /api/v1/public/* {
rate_limit {
zone public {
key {remote_host}
events 100
window 1m
}
}
reverse_proxy localhost:8082
}
}
EOF
JWT Authentication Entegrasyonu
Microservice mimarisinde kimlik doğrulamayı merkezi olarak yönetmek büyük bir avantaj sağlar. Caddy ile JWT validation yapabilirsiniz:
cat > /etc/caddy/Caddyfile << 'EOF'
{
order authenticate before respond
security {
oauth identity provider google {
realm google
driver google
client_id {env.GOOGLE_CLIENT_ID}
client_secret {env.GOOGLE_CLIENT_SECRET}
scopes openid email profile
}
authentication portal myportal {
crypto default token lifetime 3600
crypto key sign-verify {env.JWT_SECRET}
enable identity provider google
ui {
links {
"API Documentation" /docs icon "las la-book"
}
}
}
authorization policy api_users {
set auth url https://auth.sirketiniz.com/
allow roles authp/admin authp/user
crypto key verify {env.JWT_SECRET}
allow uri /api/v1/public/*
acl rule {
comment "Admin endpoint korumasi"
match role authp/admin
allow stop log warn
}
}
}
}
api.sirketiniz.com {
authenticate with myportal
handle /api/v1/admin/* {
authorize with api_users
reverse_proxy localhost:8085
}
handle /api/v1/* {
authorize with api_users
reverse_proxy {
to localhost:8081 localhost:8082 localhost:8083
lb_policy round_robin
}
}
}
EOF
Daha basit bir yaklaşım olarak harici auth servisini kullanabilirsiniz:
cat > /etc/caddy/Caddyfile << 'EOF'
api.sirketiniz.com {
handle /api/v1/* {
# Once auth servisine sor
forward_auth localhost:9000 {
uri /validate
copy_headers X-User-ID X-User-Role X-Tenant-ID
@error status 4xx 5xx
handle_response @error {
respond "Unauthorized" 401
}
}
# Auth basarili, servise ilet
reverse_proxy localhost:8081 {
header_up X-User-ID {http.request.header.X-User-ID}
header_up X-User-Role {http.request.header.X-User-Role}
}
}
}
EOF
Request/Response Transformation
Microservice’ler arasındaki iletişimde header manipülasyonu ve request transformation kritik rol oynar:
cat > /etc/caddy/Caddyfile << 'EOF'
api.sirketiniz.com {
# Guvenlik headerlari - tum yanıtlara ekle
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "DENY"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
Content-Security-Policy "default-src 'self'"
# Sunucu bilgisini gizle
-Server
-X-Powered-By
}
# CORS konfigurasyonu
@cors_preflight method OPTIONS
handle @cors_preflight {
header Access-Control-Allow-Origin "https://app.sirketiniz.com"
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, PATCH, OPTIONS"
header Access-Control-Allow-Headers "Authorization, Content-Type, X-API-Key, X-Request-ID"
header Access-Control-Max-Age "86400"
respond "" 204
}
header Access-Control-Allow-Origin "https://app.sirketiniz.com"
# Request ID injection
handle /api/* {
request_header X-Request-ID {http.request.uuid}
request_header X-Forwarded-Host {host}
request_header X-Real-IP {remote_host}
# Hassas headerlari temizle
request_header -X-Internal-Token
request_header -X-Admin-Bypass
reverse_proxy localhost:8081 {
# Timeout ayarlari
dial_timeout 5s
response_header_timeout 30s
read_timeout 60s
write_timeout 60s
# Upstream yanıtından gereksiz headerlari kaldir
header_down -X-Internal-Error
header_down -X-Debug-Info
# Cache-Control eklenmemisse ekle
header_down ?Cache-Control "no-cache, no-store"
}
}
}
EOF
Canary Deployment ve A/B Testing
Yeni servis versiyonlarını canlıya alırken Caddy üzerinden trafik bölme yapabilirsiniz:
cat > /etc/caddy/Caddyfile << 'EOF'
api.sirketiniz.com {
handle /api/v1/products* {
# Canary deployment - trafigin %10'unu yeni versiyona yonlendir
reverse_proxy {
to localhost:8082 localhost:8092
# Agirlikli round robin
# 8082 = v1 (mevcut), 8092 = v2 (canary)
lb_policy weighted_round_robin {
localhost:8082 9
localhost:8092 1
}
health_uri /health
health_interval 10s
}
}
# Beta kullanicilari icin yeni versiyona yonlendir
@beta_user header X-Beta-User "true"
handle @beta_user {
handle /api/v1/products* {
reverse_proxy localhost:8092
}
}
# Belirli bir tenant'i yeni versiyona yonlendir
@tenant_migration {
header X-Tenant-ID "tenant-123"
path /api/v1/*
}
handle @tenant_migration {
reverse_proxy localhost:8092 {
header_up X-Migration-Mode "true"
}
}
}
EOF
Monitoring ve Observability
Caddy’nin metrics desteğini Prometheus ile entegre edin:
cat > /etc/caddy/Caddyfile << 'EOF'
{
# Admin API
admin 0.0.0.0:2019
# Prometheus metrics
servers {
metrics
}
}
# Metrics endpoint - sadece internal network
metrics.internal.sirketiniz.com {
bind lo
handle /metrics {
metrics
}
# Unauthorized erisimi engelle
handle {
respond "Not found" 404
}
}
api.sirketiniz.com {
log {
output file /var/log/caddy/api-access.log {
roll_size 200mb
roll_keep 30
roll_keep_for 720h
}
format json {
time_format iso8601
}
}
}
EOF
Prometheus scrape konfigürasyonu:
cat >> /etc/prometheus/prometheus.yml << 'EOF'
scrape_configs:
- job_name: 'caddy'
static_configs:
- targets: ['localhost:2019']
metrics_path: /metrics
scrape_interval: 15s
scrape_timeout: 10s
EOF
# Caddy log'larini parse etmek icin log rotation ayari
cat > /etc/logrotate.d/caddy << 'EOF'
/var/log/caddy/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
sharedscripts
postrotate
systemctl reload caddy
endscript
}
EOF
Circuit Breaker Pattern
Caddy’nin passive health check mekanizması basit bir circuit breaker görevi görür. Bunu daha gelişmiş hale getirebilirsiniz:
cat > /etc/caddy/Caddyfile << 'EOF'
api.sirketiniz.com {
handle /api/v1/orders* {
reverse_proxy {
to localhost:8083 localhost:8093 localhost:8103
lb_policy least_conn
# Circuit breaker ayarlari
# 30 saniye icinde 5 hata olursa devre kopar
fail_duration 30s
max_fails 5
# Unhealthy tespiti
unhealthy_status 500 502 503 504
unhealthy_latency 3s
# Fallback response - servis tamamen cakmissa
@down status 502 503
handle_response @down {
respond `{"error": "Order service temporarily unavailable", "retry_after": 30}` 503 {
header Content-Type application/json
header Retry-After 30
}
}
}
}
# Fallback servis - sadece read-only islemler
handle /api/v1/orders/history* {
reverse_proxy {
to localhost:8083 localhost:9083
lb_policy first
@primary_down status 5xx
handle_response @primary_down {
# Cache'den sun
reverse_proxy localhost:6379 {
header_up X-Cache-Fallback "true"
}
}
}
}
}
EOF
Dinamik Konfigürasyon Yönetimi
Caddy’nin JSON API’si üzerinden servisleri dinamik olarak ekleyip çıkarabilirsiniz. Bu özellikle Kubernetes veya container orchestration ile çalışırken işe yarar:
#!/bin/bash
# Yeni bir backend ekle
add_backend() {
local service=$1
local upstream=$2
curl -X POST "http://localhost:2019/config/apps/http/servers/api/routes/0/handle/0/upstreams"
-H "Content-Type: application/json"
-d "{"dial": "$upstream"}"
echo "Backend $upstream $service servisine eklendi"
}
# Backend kaldir
remove_backend() {
local upstream_index=$1
curl -X DELETE "http://localhost:2019/config/apps/http/servers/api/routes/0/handle/0/upstreams/$upstream_index"
echo "Backend $upstream_index kaldirildi"
}
# Mevcut konfigurasyonu goruntule
show_config() {
curl -s "http://localhost:2019/config/" | python3 -m json.tool
}
# Caddy'yi graceful reload yap
reload_caddy() {
curl -X POST "http://localhost:2019/load"
-H "Content-Type: application/json"
-d @/etc/caddy/caddy.json
echo "Caddy konfigurasyonu yenilendi"
}
# Kullanim
case "$1" in
add) add_backend "$2" "$3" ;;
remove) remove_backend "$2" ;;
show) show_config ;;
reload) reload_caddy ;;
*) echo "Kullanim: $0 {add|remove|show|reload}" ;;
esac
Güvenlik Sertleştirme
API gateway’i production’a almadan önce güvenlik katmanlarını ekleyin:
cat > /etc/caddy/Caddyfile << 'EOF'
{
email [email protected]
# OCSP stapling
ocsp_stapling on
# TLS versiyon ve cipher ayarlari
servers {
protocol {
strict_sni_host
}
}
}
api.sirketiniz.com {
tls {
protocols tls1.2 tls1.3
ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
curves x25519 secp384r1
}
# IP bazli engelleme
@blocked_ips {
remote_ip 192.168.1.100 10.0.0.50
}
handle @blocked_ips {
respond "Forbidden" 403
}
# Sadece belirli IP araligina izin ver
@internal_only {
path /api/v1/internal/*
not remote_ip 10.0.0.0/8 172.16.0.0/12
}
handle @internal_only {
respond "Access denied" 403
}
# Bot ve scraper engellemesi
@bad_bots {
header User-Agent *bot* *crawler* *scraper* *spider*
}
handle @bad_bots {
respond "Not allowed" 403
}
# Cok buyuk request body'lerini reddet
request_body {
max_size 10MB
}
}
EOF
Performans Optimizasyonu
Yüksek trafikli ortamlarda Caddy’yi en iyi performans için ayarlamanız gerekir:
# Sistem seviyesi optimizasyon
cat >> /etc/sysctl.conf << 'EOF'
# TCP optimizasyonu
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.ip_local_port_range = 1024 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
net.ipv4.tcp_keepalive_probes = 6
# File descriptor limiti
fs.file-max = 2097152
EOF
sysctl -p
# Caddy servis dosyasini optimize et
cat > /etc/systemd/system/caddy.service.d/override.conf << 'EOF'
[Service]
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
PrivateDevices=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE
EOF
systemctl daemon-reload
systemctl restart caddy
Caddyfile içinde buffer ve timeout ayarları:
cat >> /etc/caddy/Caddyfile << 'EOF'
{
servers {
timeouts {
read_body 10s
read_header 10s
write 30s
idle 2m
}
# Keep-alive ayarlari
keepalive_interval 10s
}
}
EOF
Sonuç
Caddy’yi API gateway olarak kullanmak, özellikle microservice mimarisine yeni geçen ya da operasyon yükünü azaltmak isteyen ekipler için oldukça akıllıca bir tercih. Nginx veya özel gateway çözümleriyle kıyaslandığında konfigürasyon karmaşıklığı belirgin biçimde azalıyor, otomatik TLS yönetimi operasyonel yükü düşürüyor ve JSON API sayesinde dinamik konfigürasyon değişiklikleri mümkün hale geliyor.
Yazıda ele aldığımız konuları üretim ortamına taşırken dikkat etmeniz gereken birkaç önemli nokta var:
- Monitoring önce gelir: Caddy metrics’i Prometheus’a bağlamadan canlıya almayın. Sorun yaşandığında kör olursunuz.
- Rate limiting konfigürasyonunu servis başına ayarlayın: Tek bir global limit tüm servisleri olumsuz etkiler.
- Health check endpoint’leri gerçekten çalışıyor mu test edin: Birçok ekip bu endpoint’leri ekleyip test etmeyi unutuyor, ta ki bir servis düşene kadar.
- Dinamik konfigürasyon değişikliklerini version control’de tutun: Admin API’si üzerinden yapılan değişiklikler restart’ta kaybolabilir.
- Circuit breaker threshold’larını servis SLA’larına göre ayarlayın: Çok sıkı ayarlar gereksiz hata üretir, çok gevşek ayarlar ise aşağı akış servislerinizi kasıp kavurur.
Caddy, Kong veya Envoy kadar özellik zengin olmayabilir ama operasyon kolaylığı ve sade konfigürasyonuyla küçük ve orta ölçekli microservice mimarileri için mükemmel bir seçim. Büyüdükçe ihtiyaçlarınız değişirse, bu temeller üzerine inşa ettiğiniz altyapıyı daha kapsamlı çözümlere geçiş için sağlam bir köprü olarak kullanabilirsiniz.