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.