· nervico-team · arquitectura-cloud · 11 min read
CDN y CloudFront: configuración óptima para rendimiento web
Guía práctica de Amazon CloudFront: configuración paso a paso, optimización de caché, compresión, seguridad con WAF y costes reales para mejorar el rendimiento web.
Un usuario en Madrid que accede a un servidor en Virginia experimenta una latencia base de 120-150ms. Solo por la distancia física. Añade el tiempo de procesamiento del servidor, las consultas a base de datos y la transferencia de assets (imágenes, CSS, JavaScript), y la primera carga de la página puede tardar 3-5 segundos.
CloudFront reduce esa latencia a 10-30ms sirviendo el contenido desde el edge location más cercano al usuario. AWS opera más de 600 puntos de presencia en 100 ciudades de 50 países. La diferencia es perceptible: una página que carga en 1 segundo en lugar de 3 no solo mejora la experiencia de usuario, sino que mejora directamente las métricas de conversión. Google ha documentado que cada 100ms adicionales de latencia reducen las ventas en un 1%.
Este artículo explica cómo configurar CloudFront de forma óptima, con los parámetros que realmente importan, los errores de configuración que anulan los beneficios del CDN, y los costes reales que puedes esperar.
Cómo funciona CloudFront
El flujo de una petición
Cuando un usuario solicita un recurso a través de CloudFront, el flujo es:
- Resolución DNS: El navegador resuelve el dominio. Route 53 (o el DNS configurado) responde con la IP del edge location más cercano al usuario, basándose en latencia o geolocalización.
- Edge location: La petición llega al punto de presencia más cercano. CloudFront busca el recurso en su caché local.
- Cache hit: Si el recurso está en caché y no ha expirado, CloudFront lo devuelve directamente. Latencia mínima.
- Cache miss: Si el recurso no está en caché, CloudFront lo solicita al Regional Edge Cache (caché intermedia). Si tampoco está ahí, lo solicita al origen (S3, ALB, API Gateway, servidor custom).
- Respuesta: El recurso se devuelve al usuario y se almacena en caché para peticiones futuras.
Usuario (Madrid) → Edge Location (Madrid) → Regional Cache (Frankfurt)
↓ (cache miss)
Origin (S3 / ALB / API)Orígenes soportados
CloudFront puede servir contenido desde múltiples tipos de origen:
- Amazon S3: La opción más común para assets estáticos (HTML, CSS, JS, imágenes). Integración nativa con Origin Access Control (OAC).
- Application Load Balancer (ALB): Para contenido dinámico servido por aplicaciones en ECS, EKS o EC2.
- API Gateway: Para APIs REST o HTTP.
- Lambda@Edge / CloudFront Functions: Para lógica de procesamiento en el edge (redirecciones, autenticación, personalización).
- Origen custom: Cualquier servidor HTTP/HTTPS accesible por internet.
Configuración paso a paso
Distribución para sitio estático en S3
El caso más común: un sitio web estático (React, Next.js, Astro, Vue) desplegado en S3 con CloudFront como CDN.
# Terraform: Distribución CloudFront con S3
resource "aws_cloudfront_distribution" "website" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
aliases = ["www.tudominio.com"]
price_class = "PriceClass_100"
http_version = "http2and3"
origin {
domain_name = aws_s3_bucket.website.bucket_regional_domain_name
origin_id = "S3Origin"
origin_access_control_id = aws_cloudfront_origin_access_control.s3.id
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3Origin"
viewer_protocol_policy = "redirect-to-https"
compress = true
cache_policy_id = aws_cloudfront_cache_policy.optimized.id
origin_request_policy_id = data.aws_cloudfront_origin_request_policy.cors_s3.id
response_headers_policy_id = aws_cloudfront_response_headers_policy.security.id
}
# SPA: redirigir 404 a index.html
custom_error_response {
error_code = 403
response_code = 200
response_page_path = "/index.html"
}
custom_error_response {
error_code = 404
response_code = 200
response_page_path = "/index.html"
}
viewer_certificate {
acm_certificate_arn = aws_acm_certificate.cert.arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
}
# Origin Access Control (reemplaza a OAI)
resource "aws_cloudfront_origin_access_control" "s3" {
name = "s3-oac"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}Notas sobre la configuración:
price_class = "PriceClass_100": Usa solo edge locations en Norteamérica y Europa. Reduce costes un 20-30% frente aPriceClass_All. Si tus usuarios están solo en Europa y América, no necesitas edge locations en Asia u Oceanía.http_version = "http2and3": Habilita HTTP/2 y HTTP/3 (QUIC). HTTP/3 reduce la latencia de conexión inicial en un 30-40% porque usa UDP en lugar de TCP.compress = true: Comprime automáticamente con Brotli o gzip los formatos text/html, application/javascript, text/css, etc. Reduce el tamaño de transferencia un 60-80%.
Políticas de caché
CloudFront usa Cache Policies para determinar qué parámetros de la petición afectan a la clave de caché. Una política bien configurada maximiza el cache hit ratio.
resource "aws_cloudfront_cache_policy" "optimized" {
name = "optimized-cache-policy"
min_ttl = 0
default_ttl = 86400 # 24 horas
max_ttl = 31536000 # 1 año
parameters_in_cache_key_and_forwarded_to_origin {
cookies_config {
cookie_behavior = "none" # No incluir cookies en la cache key
}
headers_config {
header_behavior = "none" # No incluir headers en la cache key
}
query_strings_config {
query_string_behavior = "none" # No incluir query strings
}
enable_accept_encoding_brotli = true
enable_accept_encoding_gzip = true
}
}La regla de oro: Cuantos menos parámetros incluyas en la cache key, mayor será el cache hit ratio. Cada parámetro adicional (cookie, header, query string) crea una variante diferente en caché.
Para assets estáticos con fingerprinting (ej: app.a1b2c3.js), el query string no importa porque el hash está en el nombre del archivo. Para APIs, necesitas incluir query strings relevantes.
Distribución para APIs dinámicas
Para contenido dinámico (APIs, SSR), la configuración cambia:
# Cache behavior para API
ordered_cache_behavior {
path_pattern = "/api/*"
allowed_methods = ["GET", "HEAD", "OPTIONS", "PUT", "POST", "PATCH", "DELETE"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "ALBOrigin"
viewer_protocol_policy = "https-only"
compress = true
# No cachear por defecto; respetar Cache-Control del origen
cache_policy_id = data.aws_cloudfront_cache_policy.caching_disabled.id
origin_request_policy_id = data.aws_cloudfront_origin_request_policy.all_viewer.id
}Principio: Para APIs, desactiva el caché de CloudFront por defecto y deja que el origen controle el comportamiento con headers Cache-Control. CloudFront respeta Cache-Control: max-age=0, no-cache, no-store.
Para endpoints que devuelven datos que cambian con poca frecuencia (catálogo de productos, configuración), puedes activar caché con un TTL corto:
Cache-Control: public, max-age=300, s-maxage=600Esto indica: el navegador cachea 5 minutos, CloudFront cachea 10 minutos.
Optimización avanzada
Cache invalidation vs versioning
Cuando actualizas contenido, tienes dos opciones para que los usuarios vean la versión nueva:
Invalidation: Solicitas a CloudFront que elimine objetos específicos de todas las edge locations.
aws cloudfront create-invalidation \
--distribution-id E1234567890 \
--paths "/index.html" "/css/*" "/js/*"Problemas: Las invalidaciones tardan 5-15 minutos en propagarse globalmente. Las primeras 1.000 rutas/mes son gratuitas; después, 0,005 dolares por ruta.
Versioning (recomendado): Incluye un hash o versión en el nombre del archivo. Los frameworks modernos hacen esto automáticamente.
app.a1b2c3d4.js (versión actual)
app.e5f6g7h8.js (versión nueva)Con versioning, el nuevo archivo tiene un nombre diferente. CloudFront lo solicita al origen como un recurso nuevo. No necesitas invalidar nada. El archivo antiguo se sirve desde caché hasta que expira, pero nadie lo solicita porque el HTML referencia la versión nueva.
Excepción: index.html no puede tener versionado en el nombre porque es el punto de entrada. Para este archivo, configura un TTL corto (60-300 segundos) o usa invalidación después de cada despliegue.
CloudFront Functions vs Lambda@Edge
CloudFront ofrece dos formas de ejecutar código en el edge:
| Característica | CloudFront Functions | Lambda@Edge |
|---|---|---|
| Runtime | JavaScript (limitado) | Node.js, Python |
| Memoria | 2 MB | 128 MB - 10 GB |
| Duración máxima | 1 ms | 5s (viewer) / 30s (origin) |
| Eventos | Viewer request/response | Viewer + origin request/response |
| Coste | 0,10 $ por millón | 0,60 $ por millón + duración |
| Acceso a red | No | Si |
CloudFront Functions para:
- Redirecciones URL (www a non-www, HTTP a HTTPS)
- Manipulación de headers (añadir security headers)
- Reescritura de URL (clean URLs, trailing slashes)
- A/B testing basado en cookies
// CloudFront Function: añadir security headers
function handler(event) {
var response = event.response;
var headers = response.headers;
headers['strict-transport-security'] = {
value: 'max-age=63072000; includeSubdomains; preload',
};
headers['x-content-type-options'] = { value: 'nosniff' };
headers['x-frame-options'] = { value: 'DENY' };
headers['x-xss-protection'] = { value: '1; mode=block' };
headers['referrer-policy'] = { value: 'strict-origin-when-cross-origin' };
return response;
}Lambda@Edge para:
- Autenticación y autorización
- Generación de contenido dinámico en el edge
- A/B testing con lógica compleja
- Personalización por geolocalización
Compresión: Brotli vs gzip
CloudFront soporta compresión automática con Brotli y gzip. Brotli ofrece un 15-25% mejor ratio de compresión que gzip para contenido web, pero solo funciona sobre HTTPS (que debería ser el 100% de tu tráfico).
| Tipo de archivo | Sin comprimir | gzip | Brotli | Ahorro Brotli vs gzip |
|---|---|---|---|---|
| HTML (100 KB) | 100 KB | 25 KB | 20 KB | 20% menor |
| JavaScript (500 KB) | 500 KB | 120 KB | 95 KB | 21% menor |
| CSS (80 KB) | 80 KB | 18 KB | 14 KB | 22% menor |
| JSON (200 KB) | 200 KB | 45 KB | 36 KB | 20% menor |
CloudFront selecciona automáticamente el mejor algoritmo basándose en el header Accept-Encoding del navegador. No necesitas configurar nada más allá de compress = true.
Seguridad con CloudFront
AWS WAF
CloudFront se integra nativamente con AWS WAF (Web Application Firewall) para proteger contra ataques comunes:
resource "aws_wafv2_web_acl" "cloudfront" {
name = "cloudfront-waf"
scope = "CLOUDFRONT"
default_action {
allow {}
}
# Protección contra SQL injection
rule {
name = "aws-sql-injection"
priority = 1
override_action { none {} }
statement {
managed_rule_group_statement {
name = "AWSManagedRulesSQLiRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
sampled_requests_enabled = true
cloudwatch_metrics_enabled = true
metric_name = "sql-injection"
}
}
# Rate limiting: 2000 peticiones por IP en 5 minutos
rule {
name = "rate-limit"
priority = 2
action { block {} }
statement {
rate_based_statement {
limit = 2000
aggregate_key_type = "IP"
}
}
visibility_config {
sampled_requests_enabled = true
cloudwatch_metrics_enabled = true
metric_name = "rate-limit"
}
}
visibility_config {
sampled_requests_enabled = true
cloudwatch_metrics_enabled = true
metric_name = "cloudfront-waf"
}
}Coste de WAF: 5 dolares/mes por Web ACL + 1 dolar/mes por regla + 0,60 dolares por millón de peticiones evaluadas. Para un sitio con 10 millones de peticiones al mes y 5 reglas, el coste es aproximadamente 16 dolares/mes.
Origin Access Control (OAC)
Si tu origen es S3, OAC garantiza que los usuarios solo pueden acceder al contenido a través de CloudFront. El bucket S3 no es accesible directamente por URL.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::mi-bucket-web/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789:distribution/E1234567890"
}
}
}
]
}HTTPS y certificados
CloudFront requiere certificados SSL/TLS de AWS Certificate Manager (ACM). Los certificados de ACM son gratuitos y se renuevan automáticamente. El único requisito es que el certificado debe estar en la región us-east-1 (requisito global de CloudFront).
Costes reales de CloudFront
Modelo de facturación
CloudFront cobra por tres conceptos:
- Transferencia de datos al usuario: Desde 0,085 $/GB (primeros 10 TB/mes) hasta 0,020 $/GB (más de 5 PB/mes).
- Peticiones HTTP/HTTPS: 0,0075 $ por 10.000 peticiones HTTPS (Norteamérica/Europa).
- Invalidaciones: Primeras 1.000 rutas/mes gratis; después, 0,005 $ por ruta.
Escenarios de coste
| Escenario | Tráfico | Peticiones | Coste mensual |
|---|---|---|---|
| Blog/landing page | 50 GB | 2M | 5-8 $ |
| Aplicación SaaS media | 500 GB | 20M | 50-70 $ |
| E-commerce con assets pesados | 5 TB | 100M | 450-550 $ |
| Plataforma de streaming | 50 TB | 500M | 3.500-4.500 $ |
Ahorro vs servir desde el origen
CloudFront no solo mejora la latencia; también puede reducir costes. La transferencia de datos desde S3 directamente cuesta 0,09 $/GB. Desde CloudFront, los primeros 10 TB cuestan 0,085 $/GB, pero 1 TB gratuito al mes está incluido en el Free Tier. Además, las peticiones de CloudFront al origen (S3) son gratuitas.
Para sitios con tráfico mayoritariamente cacheable, CloudFront puede ser más barato que servir directamente desde S3 o ALB.
Monitorización y métricas
Métricas clave en CloudWatch
- Cache hit ratio: El porcentaje de peticiones servidas desde caché. Objetivo: más del 90% para assets estáticos.
- Error rate: Porcentaje de respuestas 4xx y 5xx. Objetivo: menos del 1%.
- Latencia: Tiempo hasta el primer byte (TTFB). Objetivo: menos de 50ms para assets cacheados.
- Bytes transferred: Volumen total de datos servidos. Para estimación de costes.
# Consultar cache hit ratio de las últimas 24 horas
aws cloudwatch get-metric-statistics \
--namespace AWS/CloudFront \
--metric-name CacheHitRate \
--dimensions Name=DistributionId,Value=E1234567890 \
--start-time $(date -u -d '24 hours ago' +%Y-%m-%dT%H:%M:%S) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%S) \
--period 3600 \
--statistics AverageCloudFront Access Logs
Habilita los access logs para analizar patrones de tráfico, identificar contenido no cacheado y detectar abusos.
Los logs se almacenan en S3 y pueden analizarse con Athena:
SELECT
date,
time,
sc_status,
cs_uri_stem,
x_edge_result_type,
time_taken
FROM cloudfront_logs
WHERE x_edge_result_type = 'Miss'
AND date = '2025-09-24'
ORDER BY time_taken DESC
LIMIT 20;Errores de configuración frecuentes
Error 1: cachear contenido personalizado
Si tu página incluye el nombre del usuario en el HTML y la cacheas sin incluir la cookie de sesión en la cache key, un usuario verá el nombre de otro. Para contenido personalizado, usa Cache-Control: private, no-store o incluye un identificador en la cache key.
Error 2: TTL demasiado largo en index.html
Si configuras un TTL de 24 horas para index.html y despliegas una actualización, los usuarios verán la versión antigua durante hasta 24 horas. Configura un TTL de 60-300 segundos para archivos de entrada y usa invalidación post-despliegue.
Error 3: no habilitar compresión
CloudFront puede comprimir automáticamente el contenido, pero necesitas activar compress = true. Sin compresión, estás transfiriendo 3-5 veces más datos de los necesarios, pagando más en transferencia y ofreciendo peor experiencia.
Error 4: ignorar HTTP/3
HTTP/3 usa QUIC sobre UDP, lo que elimina el head-of-line blocking de HTTP/2 y reduce el tiempo de establecimiento de conexión. CloudFront soporta HTTP/3 sin coste adicional. Habilitarlo es una mejora gratuita de rendimiento.
Conclusión
CloudFront no es un complemento opcional. Para cualquier aplicación web que sirva a usuarios en múltiples ubicaciones geográficas, un CDN correctamente configurado es la mejora de rendimiento más impactante y más barata que puedes implementar.
La configuración óptima no es complicada, pero requiere atención a los detalles: políticas de caché restrictivas para maximizar el hit ratio, compresión habilitada, HTTP/3 activo, security headers en el edge y TTLs apropiados para cada tipo de contenido.
Si necesitas ayuda para optimizar la distribución de contenido de tu aplicación o configurar CloudFront para un caso de uso complejo, nuestro equipo de consultoría AWS tiene experiencia directa con estas configuraciones. Solicita una auditoría gratuita para evaluar el rendimiento actual de tu infraestructura web.