Açık Kaynak Uygulamalar

    Caddy Kurulumu ve Otomatik SSL: Certbot Uğraşına Son

    Birkaç satırlık Caddyfile ile sertifikayı kendiliğinden alıp yenileyen bir web sunucusu kurmanın pratik rehberi.

    12 dk okuma Güncellendi: 18 Ağustos 2026

    Cumartesi sabahı telefonunuz titriyor: müşteri "site açılmıyor, tarayıcı güvenli değil diyor" yazmış. SSH ile bağlanıp certbot renew --dry-run çalıştırıyorsunuz, çıktının ortasında Timeout during connect (likely firewall problem) satırını görüyorsunuz. Üç ay önce kurduğunuz cron görevi hâlâ çalışıyor ama nginx'in .well-known/acme-challenge dizinini eski bir location bloğu yutmuş, doğrulama düşmüş, kimse fark etmemiş. Sertifika sessizce süresi dolana kadar bekledikten sonra tam hafta sonunda patlamış.

    Bu senaryoyu bir kez yaşadıysanız Caddy'nin ne çözdüğünü anlatmak kolaylaşır. Caddy, Go ile yazılmış açık kaynak bir web sunucusudur ve ACME istemcisi sunucunun kendi içindedir. Ayrı bir certbot paketi, ayrı bir cron/timer, ayrı bir webroot dizini, yenileme sonrası systemctl reload nginx kancası yoktur. Bir alan adını yapılandırma dosyasına yazdığınız anda Caddy sertifikayı alır, kurar, süresi dolmadan yeniler ve yenilediğinde yapılandırmayı kendi içinde tazeler.

    Bu rehberde Caddy'yi Ubuntu/Debian üzerine kurup üç farklı senaryoda çalıştıracağız: statik site, self-hosted bir uygulamanın önünde reverse proxy ve PHP-FPM ile klasik bir PHP sitesi. Ardından işin sıkıcı ama kritik tarafına geleceğiz — sunucuda zaten nginx varken 80/443 çakışmasını nasıl yöneteceğiniz, sertifika alınamadığında nereye bakacağınız ve hangi durumlarda Caddy'ye geçmemeniz gerektiği.

    Caddy Sertifikayı Neden Kendi Alıyor?#

    Let's Encrypt'ten sertifika almak üç adımlık bir iştir: ACME sunucusuna hesap açmak, alan adının size ait olduğunu bir doğrulama (challenge) ile kanıtlamak ve imzalanmış sertifikayı diske yazmak. Certbot bu üç adımı yapar ve orada durur. Sertifikayı web sunucusuna tanıtmak, yenilemeyi zamanlamak ve yenileme sonrası servisi yeniden yüklemek sizin sorumluluğunuzdadır. Zincirdeki her halka ayrı bir arıza noktasıdır.

    Caddy'de bu zincir yoktur çünkü ACME istemcisi ile TLS'i sonlandıran katman aynı süreçtir. Yapılandırmada ornek.com gördüğü anda:

    1. Bellekte bir ACME hesabı yoksa oluşturur ve /var/lib/caddy altına yazar.
    2. HTTP-01 (port 80) veya TLS-ALPN-01 (port 443) doğrulamasını kendi dinlediği port üzerinden yanıtlar — dosya sistemine bir doğrulama dosyası bırakmaz, dolayısıyla location kuralı bir şeyi yutamaz.
    3. Sertifikayı alıp bellekte tutar ve diske yedekler.
    4. Ömrünün üçte ikisi dolduğunda arka planda yeniler; yenilenen sertifika yeniden başlatma olmadan devreye girer.

    Doğrulama mantığının kendisini merak ediyorsanız Let's Encrypt ücretsiz SSL yazısı arka plandaki ACME akışını ayrıntılı anlatıyor. Buradaki fark araç değil, mimari: yenileme ayrı bir görev değil, sunucunun normal işleyişinin parçası.

    Varsayılan olarak Caddy sertifika sağlayıcısı olarak Let's Encrypt'i kullanır ve başarısız olursa yedek bir ACME sağlayıcısına (ZeroSSL) düşer. Bu davranış sürüme göre değişebildiği için üretimde hangi sağlayıcının kullanıldığını günlüklerden doğrulamak iyi bir alışkanlıktır.

    Ubuntu ve Debian Üzerine Caddy Kurulumu#

    Caddy'nin resmi APT deposu Cloudsmith üzerinde barındırılır. Dağıtımın kendi deposundaki paket çoğu zaman geride kalır, bu yüzden resmi depoyu eklemek daha sağlıklıdır:

    sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
    
    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 -y caddy
    

    Kurulumdan sonra caddy adında bir sistem kullanıcısı, caddy.service adında bir systemd birimi ve /etc/caddy/Caddyfile adında örnek bir yapılandırma oluşur. Doğrulayın:

    caddy version
    systemctl status caddy --no-pager
    

    Servis ayakta ise sunucunun IP'sine tarayıcıdan girdiğinizde Caddy'nin karşılama sayfasını görürsünüz. Sertifika alınabilmesi için 80 ve 443 portlarının dışarıya açık olması şart; güvenlik duvarı katmanınızı UFW güvenlik duvarı yazısındaki gibi yapılandırdıysanız iki portu da geçirdiğinizden emin olun:

    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw status
    

    Alan adının A kaydı sunucunun IP'sini göstermiyorsa Caddy sertifika alamaz ve döngüye girer. DNS'i yayılmadan Caddy'yi canlıya almayın.

    İlk Caddyfile: Statik Site Üç Satırda#

    /etc/caddy/Caddyfile dosyasını açıp içeriğini şununla değiştirin:

    {
    	email [email protected]
    }
    
    ornek.com, www.ornek.com {
    	root * /var/www/ornek.com
    	encode zstd gzip
    	file_server
    }
    

    Üstteki süslü parantez bloğu global seçeneklerdir; buradaki email ACME hesabına bağlanır ve sertifika süresi dolmak üzereyken Let's Encrypt'in size e-posta atabilmesini sağlar. Alttaki blok ise bir "site adresi"dir. Şema (https://) yazmadığınız her alan adı için Caddy otomatik HTTPS'i açar: sertifikayı alır, 80 portundan gelen isteği 443'e yönlendirir ve HTTP/2 ile HTTP/3'ü etkinleştirir. https-yonlendirme için ayrı bir kural yazmanız gerekmez — HTTP'den HTTPS'e yönlendirme tarafında elle kurduğunuz return 301 bloğunun karşılığı burada varsayılan davranıştır.

    Uygulamadan önce her seferinde iki komut çalıştırma alışkanlığı edinin:

    sudo caddy fmt --overwrite /etc/caddy/Caddyfile
    sudo caddy validate --config /etc/caddy/Caddyfile
    sudo systemctl reload caddy
    

    caddy fmt girintileri düzeltir, caddy validate yapılandırmayı ayrıştırıp hata varsa satır numarasıyla söyler. reload ise servisi kesintiye uğratmadan yeni yapılandırmaya geçer.

    Ne olup bittiğini izlemek için:

    sudo journalctl -u caddy --no-pager -n 80
    

    İlk sertifika alımı başarılıysa günlükte certificate obtained successfully benzeri bir satır görürsünüz. Sertifikaların diskteki yeri:

    sudo ls -R /var/lib/caddy/.local/share/caddy/certificates/
    

    Reverse Proxy: Self-Hosted Uygulamanın Önüne Caddy Koymak#

    Caddy'nin en çok kullanıldığı senaryo bu. Docker ile ayağa kaldırdığınız bir uygulama 3000, 5678 veya 8080 portunda dinliyor; siz onu alan adı ve sertifika ile dışarı açmak istiyorsunuz:

    panel.ornek.com {
    	reverse_proxy 127.0.0.1:3000
    }
    
    otomasyon.ornek.com {
    	reverse_proxy 127.0.0.1:5678
    }
    

    İki blok, iki alan adı, iki sertifika. Caddy X-Forwarded-For, X-Forwarded-Proto ve X-Forwarded-Host başlıklarını kendiliğinden ekler; WebSocket bağlantılarını da ek yapılandırma olmadan geçirir. Nginx tarafında proxy_http_version 1.1, Upgrade ve Connection başlıklarını elle yazmak zorunda kaldığınız kısım burada yoktur. Nginx karşılığını görmek isterseniz nginx reverse proxy yapılandırma yazısındaki blokla bu üç satırı yan yana koymak farkı anlatmaya yetiyor.

    Yük dengeleme de aynı direktifin içindedir:

    api.ornek.com {
    	reverse_proxy 10.0.0.11:8080 10.0.0.12:8080 {
    		lb_policy least_conn
    		health_uri /health
    		health_interval 10s
    	}
    }
    

    Uygulamanızı Docker Compose ile çalıştırıyorsanız konteyner portlarını 127.0.0.1 üzerine bağlayıp (örneğin 127.0.0.1:3000:3000) dışarıya sadece Caddy'yi açmak en temiz kurulumdur. Böylece uygulama portu internete hiç çıkmaz.

    Yol Bazlı Yönlendirme#

    Tek alan adı altında birden çok servis varsa:

    ornek.com {
    	handle /api/* {
    		reverse_proxy 127.0.0.1:4000
    	}
    
    	handle {
    		root * /var/www/ornek.com
    		file_server
    	}
    }
    

    handle blokları sırayla değerlendirilir ve ilk eşleşen kazanır; sondaki boş handle "diğer her şey" anlamına gelir.

    PHP Sitesini Caddy ile Yayınlamak#

    PHP tarafı da tek direktife iner. Önce PHP-FPM'in soket yolunu doğrulayın:

    sudo systemctl status php8.3-fpm --no-pager
    ls /run/php/
    

    Ardından:

    ornek.com {
    	root * /var/www/ornek.com/public
    	encode zstd gzip
    	php_fastcgi unix//run/php/php8.3-fpm.sock
    	file_server
    
    	log {
    		output file /var/log/caddy/ornek.com.log
    		format json
    	}
    }
    

    Soket yolundaki çift eğik çizgi yazım hatası değildir: unix/ şema önekidir, ardından gelen /run/php/... mutlak yoldur. Tek eğik çizgi yazarsanız Caddy soketi bulamaz ve 502 döner.

    php_fastcgi direktifi tek başına üç işi birden yapar: dizin isteklerinde index.php dener, var olmayan yolları index.php'ye yönlendirir (WordPress ve Laravel gibi ön denetleyici kullanan uygulamalar için gereken davranış) ve FastCGI parametrelerini doğru kurar. Nginx'te bu, try_files $uri $uri/ /index.php?$args satırı artı bir location ~ \.php$ bloğu artı fastcgi_params dahil etmek demektir.

    Günlük dizinini oluşturmayı unutmayın:

    sudo mkdir -p /var/log/caddy
    sudo chown caddy:caddy /var/log/caddy
    sudo systemctl reload caddy
    

    Nginx + Certbot ile Caddy Arasındaki Fark Nerede Ortaya Çıkıyor?#

    İki yaklaşımı adil karşılaştırmak için aynı işi yapmak için ne kadar parça gerektiğine bakalım:

    KonuNginx + CertbotCaddy
    Sertifika almacertbot --nginx ayrı çalıştırılırAlan adı yazıldığı anda otomatik
    Yenilemesystemd timer veya cron + --deploy-hookSunucu süreci içinde, zamanlayıcısız
    Yenileme sonrası reloadKancayla elle kurulurGerekmez, bellekte tazelenir
    HTTP → HTTPSAyrı server bloğu + return 301Varsayılan
    Bir statik site~15-20 satır (iki blok)4 satır
    Basit reverse proxy6-8 satır (proxy başlıkları dahil)1 satır
    HTTP/3Derleme/sürüm ve ek direktif isterVarsayılan açık
    Yapılandırma sözdizimiBlok tabanlı, bağlam kuralları öğrenilirSite adresi + direktif
    Karmaşık kurallar (map, geo, limit_req)Çok olgun, geniş ekosistemDaha sınırlı, eklenti gerekebilir
    Ekip bilgisi ve internet kaynağıDevasaGörece küçük

    Tablo Caddy'yi kayıtsız şartsız kazanan gibi gösteriyor ama son iki satır bilerek orada. Certbot'un ileri kullanımına, kancalara ve DNS doğrulamasına zaten hâkimseniz certbot ileri kullanım tarafındaki otomasyonunuz gayet iyi çalışıyor demektir ve göç etmenin somut bir getirisi olmayabilir.

    Sunucuda Zaten Nginx Varken 80/443 Çakışması#

    En sık karşılaşılan hata budur: Caddy kurulur, systemctl start caddy çalıştırılır ve servis şu satırla ölür:

    listen tcp :443: bind: address already in use
    

    Sebep basit — 80 ve 443'ü aynı anda iki süreç dinleyemez. Önce kimin dinlediğini görün:

    sudo ss -tlnp | grep -E ':80 |:443 '
    

    Buradan sonra üç seçeneğiniz var ve ikisi tuzaktır.

    Seçenek 1 — Nginx'i durdurup portları Caddy'ye devretmek. Temiz olan yol budur, ancak nginx'in altındaki tüm vhost'ları Caddyfile'a taşımanız gerekir. Geçişi kademeli yapmak isterseniz önce nginx'i durdurun, Caddy ile tek alan adını test edin, sonra kalanları taşıyın:

    sudo systemctl stop nginx
    sudo systemctl disable nginx
    sudo systemctl restart caddy
    

    Seçenek 2 — Caddy'yi alternatif portlarda çalıştırmak. Test amaçlı geçerlidir, üretim için değil:

    {
    	http_port 8080
    	https_port 8443
    }
    

    Bunu yaptığınızda HTTP-01 ve TLS-ALPN-01 doğrulamaları çalışmaz, çünkü Let's Encrypt doğrulama isteğini her zaman 80 veya 443'e gönderir. Bu yapılandırmayla sertifika almak istiyorsanız DNS-01 doğrulamasına geçmek zorundasınız (aşağıda).

    Seçenek 3 — Nginx'i önde bırakıp Caddy'yi arkaya koymak. Teknik olarak mümkündür ama otomatik HTTPS'in tüm anlamını yok eder: TLS'i nginx sonlandırır, sertifikayı yine certbot alır, Caddy sadece bir iç proxy'ye dönüşür. Bir geçiş dönemi çözümü olarak birkaç gün taşınabilir, kalıcı mimari olarak taşınmamalıdır.

    DNS-01 Doğrulaması ve Wildcard Sertifika#

    Portlar müsait değilse veya *.ornek.com gibi bir wildcard sertifika istiyorsanız DNS doğrulaması gerekir. Bunun için Caddy'ye DNS sağlayıcı eklentisi eklemek şarttır; varsayılan binary bu yeteneği içermez:

    sudo caddy add-package github.com/caddy-dns/cloudflare
    sudo systemctl restart caddy
    

    API anahtarını yapılandırma dosyasına düz metin yazmak yerine servis ortamına verin:

    sudo systemctl edit caddy
    

    Açılan dosyaya:

    [Service]
    Environment="CF_API_TOKEN=buraya_token"
    

    Ardından Caddyfile:

    *.ornek.com {
    	tls {
    		dns cloudflare {env.CF_API_TOKEN}
    	}
    	reverse_proxy 127.0.0.1:3000
    }
    

    Sertifika Alınamıyor: En Sık Görülen Beş Sebep#

    Günlükte could not get certificate veya authorization failed görüyorsanız sırayla şunları eleyin.

    Belirti: Timeout during connectSebep: 80 portu dışarıdan kapalı. → Çözüm: Güvenlik duvarı ve sağlayıcı tarafındaki ağ kurallarını kontrol edin; Caddy'nin 80'i dinlediğini ss -tlnp ile doğrulayın.

    Belirti: DNS problem: NXDOMAINSebep: A kaydı yok veya henüz yayılmamış. → Çözüm: dig ornek.com A +short çıktısının sunucu IP'sini verdiğinden emin olun, sonra yeniden deneyin.

    Belirti: too many certificates already issuedSebep: Let's Encrypt oran sınırına takıldınız (aynı kayıtlı alan adı için haftalık sertifika limiti). → Çözüm: Deneme yaparken mutlaka staging sunucusunu kullanın; staging'in oran sınırı çok daha geniştir.

    {
    	acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
    }
    

    Test bittiğinde bu satırı silin ve sudo rm -rf /var/lib/caddy/.local/share/caddy/certificates ile staging sertifikalarını temizleyip yeniden yükleyin; aksi hâlde tarayıcılar staging sertifikasına güvenmediği için site "güvenli değil" görünür.

    Belirti: Sertifika alınıyor ama site iç ağdan açılmıyor → Sebep: Alan adı sunucunun kendisine değil bir CDN'e (Cloudflare proxy) çözümleniyor ve doğrulama CDN üzerinden geliyor. → Çözüm: İlk sertifika alımı sırasında turuncu bulutu kapatın veya doğrudan DNS-01'e geçin.

    Belirti: Yerel geliştirme ortamında sürekli hata → Sebep: localhost veya .test gibi genel olmayan bir isim için Let's Encrypt sertifika veremez. → Çözüm: tls internal ile Caddy'nin kendi iç CA'sını kullanın:

    uygulama.test {
    	tls internal
    	reverse_proxy 127.0.0.1:8080
    }
    

    Caddy'ye Ne Zaman Geçmemelisiniz?#

    Otomasyon güzeldir ama her ortama uymaz. Şu durumlarda mevcut kurulumunuzda kalın:

    • cPanel, Plesk veya DirectAdmin kullanıyorsanız. Panel Apache/LiteSpeed yapılandırmasını kendisi üretir ve 80/443'ü kendisi yönetir. Araya Caddy sokmak panelin ürettiği vhost'ları, e-posta doğrulama yollarını ve panelin kendi SSL otomasyonunu bozar. Panelli ortamda doğru araç panelin kendi SSL modülüdür.
    • Nginx yapılandırmanız gerçekten karmaşıksa. map, geo, limit_req zincirleri, ayrıntılı önbellek katmanı veya Lua modülleri kullanıyorsanız bunların birebir karşılığını Caddy'de kurmak zaman alır ve bazıları eklenti gerektirir. Kazanacağınız şey sadece sertifika otomasyonuysa bu takas kötüdür.
    • Kurumsal OV/EV sertifikası kullanıyorsanız. Sertifika elle satın alınıp elle kuruluyorsa Caddy'nin en büyük avantajı devre dışı kalır; tls sertifika.crt sertifika.key ile kurabilirsiniz ama bunun için sunucu değiştirmenin anlamı yoktur.
    • Ekip nginx biliyor ve gece nöbeti tutan siz değilseniz. Bir arıza anında yapılandırmayı okuyup düzeltecek kişinin dile hâkim olması, satır sayısından daha değerlidir.

    Buna karşılık Caddy'yi tereddütsüz seçebileceğiniz yerler de nettir: tek amaçlı bir uygulama sunucusu, self-hosted araçların önündeki proxy katmanı, çok sayıda alt alan adının olduğu iç servisler ve sertifika yenilemesini takip edecek kimsenin olmadığı küçük projeler. Nginx ile Caddy arasındaki tercihi genel mimari açısından tartan bir bakış için Apache ve Nginx karşılaştırması yazısındaki değerlendirme ölçütleri burada da işinize yarar.

    Sıkça Sorulan Sorular#

    Caddy sertifikayı ne sıklıkla yeniliyor ve ben bir şey yapmam gerekiyor mu?#

    Caddy sertifikaların geçerlilik durumunu arka planda düzenli olarak kontrol eder ve ömrünün yaklaşık üçte ikisi dolduğunda yenilemeyi başlatır. Doksan günlük bir Let's Encrypt sertifikasında bu, süre dolmadan yaklaşık bir ay önce demektir. Yenilenen sertifika servis yeniden başlatılmadan devreye girer. Sizin tarafınızda cron görevi, systemd timer veya reload kancası kurmanız gerekmez.

    Mevcut nginx yapılandırmamı Caddy'ye otomatik çevirebilir miyim?#

    Caddy'nin nginx yapılandırmasını içe aktarabilen deneysel bir dönüştürücüsü vardır, ancak üretim yapılandırmalarını olduğu gibi taşımaya güvenmeyin. Karmaşık rewrite, map ve önbellek kuralları çoğunlukla elle yeniden yazılır. Sağlıklı yöntem, en önemli tek siteyi elle Caddyfile'a çevirip staging ortamında doğrulamak, sonra kalanları teker teker taşımaktır.

    Caddy nginx'ten yavaş mı?#

    Statik dosya ve reverse proxy senaryolarında ikisi arasındaki fark çoğu site için ölçülebilir ama hissedilmez düzeydedir; darboğaz genellikle uygulama veya veritabanı tarafındadır. Çok yüksek eşzamanlı bağlantı ve saniyede on binlerce istek gibi uç senaryolarda nginx'in olgun ayar seçenekleri hâlâ avantajlıdır. Küçük ve orta ölçekli projelerde performans, tercih ederken bakacağınız ilk kriter olmamalı.

    80 portunu kapatıp yalnızca 443 kullanabilir miyim?#

    Kullanabilirsiniz ama HTTP-01 doğrulaması çalışmaz. Bu durumda Caddy TLS-ALPN-01 doğrulamasını 443 üzerinden deneyebilir; yine de en güvenli yol DNS-01 doğrulamasına geçmektir. Ayrıca 80'i tamamen kapatmak, adresi http:// ile yazan ziyaretçilerin siteye hiç ulaşamaması anlamına gelir — yönlendirme yapılabilmesi için 80'in açık olması pratikte tercih edilir.

    Caddy'yi Docker içinde çalıştırırken sertifikalar kayboluyor, neden?#

    Sertifikalar konteyner içinde /data dizininde saklanır. Bu dizini kalıcı bir volume'e bağlamazsanız her konteyner yeniden oluşturmada Caddy sertifikayı sıfırdan almaya çalışır ve kısa sürede Let's Encrypt oran sınırına takılırsınız. Compose dosyanızda /data ve tercihen /config dizinlerini adlandırılmış volume'lere bağlayın.

    Aynı sunucuda hem Apache hem Caddy çalıştırabilir miyim?#

    İkisinin aynı anda 80 ve 443'ü dinlemesi mümkün değildir. Ancak Apache'yi 8080 gibi bir iç porta alıp Caddy'yi öne koyabilirsiniz: Caddy TLS'i sonlandırır ve reverse_proxy 127.0.0.1:8080 ile istekleri Apache'ye devreder. Bu, .htaccess bağımlılığı olan eski uygulamaları taşımadan HTTPS otomasyonu kazanmanın pratik yoludur.

    CaddySSLReverse Proxy

    Uygulamaya geçmeye hazır mısınız?

    NVMe SSD, ücretsiz SSL ve %99.9 uptime garantisiyle Clou.TR hosting ve sunucu çözümleriyle projenizi hayata geçirin.