CDN Edge Caching: Cloudflare, CloudFront, Fastly
Configura reglas de edge caching en Cloudflare, AWS CloudFront y Fastly: políticas de TTL, claves de caché, purga y stale-while-revalidate.
Visión General
Tu aplicación sirve usuarios en tres continentes desde un único origen en us-east-1, y todo el que está fuera de EE. UU. espera más de 300 ms por cada asset. Una CDN coloca copias en caché en nodos edge cercanos a cada usuario, así que los archivos estáticos de una página dejan de cruzar el Atlántico en cada petición. Esta receta configura los tres proveedores más habituales: cache rules de Cloudflare, cache policies de CloudFront vía Terraform y VCL de Fastly — más los patrones de purga que mantienen el caché honesto.
Cuándo Usar
Usa este recurso cuando:
- Los assets estáticos (JS, CSS, fuentes, imágenes) se sirven a una audiencia distribuida geográficamente
- El origen gasta CPU re-renderizando respuestas idénticas para tráfico anónimo
- Las respuestas de API son cacheables y se benefician del caché edge con
s-maxage - Necesitas descargas cacheables cerca de los usuarios para reducir costos de egress
Omite el edge caching cuando:
- Tu audiencia está concentrada en una región cercana al origen: el salto extra no aporta nada
- Las respuestas son por usuario y no compartibles (saldos bancarios, páginas de sesión): usa
Cache-Control: privatey sáltate la CDN en esas rutas - Estás en un plan gratuito con mucho tráfico; el ahorro de ancho de banda existe, pero las funciones de pago (claves de caché personalizadas, purga por tags) pueden costar más que el egress del origen
Requisitos
- Una cuenta de CDN: zona de Cloudflare, cuenta de AWS para CloudFront, o un servicio de Fastly
- Un token de API con permisos sobre cache rules (Cloudflare) o permisos IAM para CloudFront
- Opcional: Terraform 1.5+ para el ejemplo de CloudFront; AWS CLI para las invalidaciones
- Un navegador o
curl -Ipara verificar los headers de respuesta (Age,CF-Cache-Status,X-Cache)
Código companion: el repo companion de cdn-edge-caching tiene el módulo Terraform, el JSON de cache rules, el archivo VCL y los scripts de purga listos para adaptar.
Solución
Cloudflare: cache rules vía la Ruleset API
Las Page Rules quedaron deprecadas en favor de las cache rules del Ruleset Engine. Una sola llamada a rulesets puede crear varias reglas a la vez:
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/rulesets" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "static-asset-caching",
"kind": "zone",
"phase": "http_request_cache_settings",
"rules": [{
"expression": "(http.request.uri.path.extension in {\"css\" \"js\" \"png\" \"jpg\" \"woff2\"})",
"action": "set_cache_settings",
"action_parameters": {
"edge_ttl": { "mode": "override_origin", "default": 2592000 },
"browser_ttl": { "mode": "override_origin", "default": 86400 }
},
"enabled": true
}]
}'
edge_ttl controla cuánto tiempo conserva el objeto Cloudflare; browser_ttl lo que le indica al navegador. Ambos usan override_origin porque las URLs hasheadas hacen seguro un TTL edge de 30 días, porque un nuevo despliegue trae URLs nuevas.
AWS CloudFront: cache policy con Terraform
resource "aws_cloudfront_distribution" "cdn" {
enabled = true
origin {
domain_name = aws_s3_bucket.static.bucket_regional_domain_name
origin_id = "S3Origin"
}
default_cache_behavior {
target_origin_id = "S3Origin"
viewer_protocol_policy = "redirect-to-https"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = true
cache_policy_id = aws_cloudfront_cache_policy.static.id
}
}
resource "aws_cloudfront_cache_policy" "static" {
name = "static-assets"
min_ttl = 1
default_ttl = 86400
max_ttl = 31536000
parameters_in_cache_key {
headers_config { header_behavior = "none" }
cookies_config { cookie_behavior = "none" }
query_strings_config { query_string_behavior = "none" }
}
}
El bloque parameters_in_cache_key es la parte importante: mantener headers, cookies y query strings fuera de la clave de caché es lo que hace que la distribución realmente cachee. Cada parámetro añadido a la clave multiplica el número de entradas por asset.
Fastly: VCL
sub vcl_recv {
# Marca los assets estáticos hasheados para que vcl_fetch los trate como inmutables
if (req.url.ext ~ "^(css|js|png|jpg|woff2)$") {
set req.http.X-Static = "true";
}
}
sub vcl_fetch {
if (req.http.X-Static == "true") {
set beresp.ttl = 365d;
set beresp.http.Cache-Control = "public, max-age=31536000, immutable";
set beresp.http.Surrogate-Key = "static";
}
}
Surrogate-Key agrupa objetos para la purga: PURGE /service/<id>/purge/static vacía todo lo etiquetado como static sin tocar el resto del caché.
Explicación
Toda CDN se reduce al mismo flujo:
Un cache hit sirve la respuesta desde el PoP sin tocar tu origen — de ahí vienen la reducción de latencia y la descarga del servidor. Un cache miss pide al origen, guarda la respuesta según la cache policy y la sirve. El TTL decide cuánto tiempo el edge confía en esa copia antes de revalidar.
La clave de caché es donde se gana o se pierde el hit ratio. Si tu clave incluye ?utm_source=twitter, cada enlace de marketing se convierte en una entrada aparte y el hit ratio se desploma; la policy de CloudFront anterior elimina los query strings justo por eso. Si sí necesitas respuestas que varíen, añade solo el parámetro concreto (?v=) a la clave en lugar de aceptarlos todos.
Para contenido en vivo, Cache-Control se divide en dos TTLs: max-age para el navegador y s-maxage para la CDN. Cache-Control: max-age=0, s-maxage=60 le dice a los navegadores “revalida siempre” mientras el edge conserva la respuesta un minuto — suficiente para absorber un pico, tan corto que la obsolescencia es invisible. stale-while-revalidate va más allá: sirve la copia obsoleta al instante mientras el edge la refresca en segundo plano.
La mecánica profunda de cache-control está en headers HTTP Cache-Control, y las estrategias de purga y tags se cubren en invalidación de caché en CDN.
Uso Avanzado
Purgar en lugar de esperar
Cuando el contenido debe cambiar antes de que expire su TTL:
# CloudFront: invalidar por ruta
aws cloudfront create-invalidation \
--distribution-id E1EXAMPLE \
--paths "/assets/*"
# Cloudflare: purgar por URL
curl -X POST "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"files": ["https://example.com/app.js"]}'
# Fastly: purgar por surrogate key
curl -X POST "https://api.fastly.com/service/$SERVICE_ID/purge/static" \
-H "Fastly-Key: $FASTLY_API_TOKEN"
La purga por surrogate key de Fastly es instantánea y acotada; la purga por tags de Cloudflare funciona igual pero requiere plan Enterprise; en otros planes purgas por URL o por host. Las invalidaciones de CloudFront se propagan a todos los nodos edge en unos minutos y se cobran pasados los 1000 paths gratuitos al mes, por eso los nombres de archivo versionados siguen siendo más baratos que invalidar.
Servir obsoleto cuando el origen cae
stale-while-revalidate y stale-if-error permiten al edge servir una copia expirada en lugar de dar error:
Cache-Control: max-age=60, s-maxage=300, stale-while-revalidate=86400, stale-if-error=604800
Con ese header, una caída del origen se degrada a “los usuarios ven contenido de hasta una semana” en lugar de errores 500: mejora de disponibilidad gratis para contenido casi estático.
Variantes
| Proveedor | Configuración | Control de clave de caché | Modelo de purga |
|---|---|---|---|
| Cloudflare | Dashboard, Ruleset API, Terraform | Cache rules, claves personalizadas | URL, tag (Enterprise), host |
| AWS CloudFront | Console, Terraform, CDK | Cache policies + origin request policies | Invalidaciones por ruta |
| Fastly | VCL, API, Terraform | Control total vía VCL | Purga instantánea por key/URL/surrogate |
| Akamai | Control Center, PAPI | Reglas de Property Manager | Fast Purge API, cache tags |
Lo Que Funciona
- Versiona los nombres de archivo de los assets (
app.v2.js,style.a1b2c3.css) para que la propia URL sea la clave de caché, así que los despliegues nuevos nunca pelean con entradas viejas - Mantén la clave de caché mínima: headers, cookies y query strings en la clave fragmentan el caché y matan el hit ratio
max-age=0, s-maxage=Npara contenido seguro en el edge pero no en el navegadorstale-while-revalidatepara que los usuarios nunca esperen un refresh, ystale-if-errorpara caídas del origen- Monitorea el hit ratio (
CF-Cache-Statusde Cloudflare,X-Cachede CloudFront,Fastly-Debugde Fastly) y trata las caídas como mala configuración, no como ruido
Errores Comunes
- Cachear respuestas que llevan
Set-Cookie: una cookie de sesión servida al usuario equivocado es una fuga de datos, no una ganancia de rendimiento - Purgas completas en cada despliegue: vacían todos los edges a la vez; los nombres versionados y las purgas por tag lo evitan
- Ignorar los query strings en la clave de caché (
?utm_source=...crea miles de entradas duplicadas) max-agelargo en el HTML que referencia assets versionados; el HTML es el puntero mutable, dale un TTL corto- Asumir que la CDN cachea POST: solo GET/HEAD son cacheables en las políticas por defecto
Lectura Adicional
- Documentación de cache rules de Cloudflare: Ruleset API, expresiones y modos de TTL
- Cache policies de AWS CloudFront: policies gestionadas vs personalizadas y composición de la clave
- Guía de caching de Fastly: ciclo de vida VCL, surrogate keys y shielding
Preguntas frecuentes
¿Cómo cacheo respuestas de API en el edge?
Dales s-maxage para que la CDN cachee mientras los navegadores no (Cache-Control: max-age=0, s-maxage=60), y asegúrate de que la clave de caché incluya lo que varía la respuesta — normalmente la ruta más los query params concretos. Las respuestas con Set-Cookie o Authorization se omiten en las políticas por defecto, que suele ser lo que quieres.
¿Cuál es la diferencia entre purgar e invalidar?
Misma idea, distinto verbo: ambos marcan objetos cacheados como inutilizables para que la siguiente petición los reobtenga. Fastly lo llama purge (instantáneo), CloudFront invalidación (se propaga en minutos y se factura por ruta). Si la URL cambió (nombres versionados) no necesitas ninguno.
¿Merece la pena el edge caching para backends de solo API?
Sí cuando las respuestas son compartidas y cacheables: catálogos de producto, configuraciones públicas, estadísticas agregadas. Es inútil para respuestas por usuario, que deben llevar Cache-Control: private. GraphQL es más difícil que REST aquí porque todo es un POST a un solo endpoint; necesitarías lógica en el edge para normalizar las queries en claves de caché.
¿Cuánto deben durar mis TTLs?
Tanto como la URL siga siendo válida. Los nombres hasheados (app.a1b2c3.js) justifican immutable + TTLs de un año porque un cambio de contenido produce una URL nueva. El HTML y los datos vivos deben ser cortos — de segundos a un minuto en el edge — porque no puedes invalidar lo que ya tiene el navegador.
¿Puedo cachear contenido autenticado o personalizado?
No por defecto, y eso es protector. Si realmente lo necesitas, incluye la dimensión de autenticación en la clave de caché (Vary: Authorization, o un worker en el edge que varíe por una clave derivada de sesión) para que usuarios distintos nunca compartan una entrada. Mal configurado, es un vector de fuga de datos.
Recursos Relacionados
Estrategias y patrones de invalidación de caché CDN
Implementa invalidación de caché CDN usando purge APIs, surrogate keys, invalidación por tags y URLs versionadas para mantener el contenido fresco
RecipeConfigurar headers HTTP Cache-Control para APIs y assets
Establece headers Cache-Control, ETag y Last-Modified para controlar la caché de navegadores y CDN en respuestas de API y assets estáticos
RecipeHabilita compresión Brotli en Nginx para assets estáticos
Configura compresión Brotli en Nginx para reducir assets de JavaScript, CSS y HTML con mejores ratios que Gzip y cargar más rápido.
RecipeCachear Respuestas HTTP con Nginx Reverse Proxy
Configura Nginx como reverse proxy con cache para almacenar respuestas HTTP upstream con zonas TTL, claves de cache y purge condicional.
RecipeImplementar Estrategias de Invalidación de Caché
Cómo mantener la caché consistente con las bases de datos usando TTL, write-through, write-behind y patrones de invalidación event-driven.
GuideEstrategia de Caching CDN
Disenar caching CDN para aplicaciones web y APIs. Cubre edge caching, cache keys, cache headers, estrategias de invalidacion, surrogate keys y setups multi-CDN para rendimiento global.