Postavit vlastní CDN server: jednou stáhnout, tisíckrát vydat
CDN server stáhne každý soubor ze zdroje jednou a potom ho tisíckrát vydá sám. Zdrojový server vidí už jen zlomek požadavků a návštěvníci dostanou krátké doby načítání. Takto si jeden postavíte.
Každý soubor, který si návštěvník z vaší stránky stáhne, vytáhne váš zdrojový server ze souborového systému, zabalí ho do odpovědi a vypraví ho na cestu. Při deseti návštěvnících za den si toho nikdo nevšimne. Při deseti tisících současných návštěvníků je přesně to důvod, proč se stránka zpomalí, přestože samotná aplikace nemá vůbec co dělat.
CDN server se před něj postaví. Každý soubor stáhne ze zdroje (origin) jednou a potom ho vydává sám, tolikrát, kolikrát je potřeba. Zdroj tím vidí už jen zlomek požadavků a návštěvníci dostávají své soubory ze serveru, který nedělá nic jiného než výdej. Tento článek ukazuje, kolik to skutečně přinese, jak takový server postavíte s nginx a na čem záleží u trafficu a lokality.
Co CDN server skutečně dělá
Celý postup se vypráví ve třech větách:
- Návštěvník si vyžádá soubor od CDN serveru.
- Pokud tam už leží, jde okamžitě ven. To je zásah.
- Pokud tam neleží, CDN server si ho vyzvedne ze zdroje, odloží ho a vydá ho. To je minutí a na každý soubor se stane jen jednou za dobu platnosti.
Princip je stejný jako u streamovacího serveru: jednou stáhnout, mnohokrát vydat. Rozdíl je jen v tom, že streamovací server rozdává běžící tok dat a CDN server hotové soubory.
Výpočet: jak moc cache odlehčí
Rozhodující je úspěšnost cache, tedy podíl požadavků, které cache odpoví sama. Při milionu požadavků za den vypadá odlehčení takto:
| Úspěšnost cache | Požadavky na zdroji | Odlehčení |
|---|---|---|
| 50 % | 500 000 | faktor 2 |
| 80 % | 200 000 | faktor 5 |
| 95 % | 50 000 | faktor 20 |
| 99 % | 10 000 | faktor 100 |
U statických souborů je 95 procent a více normální stav, protože obrázky, skripty a fonty se mění zřídka. Skok z 95 na 99 procent je přitom cennější, než čísla naznačují: zbývající zátěž ještě jednou zmenší na pětinu.
Zároveň se přesune traffic. Zdroj přenáší už téměř nic, CDN server o to víc. Při 500 000 vyvoláních obrázků za den po 400 KB je to 200 GB denně, tedy přibližně 6 TB za měsíc, jen za obrázky. Proto není u uzlu CDN důležitým číslem CPU, ale konektivita a objem.
Kdy se vlastní CDN server vyplatí
Komerční poskytovatelé CDN účtují za každý přenesený gigabyte. To je pohodlné a při malém objemu výhodné. Od určitého množství se poměr obrací:
| Případ | Vlastní CDN server | Účtování za gigabyte |
|---|---|---|
| Několik GB za měsíc | vyplatí se málo | výhodnější |
| Mnoho TB za měsíc | pevná měsíční cena | roste lineárně s objemem |
| Velké soubory ke stažení, videoarchivy | jasně ve výhodě | rychle se prodraží |
| Plná kontrola nad pravidly a protokoly | úplná | omezená |
K tomu přichází bod, který se dá špatně vyčíslit: u vlastního uzlu rozhodujete sami, co se cachuje, jak dlouho a kdy to zmizí. Nejste vázáni pravidly cizího poskytovatele a můžete vydávat i věci, které se do cizích schémat nevejdou.
Stavba s nginx jako cache
Instalace
apt update
apt install -y nginx
Víc není potřeba, cache je v nginx zabudovaná. Vytvořte adresář, v němž mají soubory ležet:
mkdir -p /var/cache/cdn
chown www-data:www-data /var/cache/cdn
Konfigurace
Cache se jednou popíše v bloku http a potom se používá v jednotlivých blocích location:
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";
Hodnoty znamenají jednotlivě: keys_zone=cdn:100m stačí asi na 800 000 záznamů, max_size omezuje místo na disku, inactive=30d zahodí soubory, na které 30 dní nikdo nepožádal, a use_temp_path=off se vyhne nepotřebnému přesouvání mezi adresáři.
Pod tím vlastní server:
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;
# sloučit několik současných minutí do jednoho požadavku
proxy_cache_lock on;
proxy_cache_lock_timeout 10s;
# při problémech na zdroji vydávat dál
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
# cookies relace nesmí cache roztrhat
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
add_header X-Cache-Status $upstream_cache_status always;
}
}
Tři řádky z toho si zaslouží zvláštní pozornost. proxy_cache_lock se stará o to, aby u nového souboru nepožádalo zdroj sto návštěvníků současně, ale jen jeden a ostatní počkali. proxy_cache_use_stale drží výdej v chodu, zatímco se zdroj znovu spouští nebo odpovídá pomalu. A skrytí Set-Cookie zabrání tomu, aby jediná odpověď s cookie relace znehodnotila celou cache.
Zkontrolovat, zda to zabírá
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
Při prvním vyvolání tam stojí MISS, při druhém HIT. Stojí-li i podruhé MISS, je to téměř vždy kvůli jednomu ze tří obvyklých podezřelých: Set-Cookie v odpovědi, Cache-Control: no-store ze zdroje nebo chybějící údaj o délce.
Co se cachuje a co ne
Čisté řešení je, že to řekne zdroj sám. Zná svůj obsah, cache ne. Nastaví k tomu vhodné hlavičky:
| Obsah | Hlavička na zdroji |
|---|---|
| Soubor s kontrolním součtem v názvu | Cache-Control: public, max-age=31536000, immutable |
| Obrázek nebo soubor ke stažení bez verzování | Cache-Control: public, max-age=86400 |
| HTML veřejné stránky | Cache-Control: public, max-age=300 |
| Přihlášená sekce, nákupní košík | Cache-Control: private, no-store |
Chcete-li rozhodovat v cache sami, jde to přes vlastní bloky location pro každý typ souboru:
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;
}
Cíleně se zbavit obsahu
Nejjednodušší cesta je nemuset mazat vůbec: kdo každému změněnému obrázku dá nový název souboru, třeba logo.a1b2c3.png, tento problém nemá. Starý soubor někdy sám vypadne z cache.
Pokud to nejde, pomůže u nginx volný modul ngx_cache_purge. Bez doplňkového modulu lze cestu vypočítat z klíče cache, protože nginx používá jeho součet MD5 jako název souboru:
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"
Pro každodenní provoz obvykle stačí malý skript, který tyto řádky provede pro seznam cest.
Velké soubory a videa
U souborů nad několik set megabajtů potřebujete rozložení na bloky, jinak cache při každém skoku ve videu stáhne celý soubor znovu:
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";
}
Tím stáhne nginx jen bloky, které jsou skutečně vyžádané. Skočí-li divák do poloviny filmu, projde linkou několik megabajtů místo několika gigabajtů.
TLS, HTTP/2 a HTTP/3
Uzel CDN vydává mnoho malých souborů do mnoha spojení, přesně tam se novější protokoly vyplatí. HTTP/2 je vyřízené pomocí http2 on;. HTTP/3 přinese něco především na mobilních připojeních, protože kvůli přepnutí sítě spojení nespadne:
listen 443 quic reuseport;
listen 443 ssl;
http2 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
Nezapomeňte při tom otevřít ve firewallu UDP 443. To je nejčastější důvod, proč je HTTP/3 nastavené a přesto ho nikdo nepoužívá.
Více lokalit
Jediný uzel přinese už největší část přínosu, totiž odlehčení zdroje. Druhý přínos, krátké cesty k návštěvníkovi, přichází teprve s více lokalitami.
Rozdělení běží přes DNS: stejný název ukazuje podle původu návštěvníka na jiný uzel. Potřebujete k tomu poskytovatele DNS s geografickým přiřazením. Všechny uzly dostanou stejnou konfiguraci a stejný zdroj, nevědí o sobě nic, a právě to dělá celou stavbu tak odolnou: vypadne-li uzel, vyndáte ho z DNS a ostatní to převezmou.
KernelHost nabízí lokality v Německu, na západním pobřeží USA, na východním pobřeží USA a také v Singapuru a Jižní Koreji. Přehled s latencemi najdete na stránce lokality serverů. Jako pravidlo palce: jeden uzel na každý kontinent, na němž sedí významná část vašeho publika.
Měřit místo hádání
Zapisujte stav cache do logu, pak můžete úspěšnost cache kdykoli spočítat:
log_format cdn '$remote_addr $status $body_bytes_sent '
'$upstream_cache_status "$request"';
access_log /var/log/nginx/cdn.log cdn;
Vyhodnotit se to dá jednořádkovým příkazem:
awk '{print $4}' /var/log/nginx/cdn.log | sort | uniq -c | sort -rn
Leží-li podíl HIT u statických souborů pod 90 procenty, hledání příčiny se téměř vždy vyplatí: obvykle jsou to cookies v odpovědích, příliš krátké doby platnosti nebo požadavky s měnícími se parametry na konci adresy, které pro cache pokaždé vypadají jako nový soubor.
Který server se hodí
Uzel CDN je výdejní stroj. Pořadí důležitých vlastností proto vypadá jinak než u aplikačního serveru:
- Traffic a konektivita. Tady vzniká celá zátěž. Uzel za provozu pravidelně přenese několik terabajtů za měsíc.
- Disk. NVMe je výrazně ve výhodě, protože cache se skládá z mnoha malých náhodných přístupů. Velikost se řídí tím, kolik z vašeho obsahu je horké, ne tím, jak velký je obsah celkem.
- RAM. Operační systém používá volnou paměť jako druhou cache před diskem. Více RAM tu znamená přímo více tempa.
- CPU. Nejméně kritické, je potřeba jen pro TLS, a to moderní procesory zvládají mimochodem.
Přesně pro tento případ jsou udělané naše root servery s neomezeným trafficem: skutečných 2 × 1 Gbit/s na server bez omezování rychlosti, neomezený objem za pevnou měsíční cenu, datacentrové NVMe v RAIDu a ochrana proti floodu 3,2 Tbps z výroby. Příprava trvá méně než 30 sekund, s plným root přístupem, IPv4 a sítí /64 IPv6. Protože se účtuje na předplacené bázi s možností zrušit kdykoli na konci měsíce, můžete začít s jedním uzlem a kdykoli přidat druhou lokalitu, až se vaše publikum rozloží.
Časté dotazy
Co přesně CDN server dělá?
Jak moc to skutečně odlehčí?
Potřebuji k tomu komerčního poskytovatele?
Které soubory mám cachovat a které ne?
Jak dlouho si má cache soubory držet?
Jak smažu soubor z cache?
Co se stane, když zdrojový server vypadne?
Funguje to i pro velké videosoubory?
Kolik lokalit potřebuji?
Jak poznám, že cache funguje?
2026 KernelHost GmbH. Všechna práva vyhrazena. Tento návod je chráněn autorským právem. Jeho zveřejnění na jiných webech, a to i po částech nebo v upravené podobě, není bez našeho písemného souhlasu dovoleno. Citace s uvedením zdroje a odkazem jsou výslovně vítány.

