Volver al Blog

Cómo leer los registros de acceso de Nginx

2025-08-2012 min read

Cuando algo falla, el registro de acceso cuenta una historia. Quién visitó el sitio. Qué pidieron. Qué URLs fallaron. Cuándo comenzó un pico. Utilicé estos pasos en un proyecto real y funcionaron. Los ejemplos a continuación son seguros para copiar y ejecutar, luego adaptarlos a tu configuración.

¿Qué son los registros de acceso de Nginx?

Los registros de acceso de Nginx son archivos de texto que registran cada solicitud HTTP que recibe tu servidor web. Cada línea representa una solicitud y contiene detalles como la dirección IP del cliente, la marca de tiempo, el método HTTP, la ruta de la URL, el código de estado, el tamaño de la respuesta y más.

Estos registros son generados automáticamente por Nginx a medida que procesa las solicitudes. Cada vez que alguien visita tu sitio, hace clic en un enlace, envía un formulario o incluso accede a una URL rota, Nginx escribe una línea en el registro de acceso. Esto sucede en tiempo real, por lo que el archivo de registro crece constantemente.

Cómo funcionan los registros de acceso

Nginx utiliza un formato de registro configurable definido en tu archivo nginx.conf. El formato predeterminado se ve así:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent"';

Esto crea entradas de registro como:

192.168.1.100 - - [20/Aug/2025:10:30:45 +0000] "GET /blog/post HTTP/1.1" 200 1234 "https://example.com/" "Mozilla/5.0..."

Muchas configuraciones modernas utilizan un formato más detallado similar a JSON con pares clave=valor, que es lo que asumen los ejemplos de esta publicación.

CDN vs. Origen: Dónde buscar los registros

Si estás utilizando una CDN (como Cloudflare, CloudFront o Fastly), hay dos conjuntos diferentes de registros a considerar:

Registros de borde de la CDN: Muestran las solicitudes de usuarios reales que acceden a la CDN. Estos contienen las IPs reales del cliente, agentes de usuario y ubicaciones geográficas.

Registros del servidor de origen (lo que cubre esta publicación): Muestran las solicitudes que llegaron a través de la CDN a tu servidor Nginx. Estos registros a menudo muestran la dirección IP de la CDN como cliente, no la IP del usuario final.

Para la resolución de problemas, generalmente querrás los registros de la CDN primero. Solo revisa los registros de origen cuando necesites ver lo que realmente llegó a tu servidor o cuando depures problemas del lado del servidor.

Todos los ejemplos asumen registros clave=valor (campos como status="404" y request="GET /path HTTP/1.1"), y archivos en /var/log/nginx/. Ajusta los nombres según sea necesario.

Lo que aprenderás

  • Cómo leer registros en vivo y comprimidos (gzipped) de una vez
  • Cómo encontrar las IPs principales y las URLs que fallan con más frecuencia
  • Cómo extraer todo de una IP
  • Cómo hacer zoom en una ventana de tiempo corta
  • Cómo vincular los registros de acceso con los bloqueos de WAF
  • Cómo mantener los resultados rápidos y útiles

Inicio rápido

Lee todo, sin importar si el archivo es .log o .gz:

zgrep -h . /var/log/nginx/ssl-*.access.log*

Ese truco de zgrep maneja tanto los archivos normales como los rotados. Agrega filtros después.

Herramientas que usarás

zgrep: Similar a grep pero funciona tanto en archivos regulares como en archivos comprimidos (.gz). Perfecto para archivos de registro que se rotan y comprimen.

awk: Una potente herramienta de procesamiento de texto que puede dividir líneas por delimitadores y extraer campos específicos. Ideal para analizar formatos de registro estructurados.

cut: Extrae columnas o campos específicos del texto. Usa -d para especificar un delimitador (como comillas o comas) y -f para elegir el número de campo que deseas.

Encuentra las IPs principales detrás de las tormentas de 404

Cuando los editores informan "muchos enlaces rotos", empieza aquí.

zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'status="' '$2 ~ /^404"/' \
| awk -F'x_forwarded_for="' '{print $2}' \
| cut -d'"' -f1 | cut -d',' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head

Por qué ayuda. Ves a los peores infractores primero. Si una IP está escaneando rutas aleatorias, la detectarás rápido.

Ver todo lo que hizo una IP individual

Útil cuando necesitas explicar un bloqueo o un pico de una sola fuente.

IP="112.134.209.112"
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| grep -F 'x_forwarded_for="'$IP

