Montar um servidor CDN próprio: buscar uma vez, entregar mil vezes
Um servidor CDN vai buscar cada ficheiro uma vez à origem e entrega-o depois mil vezes por si próprio. O servidor de origem passa a ver apenas uma fração dos pedidos, e os visitantes têm tempos de carregamento curtos. Veja como se monta um.
Cada ficheiro que um visitante carrega da sua página é lido pelo seu servidor de origem no sistema de ficheiros, empacotado numa resposta e enviado. Com dez visitantes por dia, ninguém nota. Com dez mil visitantes em simultâneo, é exatamente essa a razão por que a página fica lenta, apesar de a própria aplicação não ter nada que fazer.
Um servidor CDN coloca-se à frente. Vai buscar cada ficheiro uma vez à origem e entrega-o depois por si próprio, tantas vezes quantas forem necessárias. A origem passa a ver apenas uma fração dos pedidos, e os visitantes recebem os seus ficheiros de um servidor que não faz nada além de entregar. Este artigo mostra quanto isso rende realmente, como se monta um servidor destes com nginx e o que conta no tráfego e na localização.
O que um servidor CDN faz realmente
O processo conta-se em três frases:
- Um visitante pede um ficheiro ao servidor CDN.
- Se já está lá, sai imediatamente. É um acerto.
- Se não está lá, o servidor CDN vai buscá-lo à origem, guarda-o e entrega-o. É uma falha, e acontece por ficheiro apenas uma vez por período de validade.
O princípio é o mesmo de um servidor de streaming: buscar uma vez, entregar muitas vezes. A diferença está apenas em que um servidor de streaming distribui um fluxo de dados em curso e um servidor CDN distribui ficheiros prontos.
A conta: quanto alivia uma cache
Decisiva é a taxa de acertos, ou seja, a parte dos pedidos que a própria cache responde. Com um milhão de pedidos por dia, o alívio tem este aspeto:
| Taxa de acertos | Pedidos na origem | Alívio |
|---|---|---|
| 50 % | 500 000 | fator 2 |
| 80 % | 200 000 | fator 5 |
| 95 % | 50 000 | fator 20 |
| 99 % | 10 000 | fator 100 |
Em ficheiros estáticos, 95 por cento e mais é o caso normal, porque imagens, scripts e tipos de letra mudam raramente. O salto de 95 para 99 por cento é aí mais valioso do que os números deixam supor: volta a dividir por cinco a carga que resta.
Ao mesmo tempo, o tráfego desloca-se. A origem quase não transfere nada, e o servidor CDN tanto mais. Com 500 000 acessos a imagens por dia, a 400 KB cada, são 200 GB diários, ou seja, cerca de 6 TB por mês, só em imagens. Por isso, num nó CDN, o número importante não é a CPU, mas a ligação e o volume.
Quando vale a pena um servidor CDN próprio
Os fornecedores comerciais de CDN cobram por gigabyte transferido. Isso é cómodo e, com pouco volume, barato. A partir de uma certa quantidade, a relação inverte-se:
| Caso | Servidor CDN próprio | Faturação por gigabyte |
|---|---|---|
| Poucos GB por mês | quase não vale a pena | mais barato |
| Muitos TB por mês | preço mensal fixo | cresce linearmente |
| Downloads grandes, arquivos de vídeo | claramente em vantagem | fica depressa caro |
| Controlo total sobre regras e registos | completo | limitado |
A isto junta-se um ponto difícil de quantificar: num nó próprio, é você que decide o que vai para a cache, por quanto tempo e quando desaparece. Não está preso às regras de um fornecedor alheio e pode entregar também coisas que não encaixam em esquemas de terceiros.
Montagem com nginx como cache
Instalar
apt update
apt install -y nginx
Não é preciso mais nada, a cache está integrada no nginx. Crie o diretório onde os ficheiros devem ficar:
mkdir -p /var/cache/cdn
chown www-data:www-data /var/cache/cdn
Configurar
A cache é descrita uma vez no bloco http e depois usada em cada local:
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";
Os valores significam o seguinte: keys_zone=cdn:100m dá para cerca de 800 000 entradas, max_size limita o espaço no disco, inactive=30d deita fora os ficheiros que ninguém pediu durante 30 dias, e use_temp_path=off evita uma movimentação desnecessária entre diretórios.
Abaixo, o servidor propriamente dito:
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;
# juntar num só pedido várias falhas simultâneas
proxy_cache_lock on;
proxy_cache_lock_timeout 10s;
# continuar a entregar quando a origem tem problemas
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
# os cookies de sessão não podem rebentar a cache
proxy_ignore_headers Set-Cookie;
proxy_hide_header Set-Cookie;
add_header X-Cache-Status $upstream_cache_status always;
}
}
Três linhas daqui merecem atenção especial. O proxy_cache_lock faz com que, num ficheiro novo, não sejam cem visitantes a pedir a origem ao mesmo tempo, mas apenas um, enquanto os restantes esperam. O proxy_cache_use_stale mantém a entrega a funcionar enquanto a origem reinicia ou responde devagar. E esconder o Set-Cookie evita que uma única resposta com cookie de sessão torne a cache inteira inútil.
Verificar se funciona
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
No primeiro acesso aparece lá MISS, no segundo HIT. Se também na segunda vez aparecer MISS, a causa está quase sempre num dos três suspeitos habituais: um Set-Cookie na resposta, um Cache-Control: no-store vindo da origem ou uma indicação de comprimento que falta.
O que vai para a cache e o que não vai
A solução limpa é a própria origem dizê-lo. Ela conhece os seus conteúdos, a cache não. Para isso define os cabeçalhos adequados:
| Conteúdo | Cabeçalho na origem |
|---|---|
| Ficheiro com soma de verificação no nome | Cache-Control: public, max-age=31536000, immutable |
| Imagem ou download sem versionamento | Cache-Control: public, max-age=86400 |
| HTML de uma página pública | Cache-Control: public, max-age=300 |
| Área autenticada, carrinho de compras | Cache-Control: private, no-store |
Se quiser decidir na própria cache, isso faz-se com locais próprios por tipo de ficheiro:
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;
}
Livrar-se de conteúdos de forma direcionada
O caminho mais simples é não ter de apagar nada: quem dá um nome de ficheiro novo a cada imagem alterada, por exemplo logo.a1b2c3.png, não tem o problema. O ficheiro antigo acaba por cair da cache sozinho.
Se isso não for possível, no nginx ajuda o módulo livre ngx_cache_purge. Sem módulo adicional, o caminho pode ser calculado a partir da chave de cache, porque o nginx usa a soma MD5 dessa chave como nome de ficheiro:
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"
Para o dia a dia basta normalmente um pequeno script que execute estas linhas para uma lista de caminhos.
Ficheiros grandes e vídeos
Em ficheiros acima de algumas centenas de megabytes precisa da divisão em blocos, caso contrário a cache volta a carregar o ficheiro inteiro a cada salto no vídeo:
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";
}
Assim o nginx vai buscar apenas os blocos que são realmente pedidos. Se um espectador salta para o meio de um filme, passam poucos megabytes pela linha em vez de vários gigabytes.
TLS, HTTP/2 e HTTP/3
Um nó CDN entrega muitos ficheiros pequenos a muitas ligações, e é precisamente aí que os protocolos mais recentes compensam. O HTTP/2 fica resolvido com http2 on;. O HTTP/3 traz vantagens sobretudo em ligações móveis, porque uma mudança de rede não faz cair a ligação:
listen 443 quic reuseport;
listen 443 ssl;
http2 on;
add_header Alt-Svc 'h3=":443"; ma=86400';
Não se esqueça de abrir o UDP 443 na firewall. É a razão mais frequente para o HTTP/3 estar configurado e, apesar disso, ninguém o usar.
Vários locais
Um único nó já traz a maior parte do ganho, ou seja, o alívio da origem. O segundo ganho, caminhos curtos até ao visitante, só chega com vários locais.
A distribuição corre por DNS: o mesmo nome aponta para um nó diferente conforme a proveniência do visitante. Para isso precisa de um fornecedor de DNS com atribuição geográfica. Todos os nós recebem a mesma configuração e a mesma origem, não sabem nada uns dos outros, e é precisamente isso que torna a montagem tão robusta: se um nó falha, tira-o do DNS e os restantes assumem.
A KernelHost oferece locais na Alemanha, na costa oeste dos EUA, na costa leste dos EUA, bem como em Singapura e na Coreia do Sul. Encontra uma visão geral com latências em Localizações de servidores. Como regra prática: um nó por cada continente em que esteja uma parte considerável do seu público.
Medir em vez de adivinhar
Escreva o estado da cache no registo, assim pode contar a taxa de acertos em qualquer momento:
log_format cdn '$remote_addr $status $body_bytes_sent '
'$upstream_cache_status "$request"';
access_log /var/log/nginx/cdn.log cdn;
A avaliação faz-se com uma única linha:
awk '{print $4}' /var/log/nginx/cdn.log | sort | uniq -c | sort -rn
Se a parte de HIT em ficheiros estáticos ficar abaixo de 90 por cento, procurar a causa compensa quase sempre: normalmente são cookies nas respostas, validades demasiado curtas ou pedidos com parâmetros variáveis no fim do endereço, que para a cache parecem de cada vez um ficheiro novo.
Que servidor serve
Um nó CDN é uma máquina de entrega. A ordem das propriedades importantes é por isso diferente da de um servidor de aplicação:
- Tráfego e ligação. É aqui que nasce toda a carga. Em funcionamento, um nó transfere regularmente vários terabytes por mês.
- Disco. O NVMe está claramente em vantagem, porque a cache consiste em muitos acessos pequenos e aleatórios. O tamanho orienta-se pela parte do seu acervo que está quente, não pelo tamanho total do acervo.
- RAM. O sistema operativo usa a memória livre como segunda cache à frente do disco. Aqui, mais RAM significa diretamente mais velocidade.
- CPU. O menos crítico, só é precisa para TLS, e isso os processadores modernos fazem de passagem.
É exatamente para este caso que os nossos servidores root com tráfego ilimitado foram feitos: 2 × 1 Gbit/s reais por servidor sem estrangulamento, volume ilimitado a preço mensal fixo, NVMe de datacenter em RAID e 3,2 Tbps de proteção contra floods de fábrica. A disponibilização leva menos de 30 segundos, com acesso root completo, IPv4 e uma rede IPv6 /64. Como a faturação é em regime PrePaid e cancelável mensalmente, pode começar com um nó e acrescentar a qualquer momento um segundo local, quando o seu público se distribuir.
Perguntas frequentes
O que faz exatamente um servidor CDN?
Quanto alivia isto realmente?
Preciso de um fornecedor comercial para isto?
Que ficheiros devo colocar em cache e quais não?
Quanto tempo deve a cache guardar os ficheiros?
Como apago um ficheiro da cache?
O que acontece se o servidor de origem falhar?
Isto também funciona para ficheiros de vídeo grandes?
De quantos locais preciso?
Como vejo que a cache está a funcionar?
2026 KernelHost GmbH. Todos os direitos reservados. Este guia está protegido por direitos de autor. A sua republicação noutros sites, na íntegra, em parte ou de forma editada, não é permitida sem o nosso consentimento por escrito. Citações com indicação da fonte e ligação são expressamente bem-vindas.

