Kendi CDN sunucunuzu kurma: bir kez al, binlerce kez sun
CDN sunucusu her dosyayı kaynaktan bir kez alır ve sonrasında binlerce kez kendisi sunar. Kaynak sunucu isteklerin yalnızca küçük bir bölümünü görür, ziyaretçiler ise kısa yüklenme süreleri elde eder. Böyle bir sunucuyu şöyle kurarsınız.
Bir ziyaretçinin sitenizden yüklediği her dosyayı kaynak sunucunuz (origin) dosya sisteminden alır, bir yanıtın içine koyar ve yola çıkarır. Günde on ziyaretçide bunu kimse fark etmez. Eşzamanlı on bin ziyaretçide ise, asıl uygulamanın yapacak hiçbir işi olmadığı hâlde sitenin yavaşlamasının sebebi tam olarak budur.
CDN sunucusu bunun önüne yerleşir. Her dosyayı kaynaktan bir kez alır ve sonrasında, ne kadar gerekiyorsa o kadar, kendisi sunar. Kaynak böylece isteklerin yalnızca küçük bir bölümünü görür ve ziyaretçiler dosyalarını, sunmaktan başka hiçbir iş yapmayan bir sunucudan alır. Bu yazı bunun gerçekte ne kazandırdığını, böyle bir sunucuyu nginx ile nasıl kuracağınızı ve trafik ile lokasyonda neyin önemli olduğunu gösteriyor.
CDN sunucusu gerçekte ne yapar
Akış üç cümleyle anlatılabilir:
- Bir ziyaretçi CDN sunucusundan bir dosya ister.
- Dosya orada hazırsa hemen yola çıkar. Bu bir isabettir.
- Orada yoksa CDN sunucusu dosyayı kaynaktan alır, saklar ve sunar. Bu bir ıskadır ve dosya başına, geçerlilik süresi boyunca yalnızca bir kez olur.
İlke bir stream sunucusu ile aynı: bir kez al, çok kez sun. Tek fark, stream sunucusunun akmakta olan bir veri akışını dağıtması, CDN sunucusunun ise hazır dosyaları dağıtmasıdır.
Hesap: bir önbellek yükü ne kadar azaltır
Belirleyici olan isabet oranıdır, yani önbelleğin kendi kendine yanıtladığı isteklerin payı. Günde bir milyon istekte yükün azalması şöyle görünür:
| İsabet oranı | Kaynaktaki istekler | Yük azalması |
|---|---|---|
| %50 | 500.000 | 2 kat |
| %80 | 200.000 | 5 kat |
| %95 | 50.000 | 20 kat |
| %99 | 10.000 | 100 kat |
Statik dosyalarda yüzde 95 ve üzeri olağan durumdur, çünkü görseller, betikler ve yazı tipleri nadiren değişir. Yüzde 95'ten 99'a çıkış ise sayıların düşündürdüğünden daha değerlidir: Kalan yükü bir kez daha beşe böler.
Bu arada trafik yer değiştirir. Kaynak neredeyse hiçbir şey aktarmaz, CDN sunucusu ise bir o kadar fazlasını aktarır. Günde 500.000 görsel çağrısında her biri 400 KB ise bu günlük 200 GB, yani ayda yaklaşık 6 TB eder, hem de yalnızca görseller için. Bu yüzden bir CDN düğümünde önemli sayı CPU değil, bağlantı ve hacimdir.
Kendinize ait bir CDN sunucusu ne zaman değer
Ticari CDN sağlayıcıları aktarılan gigabayt başına faturalandırır. Bu rahattır ve az hacimde ucuza gelir. Belirli bir miktardan sonra ise denge tersine döner:
| Durum | Kendinize ait CDN sunucusu | Gigabayt başına faturalandırma |
|---|---|---|
| Ayda birkaç GB | pek değmez | daha ucuz |
| Ayda çok TB | sabit aylık fiyat | doğrusal olarak büyür |
| Büyük indirmeler, video arşivleri | açık ara avantajlı | çabucak pahalanır |
| Kurallar ve kayıtlar üzerinde tam denetim | eksiksiz | kısıtlı |
Buna, sayıyla ifade edilmesi zor bir nokta eklenir: Kendinize ait bir düğümde neyin önbelleğe alınacağına, ne kadar süreyle kalacağına ve ne zaman kaybolacağına kendiniz karar verirsiniz. Yabancı bir sağlayıcının kurallarına bağlı kalmazsınız ve yabancı şemalara sığmayan şeyleri de sunabilirsiniz.
nginx ile önbellek olarak kurulum
Kurulum
apt update
apt install -y nginx
Daha fazlası gerekmiyor, önbellek nginx'in içinde yerleşik. Dosyaların duracağı dizini oluşturun:
mkdir -p /var/cache/cdn
chown www-data:www-data /var/cache/cdn
Yapılandırma
Önbellek bir kez http bloğunda tanımlanır ve sonra tek tek konumlarda kullanılır:
proxy_cache_path /var/cache/cdn
levels=1:2
keys_zone=cdn:100m
max_size=200g
inactive=30d
use_temp_path=off;
proxy_cache_key "$scheme$request_method$host$request_uri";
Değerler tek tek şu anlama gelir: keys_zone=cdn:100m yaklaşık 800.000 kayda yeter, max_size diskteki yeri sınırlar, inactive=30d 30 gün boyunca kimsenin istemediği dosyaları atar ve use_temp_path=off dizinler arasında gereksiz bir taşımayı önler.
Bunun altında da asıl sunucu:
server {
listen 443 ssl;
http2 on;
server_name cdn.example.com;
ssl_certificate /etc/letsencrypt/live/cdn.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cdn.example.com/privkey.pem;
location / {
proxy_pass https://origin.example.com;
proxy_set_header Host origin.example.com;
proxy_http_version 1.1;
proxy_cache cdn;
proxy_cache_valid 200 301 302 24h;
proxy_cache_valid 404 1m;
# aynı anda gelen birden fazla ıskayı tek bir isteğe topla
proxy_cache_lock on;
proxy_cache_lock_timeout 10s;
# kaynakta sorun olduğunda sunmayı sürdür
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
# oturum çerezleri önbelleği patlatmamalı
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
add_header X-Cache-Status $upstream_cache_status always;
}
}
Bunlardan üç satır özel dikkat hak ediyor. proxy_cache_lock, yeni bir dosyada yüz ziyaretçinin aynı anda kaynağa sormasını değil, yalnızca birinin sorup geri kalanların beklemesini sağlar. proxy_cache_use_stale, kaynak yeniden başlarken ya da yavaş yanıt verirken sunmayı ayakta tutar. Set-Cookie başlığının gizlenmesi de oturum çerezi taşıyan tek bir yanıtın bütün önbelleği kullanılamaz hâle getirmesini engeller.
İşe yarayıp yaramadığını sınama
nginx -t && systemctl reload nginx
curl -sI https://cdn.example.com/bild.jpg | grep -i x-cache-status
curl -sI https://cdn.example.com/bild.jpg | grep -i x-cache-status
İlk çağrıda orada MISS, ikincide HIT yazar. İkinci kez de MISS yazıyorsa bu neredeyse her zaman üç olağan şüpheliden birine bağlıdır: yanıttaki bir Set-Cookie, kaynaktan gelen bir Cache-Control: no-store ya da eksik bir uzunluk bilgisi.
Neyin önbelleğe alınacağı, neyin alınmayacağı
Temiz çözüm, bunu kaynağın kendisinin söylemesidir. İçeriklerini o bilir, önbellek bilmez. Bunun için uygun başlıkları ayarlar:
| İçerik | Kaynaktaki başlık |
|---|---|
| Adında sağlama toplamı olan dosya | Cache-Control: public, max-age=31536000, immutable |
| Sürümlenmemiş görsel ya da indirme | Cache-Control: public, max-age=86400 |
| Herkese açık bir sayfanın HTML'i | Cache-Control: public, max-age=300 |
| Oturum açılan bölüm, alışveriş sepeti | Cache-Control: private, no-store |
Kararı önbellekte kendiniz vermek istiyorsanız bu, dosya türüne göre ayrı konumlarla olur:
location ~* \.(jpg|jpeg|png|gif|webp|avif|svg|ico|css|js|woff2|mp4|zip)$ {
proxy_pass https://origin.example.com;
proxy_cache cdn;
proxy_cache_valid 200 7d;
add_header Cache-Control "public, max-age=604800";
add_header X-Cache-Status $upstream_cache_status always;
}
İçerikleri hedefli biçimde atma
En kolay yol, hiç silmek zorunda kalmamaktır: Değişen her görsele yeni bir dosya adı veren kişi, örneğin logo.a1b2c3.png, bu sorunu yaşamaz. Eski dosya zamanla kendiliğinden önbellekten düşer.
Bu mümkün değilse nginx'te ücretsiz ngx_cache_purge modülü yardımcı olur. Ek modül olmadan da yol, önbellek anahtarından hesaplanabilir, çünkü nginx anahtarın MD5 toplamını dosya adı olarak kullanır:
KEY="httpsGETcdn.example.com/bild.jpg"
H=$(printf '%s' "$KEY" | md5sum | cut -d' ' -f1)
rm -f "/var/cache/cdn/${H: -1}/${H: -3:2}/$H"
Günlük kullanımda genellikle bu satırları bir yol listesi için çalıştıran küçük bir betik yeterlidir.
Büyük dosyalar ve videolar
Birkaç yüz megabaytın üzerindeki dosyalarda bloklara ayırma gerekir, aksi hâlde önbellek videodaki her atlamada bütün dosyayı yeniden indirir:
location /video/ {
proxy_pass https://origin.example.com;
proxy_cache cdn;
proxy_cache_valid 200 206 7d;
slice 1m;
proxy_set_header Range $slice_range;
proxy_cache_key "$uri$slice_range";
}
Böylece nginx yalnızca gerçekten istenen blokları alır. Bir izleyici filmin ortasına atladığında hattan birkaç gigabayt değil, birkaç megabayt geçer.
TLS, HTTP/2 ve HTTP/3
Bir CDN düğümü çok sayıda bağlantıya çok sayıda küçük dosya sunar; yeni protokoller de tam orada karşılığını verir. HTTP/2, http2 on; ile tamamlanır. HTTP/3 ise asıl kazancını mobil bağlantılarda getirir, çünkü ağ değişimi bağlantının kopmasına yol açmaz:
listen 443 quic reuseport;
listen 443 ssl;
http2 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
Bu arada güvenlik duvarında UDP 443'ü açmayı unutmayın. HTTP/3'ün kurulu olduğu hâlde kimsenin kullanmamasının en sık görülen sebebi budur.
Birden fazla lokasyon
Tek bir düğüm kazancın en büyük bölümünü, yani kaynağın yükünün azalmasını zaten sağlar. İkinci kazanç, yani ziyaretçiye giden kısa yollar, ancak birden fazla lokasyonla gelir.
Dağıtım DNS üzerinden işler: Aynı ad, ziyaretçinin nereden geldiğine göre başka bir düğümü gösterir. Bunun için coğrafi eşleme yapabilen bir DNS sağlayıcısına ihtiyacınız var. Bütün düğümler aynı yapılandırmayı ve aynı kaynağı alır, birbirlerinden haberleri olmaz ve kurulumu bu kadar dayanıklı kılan da tam olarak budur: Bir düğüm devre dışı kalırsa onu DNS'ten çıkarırsınız, geri kalanlar devralır.
KernelHost Almanya'da, ABD Batı Yakası'nda, ABD Doğu Yakası'nda, ayrıca Singapur ve Güney Kore'de lokasyonlar sunuyor. Gecikme süreleriyle birlikte genel bir bakışı sunucu lokasyonları altında bulabilirsiniz. Kaba kural: Ziyaretçi kitlenizin kayda değer bir bölümünün bulunduğu her kıtaya bir düğüm.
Tahmin yerine ölçüm
Önbellek durumunu kayda yazın, böylece isabet oranını istediğiniz zaman sayabilirsiniz:
log_format cdn '$remote_addr $status $body_bytes_sent '
'$upstream_cache_status "$request"';
access_log /var/log/nginx/cdn.log cdn;
Bunu tek satırlık bir komutla değerlendirebilirsiniz:
awk '{print $4}' /var/log/nginx/cdn.log | sort | uniq -c | sort -rn
HIT payı statik dosyalarda yüzde 90'ın altındaysa sebebi aramak neredeyse her zaman değer: Genellikle yanıtlardaki çerezler, fazla kısa geçerlilik süreleri ya da adresin sonunda değişen parametreler taşıyan istekler söz konusudur; bunlar önbelleğe her seferinde yeni bir dosya gibi görünür.
Hangi sunucu uygun
Bir CDN düğümü bir sunum makinesidir. Önemli özelliklerin sıralaması bu yüzden bir uygulama sunucusundakinden farklı görünür:
- Trafik ve bağlantı. Bütün yük burada doğar. Bir düğüm işletimde düzenli olarak ayda birkaç terabayt aktarır.
- Disk. NVMe açık ara avantajlıdır, çünkü önbellek çok sayıda küçük ve rastgele erişimden oluşur. Boyut, elinizdeki içeriğin ne kadarının sıcak olduğuna göre belirlenir, içeriğin toplamda ne kadar büyük olduğuna göre değil.
- RAM. İşletim sistemi boş belleği diskin önünde ikinci bir önbellek olarak kullanır. Burada daha fazla RAM doğrudan daha fazla hız anlamına gelir.
- CPU. En az kritik olanı; yalnızca TLS için gerekir ve bunu modern işlemciler yan işi olarak hallediyor.
Tam olarak bu durum için yapılmış olan Sınırsız Trafik root sunucularımız: sunucu başına kısıtlama olmadan gerçek 2 × 1 Gbit/s, sabit aylık fiyata sınırsız hacim, RAID içinde datacenter NVMe ve kutudan çıktığı gibi 3,2 Tbps flood koruması. Hazırlık 30 saniyenin altında sürüyor; tam root erişimi, IPv4 ve bir /64 IPv6 ağıyla. Faturalandırma PrePaid esasına göre yapıldığı ve aylık olarak iptal edilebildiği için bir düğümle başlayıp, ziyaretçi kitleniz dağıldığında istediğiniz zaman ikinci bir lokasyon ekleyebilirsiniz.
Sıkça sorulan sorular
CDN sunucusu tam olarak ne yapar?
Bu gerçekte yükü ne kadar azaltır?
Bunun için ticari bir sağlayıcıya ihtiyacım var mı?
Hangi dosyaları önbelleğe almalıyım, hangilerini almamalıyım?
Önbellek dosyaları ne kadar süre tutmalı?
Bir dosyayı önbellekten nasıl silerim?
Kaynak sunucu devre dışı kalırsa ne olur?
Bu, büyük video dosyaları için de işler mi?
Kaç lokasyona ihtiyacım var?
Önbelleğin çalıştığını nasıl anlarım?
2026 KernelHost GmbH. Tüm hakları saklıdır. Bu rehber telif hakkıyla korunmaktadır. Yazının başka web sitelerinde tamamen, kısmen ya da düzenlenmiş biçimde yayımlanması, yazılı iznimiz olmadan serbest değildir. Kaynak belirtilerek ve bağlantı verilerek yapılan alıntılar ise memnuniyetle karşılanır.