Consejo. En algunas configuraciones, la IP del cliente puede estar en src o src_ip. Si es así, cambia el nombre del campo en el grep.

URLs principales accedidas por esa IP (ignora cadenas de consulta)

IP="112.134.209.112"
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| grep -F 'x_forwarded_for="'$IP \
| awk -F'request="' '{print $2}' | cut -d'"' -f1 \
| awk '{print $2}' | cut -d'?' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head

Por qué ayuda. Al eliminar la cadena de consulta, se agrupan "la misma página con diferentes parámetros", lo que hace que los patrones sean obvios.

URLs principales fallidas por estado

404s:

zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'status="' '$2 ~ /^404"/' \
| awk -F'request="' '{print $2}' | cut -d'"' -f1 \
| awk '{print $2}' | cut -d'?' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head

5xx:

zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'status="' '{split($2,a,"\""); if (a[1] ~ /^5[0-9][0-9]$/) print}' \
| awk -F'request="' '{print $2}' | cut -d'"' -f1 \
| awk '{print $2}' | cut -d'?' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head

Por qué ayuda. Esto te da una lista clasificada de rutas problemáticas. Corrige las cinco principales y a menudo corregirás la mayor parte del dolor.

Haz zoom en una ventana de tiempo corta

Cuando un pico golpea en un momento conocido, quieres el antes y el después.

Simple y rápido (suficiente para una ventana de 10 minutos dentro de la misma hora):

# Ejemplo: 09/Aug/2025 23:15–23:25
zgrep -h 'time_local="' /var/log/nginx/ssl-*.access.log* \
| egrep '09/Aug/2025:23:1[5-9]|09/Aug/2025:23:2[0-5]'

Envía el resultado a cualquiera de los recuentos anteriores.

Por qué ayuda. Comparas el tráfico justo antes y justo después de un evento, que a menudo es todo lo que necesitas para ver qué cambió.

Publicaciones de formularios y cuerpos grandes

Las publicaciones POST grandes a un formulario pueden activar las reglas de WAF. Mídelas.

PATH_RE="/about/.*speaker-request-form"
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'request="' -v r="$PATH_RE" '
  { split($2,a,"\""); split(a[1],b," "); m=b[1]; u=b[2];
    if (m=="POST" && u ~ r) print }' \
| awk -F'request_length="' '{print $2}' | cut -d'"' -f1 \
| awk '{sum+=$1; c++} END{print "POST count="c, "avg_request_length=" (c?sum/c:0)}'

Por qué ayuda. Si el tamaño promedio de la solicitud es alto, tu WAF puede bloquear la inspección. Ahora tienes pruebas y números.

Vincula los registros de acceso con los bloqueos de WAF

  1. Obtén la hora exacta y la regla del evento de tu WAF.
  2. Filtra los registros de acceso para esa ventana usando el truco de la "ventana de tiempo".
  3. Busca la misma ruta, la misma IP o un request_length grande.
  4. Si la regla de WAF habla sobre el tamaño del cuerpo o los límites de inspección, confirma con el análisis de POST anterior.

Esto cierra el círculo. Puedes decir qué sucedió y por qué sucedió.

Consejos de velocidad que importan

  • Filtra temprano. Agrega grep 'status="404"' antes de ordenar.
  • Usa LC_ALL=C sort para ordenar de forma más rápida y estable.
  • Omite las cadenas de consulta para agrupar páginas por ruta.
  • Muestra primero. Ejecuta head en una canalización para verificar que estás cortando el campo correcto.
  • Documenta tu log_format en el repositorio. Tu yo futuro te lo agradecerá.

Errores comunes

  • Contar por remote_addr cuando tu aplicación se sienta detrás de un proxy. Usa x_forwarded_for o tu campo de IP de cliente real.
  • Asumir que todos los archivos de registro usan el mismo formato. Verifica tu log_format de nginx.conf antes de analizar.
  • Olvidar que los archivos de registro rotados (.gz) necesitan zgrep, no grep.
  • Usar patrones de expresiones regulares complejos que fallan cuando los formatos de registro cambian. Mantenlo simple.

Conclusiones

Los registros responden preguntas reales rápidamente. Comienza con una pregunta clara, envía solo lo que necesitas y cuenta. Vincula lo que ves en Nginx con lo que tu WAF informa. Pasarás de "algo se sintió lento" a "esta URL falló 2,379 veces desde una IP en diez minutos, y aquí está la solución".