Caddy ile API Gateway ve Microservice Mimarisi Kurulumu

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.

Yorum yapın