4 puntos por GN⁺ 2025-06-02 | 1 comentarios | Compartir por WhatsApp
  • Gitea y el blog de un servidor personal quedaron abrumados por tráfico de scraping, con alertas continuas de disco, CPU y memoria, y el operador salió a defenderlos combinando análisis de logs, Nginx y Fail2Ban
  • Según Zabbix, el tráfico subió muy por encima de lo normal; el promedio mensual de Nginx fue de 8 solicitudes por segundo, y en el peor tramo llegó a más de 20 solicitudes por segundo
  • La causa no fue un pico único de tráfico desde Reddit o Hacker News, sino algo más cercano a scraping distribuido, con varios bloques de IP rastreando URLs de www.lambdacreate.com y krei.lambdacreate.com
  • Nginx devolvió 403 a user agents maliciosos conocidos y aplicó límites de solicitudes por IP; los clientes que generaban demasiados 403 fueron bloqueados con Fail2Ban durante 24 horas
  • Al momento de escribir, la lista de bloqueos había crecido hasta un total de 735 bans, y en particular las solicitudes que intentaban generar tarballs para todos los commits de los repositorios públicos de Gitea aumentaban la carga del servidor

Tráfico de scraping que presionó a un servidor personal

  • Tráfico de bots no deseado llegó de golpe a un espacio personal en internet, afectando incluso servicios a los que deberían acceder lectores reales
  • Servicios como Archive.org, que indexan sitios con fines de preservación, entran en la lista de permitidos, pero Amazon, Facebook, OpenAI y varios bots aleatorios se distinguen como actores que consumen contenido para sus propios fines
  • Se considera que la recolección masiva de datos de internet por parte de grandes empresas y la demanda de datos para entrenar modelos de IA incrementaron aún más la presión del scraping
  • Este tráfico se trata no como consumidores reales de Lambdacreate, sino como un obstáculo que reduce la accesibilidad para lectores humanos

Zabbix detectó primero las señales anómalas

  • El primero en alertar del problema fue Zabbix, con una advertencia de que el disco para contenedores se había llenado
  • En un entorno basado en LXD, se amplió un sparse file de ZFS y el sitio se bajó por un momento y luego se volvió a levantar, pero la causa raíz seguía ahí
  • Después, la instancia de Gitea empezó a consumir todo el disco a diario, generando 20 a 30 GB de datos por día
  • Al principio se interpretó como un problema de que Gitea no habilita por defecto la limpieza de archivos de repositorios, y se configuró una tarea de limpieza agresiva
  • Pronto siguieron alertas de CPU y memoria, se volvió difícil hacer git pull y git push en Gitea, y el cliente weechat tampoco podía mantener la conexión

Un volumen de solicitudes unas 10 veces mayor que lo normal

  • Gracias a contar con monitoreo out-of-band para comparar métricas históricas con el estado actual, se pudo confirmar el patrón anómalo
  • En el panel de Zabbix, las métricas clave eran el número de solicitudes de Nginx y el gráfico de throughput de red
  • El promedio mensual de solicitudes a Nginx era de unas 8 solicitudes por segundo
  • En el peor momento llegaron más de 20 solicitudes por segundo; aunque para un servicio grande sería poco, para un servidor personal era alrededor de 10 veces lo habitual, por lo que el impacto fue fuerte
  • Más que el simple volumen de solicitudes, el aumento simultáneo del uso de disco y CPU relacionado con Gitea incrementó la carga operativa del servidor

Rastrear logs con lnav y goaccess

  • Para mantener el servidor vivo el tiempo suficiente como para revisar los logs, se apagaron brevemente los contenedores y Nginx y se inició el análisis
  • Las herramientas usadas fueron lnav y goaccess
  • lnav muestra archivos de log en una TUI coloreada y ofrece una capa de abstracción sobre formatos de log comunes, permitiendo consultar logs con queries SQL
  • En access.log, la revisión se centró en estas preguntas
    • Cuántas IP de visitantes había en total
    • Si había patrones en las direcciones IP
    • Si el tráfico venía de algún referrer específico
    • Qué user agents se estaban usando
    • Qué IP se asociaba con qué user agent
  • El análisis mostró que no era un “hug of death” proveniente de un único referrer, sino que varios bloques de IP estaban raspando URLs de todo el sitio

