Cuando trabajas con una arquitectura donde usas CloudFront , es muy común perder visibilidad sobre las IPs reales de tus usuarios. Si revisas los logs de Nginx, verás que todas las conexiones parecen venir de nodos de CloudFront. En este post te explico cómo logré recuperar la real IP en Nginx detrás de CloudFront, usando únicamente Terraform y una pequeña pero crítica modificación en la configuración de Nginx.
64.252.86.47 - - [03/Aug/2025:07:22:37 +0000] "GET / HTTP/1.1" 200 89007 "-" "Amazon CloudFront"
¿Por qué todas las IPs son de CloudFront? ¿Dónde están los usuarios reales?
Lo que parecía un pequeño detalle se convierte en un dolor de cabeza si quieres:
- bloquear bots
- analizar tráfico real
- o simplemente saber quién accede a tu web
Esto hace que pierdas visibilidad sobre quién está realmente accediendo a tu aplicación.
Además, si gestionas tu infraestructura con Terraform, necesitas saber exactamente cómo declarar los headers para obtener la real IP en Nginx detrás de CloudFront sin romper el comportamiento por defecto de cache.
1. Entendiendo el problema
CloudFront actúa como proxy. Por defecto, la IP que verá tu Nginx es la de CloudFront, y no la del usuario final. Pero CloudFront sí reenvía la IP original en la cabecera X-Forwarded-For
.
El problema es que, si no la configuras bien en CloudFront y no la registras explícitamente en Nginx, esa cabecera nunca se registra en tus logs.
2. Añadir X-Forwarded-For
a los headers reenviados en CloudFront
Yo gestiono toda mi distribución de CloudFront con Terraform, así que el primer paso fue modificar el bloque default_cache_behavior
para incluir la cabecera X-Forwarded-For
en el campo forwarded_values.headers
.
default_cache_behavior {
# ...
forwarded_values {
query_string = true
headers = [
"Host",
"Origin",
"CloudFront-Forwarded-Proto",
"X-Forwarded-For" # ← ESTA ES LA CLAVE
]
cookies {
forward = "whitelist"
whitelisted_names = var.cloudfront_cookies_whitelisted_names
}
}
# ...
}
Además, me aseguré de que otros ordered_cache_behavior
relevantes como "wp-login.php"
también lo incluyeran.
Los comportamientos que usan headers = ["*"]
ya lo reenvían, así que ahí no es necesario tocar nada.
3. Nginx – Configurar el log para registrar X-Forwarded-For
El siguiente paso fue asegurarme de que Nginx loguea esa cabecera. Primero lo revisé en el archivo nginx.conf
, donde ya tenía definido el formato de log:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
Pero la clave estuvo en el archivo específico del sitio donde tenía definido el server
para HTTPS sin ninguna directiva access_log
.
Añadí esta línea dentro del bloque server { ... }
:
access_log /var/log/nginx/access.log main
Después de recargar Nginx:
systemctl reload nginx
los logs empezaron a mostrar esto:
64.252.86.47 - - [03/Aug/2025:07:23:32 +0000] "GET /post-slug/ HTTP/1.1" 200 83530 "-" "Amazon CloudFront" "185.214.97.98"
Ahí estaba! El último campo es la IP real del visitante.
¿Y qué pasa con los logs de CloudFront?
Es cierto: si habilitas los Access Logs de CloudFront, también puedes obtener la IP real del cliente desde ahí. Estos logs se almacenan en un bucket de S3 y contienen información como:
- IP del viewer (usuario final)
- URI solicitada
- User-Agent
- Código de respuesta, etc.
Entonces, ¿por qué no nos centramos en eso en este post?
Porque los logs de CloudFront son útiles para análisis posterior (offline), pero no te permiten acceder a la IP real en tiempo real (bueno, AWS lanzó los Real Time logs pero tiene coste añadido), desde tu aplicación. Si necesitas:
- aplicar lógica condicional basada en la IP,
- registrar la IP en tus propios logs (como los de Nginx o Apache),
- mostrar al usuario su propia IP,
- o implementar reglas de seguridad (como bloqueos por IP o geofencing),
… entonces necesitas tener esa real IP en Nginx detrás de CloudFront, una vez dentro de tu VPC, no solo en logs de S3.
¿Y qué pasa con el módulo real_ip
de Nginx?
En este post hemos usado la cabecera X-Forwarded-For
directamente ($http_x_forwarded_for
) para registrar la IP real en nuestros logs. Pero Nginx también ofrece otra opción: el módulo real_ip
.
¿Para qué sirve real_ip
?
Este módulo permite que Nginx sobrescriba $remote_addr
con la IP real del cliente (la que viene en X-Forwarded-For
). Así, todo tu stack (PHP, WordPress, plugins, etc.) verá la IP real sin necesidad de leer cabeceras manualmente.
¿Limitaciones de no usarlo?
Si solo usas $http_x_forwarded_for
, la IP real estará en los logs, pero:
$remote_addr
seguirá siendo la IP de CloudFront.- Plugins o frameworks que dependan de la IP del cliente seguirán viendo CloudFront como origen.
¿Cuándo usarlo?
Úsalo si:
- Necesitas la IP real en WordPress, PHP u otras apps.
- Vas a aplicar reglas por IP (como bloqueos o rate limiting).
- Quieres que toda la infraestructura “vea” la IP original del visitante.