Tras un incidente, el registro de acceso lo tiene todo: qué se pidió, cuándo, desde dónde y qué respondió el servidor. El problema nunca es la falta de datos, sino un millón de líneas de ellos. Estas órdenes los recortan.

Quién pide más

sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Qué pidieron

sudo grep " 203.0.113.42 " /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -30

Un escaneo salta a la vista en esta lista: decenas de rutas, cada una pedida una vez, casi todas con 404. Una persona navegando no se parece en nada.

Qué TUVO ÉXITO, que es la verdadera pregunta

sudo awk '$9 ~ /^(200|301|302)$/ {print $1, $7}' /var/log/nginx/access.log \
  | grep -E 'wp-login|xmlrpc|/admin|\.php' | sort | uniq -c | sort -rn | head -20
Un muro de 404 es ruido. Un 200 en una ruta que no reconoces es la línea donde detenerse, sobre todo un POST a un archivo dentro de un directorio de subidas.

Solo las peticiones POST

sudo awk '$6 ~ /POST/ {print $1, $7, $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Cuándo ocurrió

sudo grep "203.0.113.42" /var/log/nginx/access.log | awk -F'[\\[\\]]' '{print $2}' | cut -d: -f1-2 | uniq -c

Y la forma de una subida lograda

sudo awk '$7 ~ /uploads/ && $9 == 200 {print}' /var/log/nginx/access.log | grep -i '\.php' | head
Copia los registros a otro sitio antes de empezar. La rotación está en marcha y un servidor con carga puede borrar la prueba en un día, justo antes de que descubras qué buscabas.