403 basados en user agent y límites de solicitudes

  • La primera respuesta fue listar en Nginx los user agents problemáticos y devolverles 403
  • La configuración de ejemplo usa map $http_user_agent $badagent para marcar agents como AdsBot-Google, Amazonbot y Amazonbot/0.1
  • En la configuración base de Nginx se incluyen las reglas de user agent y también se establece rate limiting por IP
  • La configuración del virtual host incluye estos comportamientos
    • Aplicar límites de solicitudes con limit_req zone=krei burst=20 nodelay;
    • Si $badagent es verdadero, bloquear el acceso al contenido con return 403;
  • Este enfoque ayuda a reducir el procesamiento del backend, pero como el servidor todavía tiene que recibir la solicitud HTTP y procesar el 403, sigue quedando carga cuando hay muchas solicitudes simultáneas

Automatizar bloqueos de firewall con Fail2Ban

  • Una vez acumulados los logs 403, se pueden revisar con lnav las IP únicas que recibieron 403
  • goaccess se usa para analizar logs antiguos y actuales en conjunto y comprobar cuántas solicitudes entraron al servidor y cuáles fueron los endpoints más atacados
  • Para proteger realmente el servidor, se agregó Fail2Ban
  • La regla de Fail2Ban es una forma simple de detectar, en el access log de Nginx, IP que generan demasiadas respuestas 403
  • El tiempo de bloqueo se configuró en 86400 segundos, es decir, 24 horas
  • Al momento de escribir, el resultado de fail2ban-client status nginx-forbidden era el siguiente
    • Fallos actuales: 13
    • Fallos totales: 57135
    • Bloqueos actuales: 38
    • Bloqueos totales: 735

El objetivo real no era el blog, sino la generación de tarballs en Gitea

  • Finalmente, los lectores pudieron volver a acceder al blog y a otros servicios de Lambdacreate
  • Cuando hay que bloquear tráfico de robots, se vuelve difícil incluso escribir una entrada de blog
  • El tráfico problemático no estaba raspando el blog, sino apuntando a la generación de tarballs de todos los commits de cada repositorio público de la instancia de Gitea
  • A largo plazo, se planea considerar ampliar la lista de bloqueos o crear excepciones para servicios legítimos como Archive.org
  • La postura es que no se quiere que el contenido desaparezca de los motores de búsqueda, pero tampoco dejarlo como combustible para el deterioro de internet causado por la IA

1 comentarios

 
GN⁺ 2025-06-02
Opiniones en Hacker News
  • Parece que muchos crawlers menos escrupulosos imitan a los crawlers grandes. Da la impresión de que mucha gente asume que el User-Agent es auténtico.
    Mi método favorito es poner información señuelo en robots.txt, hacer que esa URL entregue una bomba gzip y luego bloquear automáticamente las solicitudes posteriores.
    Fue fácil de configurar en Caddy y atrapa bien a los peores crawlers.
    No estoy defendiendo el comportamiento de los bots, pero si algunos bots pueden tumbar un sitio solo con solicitudes a ciegas, un atacante malicioso podría divertirse mucho más destruyéndolo.

    • Creo que lo último es bastante cierto.
      Quizá sea porque soy de otra generación que quienes escriben este tipo de posts de blog, pero no entiendo muy bien esta obsesión con un uso tan bajo de recursos.
      Me recuerda a cuando los abuelos hacen un escándalo porque no apagaste una luz LED, o a manejar 15 millas para ahorrar 5 centavos por galón.
      20 solicitudes por segundo no son absolutamente nada.
      Incluso si todo se genera dinámicamente, para empezar no sé por qué lo harían así, y habría sido mucho mejor dedicar tiempo a arreglar el caché.
      Entiendo que, con el ambiente actual, los posts del tipo “fuera bots” son populares, pero esto tampoco es muy novedoso.
      Hay muchas formas productivas de manejarlo desperdiciando mucho menos tiempo.
    • Me gustaría saber si podrías explicar un poco más este enfoque con robots.txt. Tengo entendido que la mayoría de las IA ignoran por completo lo relacionado con robots.txt, así que en la práctica me parece que solo caen los bots que sí intentan respetarlo.
      No me opongo como otros aquí; me interesa saber cómo implementarlo sin perjudicar a los actores legítimos.
    • Opero una de las wikis más grandes de mi sector, y fue imposible convencer a las demás personas del equipo de desarrollo de usar una bomba gzip como medida defensiva.
      Están convencidos de que podría implicar una responsabilidad legal peligrosa y que no vale la pena intentarlo. Realmente me pregunto si alguien usa esto en sitios web públicos reales.
  • Es molesto que los bots ya no respeten en absoluto los archivos robots.txt. La gente que crea estas cosas son villanos totales. Si eres uno de ellos, ojalá te vayas al diablo por tu cuenta.

    • Si dices eso, también tendrías que decirles lo mismo a quienes usan chatbots, buscadores y herramientas de comparación de precios. Son ellos quienes dan incentivos económicos a los scrapers.
    • Es útil poner honeypots para los bots que sí se toman la molestia de revisar robots.txt en vez de simplemente ignorarlo.
  • El problema de espacio en disco me parece un bug de Gitea. Cuando alguien descarga un zip, debería poder streamearlo al cliente, pero en realidad crea el zip en un espacio temporal, se lo entrega al cliente y luego no lo borra.
    Lo resolví marcando ese directorio como de solo lectura. Obviamente, las descargas zip ya no funcionan. Si alguien realmente las necesita, puede hacer checkout del repositorio y crearlo por su cuenta.
    Si de verdad me hubiera importado, habría corregido el bug, buscado cómo desactivar bien la función o la habría habilitado solo para usuarios con sesión iniciada.
    Además, redirijo ciertos User-Agent del lado del servidor a https://git.immibis.com/gptblock.html.
    Ahora ya no es por el desperdicio de recursos, sino simplemente porque no me caen bien. Lo que hacen de todos modos no tiene valor, y lo hago porque puedo.
    Si de verdad necesitan los datos de un repositorio Git, que clonen el repositorio Git en vez de scrapearlo de forma tonta. Eso siempre estuvo permitido.
    8 solicitudes por segundo no es tanto, siempre que cada solicitud no provoque procesamiento pesado, y de hecho, salvo por el bug de espacio en disco, no cargaba demasiado a un VPS pequeño.
    No lo bloqueé por ser un DoS, sino por ser estúpido.

  • Entiendo que el autor “ya no le dé importancia”, pero vi Google, ripe.net y semrush entre las IP bloqueadas.
    Si quiere que otras personas lo vean y hablen de ello, definitivamente no bloquearía a Google, y probablemente tampoco a los demás.
    Aunque el contenido sea scrapeado por el bot de IA de alguien, no entiendo por qué operarías un sitio público sin esperar que el sitio se use.
    Apagar el letrero luminoso de un motel mientras esperas que la gente llegue no es una buena forma de invitar.

    • Semrush se comportó tan mal durante mucho tiempo, con varios niveles de incompetencia, que al menos desde hace 8 años dejé una nota específica en el archivo robots.txt, y al final logré que alguien del área legal le pusiera atención.
      Permitir que una empresa de “SEO” pisotee torpemente el sitio y desplace a visitantes reales no aporta ningún valor para mí ni para usuarios potenciales.
      Algunos competidores de Semrush eran igual de malos.
      El caos actual de la IA también es muy deficiente. Al menos en un caso conocido, no solo hicieron falta medidas técnicas, sino también notas legales a relaciones con inversionistas y al departamento de relaciones públicas para que se restableciera cierto orden.
    • Porque las solicitudes de bots consumen bastante ancho de banda, memoria, CPU y espacio en disco. Como dice la introducción, es simplemente tráfico descortés, y no hay razón para servir tráfico a esos recolectores.
      Google también opera scrapers de IA, así que eso pudo haber sido lo que viste.
    • ¿Acaso en los últimos 10 años no empezamos ya a enseñarles a las personas que no deben usar Google?
      Especialmente cuando pasan cosas como esta.
      Google is using AI to censor independent websites like mine
      https://news.ycombinator.com/item?id=44124820
      Suena como si ya hubiéramos llegado al punto en que Google se volvió una carga mayor.
    • También hay actores maliciosos que fingen ser scrapers de Google. Google alguna vez tuvo fama de scrapear con educación, pero si ya estás obteniendo el tráfico que necesitas con o sin Googlebot, no hay razón para preocuparte.
  • Por culpa de estos bots, los logs crecían demasiado rápido, así que desactivé el logging del servidor. Son realmente persistentes, llenan todos los formularios e incluso llaman APIs a las que solo se puede acceder mediante clics en el sitio.
    Anthropic, OpenAI y Facebook siguen scrapeando hasta ahora.

    • Si es una “API a la que solo se puede acceder mediante clics en el sitio”, me pregunto de qué otra forma se supone que se accedería.
    • Me gustaría saber si puedes compartir información sobre crawlers que acceden a APIs que solo se pueden usar mediante clics en el sitio web.
      Para confirmar: ¿quieres decir que son parte de la UI y que solo una persona debería presionarlas, y que no hay otra forma de acceder a esa API?
      Ahora que existen agentes de IA, si imitan patrones de comportamiento humano, prácticamente casi no hay forma de distinguir entre usuarios reales y bots.
  • Es bueno que los bots rastreadores de IA completen honestamente el encabezado User-Agent. Pero sorprende que fueran la causa de tanto tráfico
    El 99% de todos los sitios web no cambia con la frecuencia suficiente como para necesitar ese nivel de tráfico, y mucho menos un blog de desarrollo

    • También respetan robots.txt
      Aunque también vi reportes de que, después de ser bloqueados de alguna manera, empezaron a rastrear desde IP residenciales con un User-Agent de navegador
      Pero también es posible que desde el principio alguien haya falsificado su rastreador haciéndolo pasar por OpenAI/Amazon/Facebook, etc.
  • Soy quien creó tirreno [1]
    Nuestra plataforma está diseñada principalmente para usuarios con sesión iniciada en tiempo real, pero también funciona bien para detectar y bloquear bots
    Anonimiza el último octeto de la dirección IP reemplazándolo por un asterisco y agrupa subredes prácticamente iguales bajo una misma cuenta
    Luego, con el motor de reglas integrado, se pueden crear listas de bloqueo automáticamente según condiciones como demasiados errores 500/404, intentos de inicio de sesión por fuerza bruta o tráfico desde IP de centros de datos
    Por último, se puede integrar la API de lista de bloqueo de tirreno en la lógica de la aplicación para redirigir el tráfico no deseado a una página de error
    Como extra, también se ofrece un dashboard [2] para monitorear la actividad y ajustar finamente las listas para no bloquear usuarios legítimos
    [1] https://github.com/tirrenotechnologies/tirreno
    [2] https://play.tirreno.com/login (admin/tirreno)

    • Desde el punto de vista del usuario, hay que asumir falsos positivos de un muro de bloqueo basado en “IP de centros de datos”. Es decir, puede afectar a la mayoría de los entornos que no navegan ingenuamente desde una dirección con fuga de información de la línea del último tramo
      Aunque encuentren algo que no haya sido bloqueado de antemano o logren pasar haciendo clic en 87 casillas de semáforos, quedan agrupados con vecinos de dirección totalmente ajenos
      Parece una forma de tranquilizar la conciencia diciendo que no se está creando un sistema de vigilancia de usuarios procesando datos personales sin consentimiento
      Espero que al menos cuenten con un proceso de feedback suficiente para que sus clientes puedan ver que están perdiendo clientes reales que sí gastan dinero
    • Me pregunto cómo manejan la situación en la que los ISP se están moviendo a CGNAT. Una sola IP puede representar, en la práctica, a cientos de usuarios
    • También estamos trabajando en una función para bloquear bots según rangos de IP publicados mediante el mismo dashboard. Se aceptan sugerencias
  • Mis sitios reciben entre 10 mil y 20 mil solicitudes al día. La mayoría son scrapers de IA
    Algo que noté es que muchos bots buscan páginas PHP específicas. Si no usas PHP, puedes bloquear automáticamente las IP que soliciten páginas PHP. Si usas PHP, basta con bloquear las IP que pidan páginas que en realidad no existen
    Algunos de nosotros estamos dispuestos a permitir el entrenamiento de IA, pero queremos evitar la sobrecarga. Por ejemplo, me alegra que se rastreen páginas sobre el evangelio y teología bíblica
    Para contenido grande que no quieres que sea rastreado, puede ayudar ponerlo en un directorio específico. Luego, si detectas un bot, bloqueas el acceso de esa IP a ese directorio
    En mi caso, también tengo una estrategia básica para manejar muchas solicitudes: solo texto, presentación HTML/CSS, otros elementos alojados externamente y Perma-Cache de BunnyCDN (USD 10/mes + 1 centavo por GB)
    Las solicitudes de BunnyCDN van a una VM de Digital Ocean de USD 5 al mes. Al principio ni siquiera noté los scrapers de IA, porque no afectaban el rendimiento y, durante un mes, mi saldo apenas cambió de USD 30 a USD 29.99

  • Me preguntaba si existiría algo como “page knocking”: abrir varias páginas en un orden específico para obtener acceso
    Por ejemplo, se podría hacer que todo devuelva 404 si no empiezas por una URL privada específica

    • He visto el enfoque inverso. Consiste en poner en el footer del sitio un enlace en el que es poco probable que un usuario haga clic o que se precargue, y en cuanto un robot le hace GET, convertir el resto del sitio en disparates sintácticamente válidos
    • No veo cómo podrían acceder los usuarios autorizados con ese método. Hay que considerar que se quiere que un usuario común encuentre el proyecto desde una página de resultados de búsqueda y pueda explorarlo de inmediato, sin crear una cuenta ni autenticarse
    • Como sea que lo diseñes, será poco amigable para el usuario. Si guardo un marcador o le envío un enlace a un amigo, esa persona verá un 404
  • Como mi servidor pequeño simplemente estaba funcionando en silencio, hace poco no había revisado el estado de fail2ban
    sudo fail2ban-client status | sed -n '/Jail list:/{s/^.*://; s/,//g; p}' | xargs -n1 sudo fail2ban-client status | awk '/jail:/{i=$5}; /Total failed:/{jail[i]=$5}; END{for(i in jail) printf("%s: %s\n", i, jail[i])}' | column -t
    sshd-ddos: 0
    postfix: 583
    dovecot: 9690
    postfix-sasl: 4227
    nginx-botsearch: 1421
    nginx-http-auth: 0
    postfix-botnet: 5425
    sshd: 202157
    Vaya, 220 mil IP bloqueadas

    • Hay un bot identificado como DotBot/1.2 que, al día de hoy, envió más de 220 mil solicitudes en las últimas dos semanas
      Solicita nombres de archivo y carpetas al azar en el servidor web
      Tengo curiosidad por saber hasta qué profundidad llega y si tiene algún límite, así que por ahora lo estoy observando sin bloquearlo