TPTito Pinardo Gutiérrez
← Volver al rack
English
1U · N8Nn8n · navegador sin cabeza · cada 30 min En producción

Posición 9 de 25 en el rack · En producción

Unidad 1U · Automatización

n8n · lo que se hace solo

Registro solo tras confirmar

Tareas que antes hacía a mano y ahora son flujos: cada 30 minutos uno revisa una web con un navegador sin cabeza, compara con lo que ya ha procesado, obtiene lo nuevo y lo entrega a otro servicio. Lo difícil no es hacerlo, es no perder nada cuando algo falla a mitad.

Por qué n8n
Los flujos se ven como un grafo, cada ejecución queda registrada con sus datos y se puede relanzar. Para tareas programadas entre servicios, es más fácil de depurar que un script suelto.
La regla
Algo solo se marca como hecho cuando el servicio de destino confirma que lo recibió. Si no, se queda pendiente y la siguiente ejecución lo vuelve a intentar.
Cómo se despliega
Terraform crea el contenedor y un rol de Ansible levanta n8n, el navegador sin cabeza y el flujo. Las carpetas compartidas nacen con el dueño correcto.
  • 2.104procesos de navegador huérfanos encontrados
  • 28 GBde RAM liberados al cerrarlos
  • 51ejecuciones fallidas por un permiso
  • 30 minentre ejecuciones

Su código, en abierto Versión pública del repositorio: sin IPs ni secretos.

Un flujo por dentro

Cada media hora, un flujo busca novedades y las entrega a otro servicio. Elige un recorrido para ver dónde se puede perder algo y cómo se evita.

Hermesde visita en la unidad

Pulsa una pieza o elige un recorrido. Si vienes de una habilidad, ya están encendidas las piezas donde la uso.

      Una ejecución normal
      1. Ejecución programada — Pasan 30 minutos y salta el disparador.
      2. La web de origen — Se consulta la fuente.
      3. Lista de candidatos — Llega la lista de novedades.
      4. Filtro contra el registro — El filtro la compara con el registro.
      5. Registro de procesados — Lo ya procesado se descarta.
      6. Filtro contra el registro — Quedan dos elementos nuevos.
      7. Navegador sin cabeza — El navegador sin cabeza obtiene el fichero de cada uno.
      8. El fichero obtenido — La API responde con el nombre de cada fichero.
      9. Leer por su nombre exacto — Cada elemento lee el suyo por su nombre exacto. Antes, con dos a la vez, podían cruzarse.
      10. Entrega — Se entregan al servicio de destino, cada uno con sus propios datos.
      11. El servicio de destino — El destino responde por cada uno.
      12. Confirmación — Se cruzan las respuestas con sus elementos: los dos, aceptados.
      13. Registro de procesados — Solo ahora se escriben en el registro.
      14. Limpieza — Y se limpian los temporales.
      Algo falla a mitad
      1. Entrega — Se entrega un elemento.
      2. El servicio de destino — El destino no lo acepta.
      3. Confirmación — La confirmación no llega.
      4. Pendiente — El elemento se queda pendiente, fuera del registro.
      5. Historial de ejecuciones — El fallo queda en el historial para revisarlo.
      6. Ejecución programada — En la siguiente ejecución vuelve a entrar como nuevo.
      Un navegador que no se cierra
      1. Navegador sin cabeza — Una página tarda demasiado y la API da error.
      2. Memoria del contenedor — Antes, el error soltaba la referencia al navegador pero no lo cerraba: el proceso seguía vivo.
      3. Monitorización — La memoria del contenedor sube día tras día.
      4. Yo — Hasta que me doy cuenta: 31 GB usados de 32.
      5. Navegador sin cabeza — Ahora cada error cierra el navegador antes de olvidarlo.
      6. Memoria del contenedor — Los procesos huérfanos se quedan en cero.
      Se despliega
      1. Rol de Ansible — Ansible aplica el rol.
      2. El dueño de las carpetas — Las carpetas compartidas, con el dueño del usuario de n8n.
      3. Proxy del socket de Docker — El acceso a Docker, a través del proxy.
      4. Ejecución programada — n8n arranca con su flujo importado.
      5. Puerta interna — El panel, detrás de la puerta interna.
      6. Yo — Lo reviso desde casa o la VPN.
      1. La web de origen

        De donde salen las novedades.

      2. El servicio de destino

        Quien recibe cada elemento y confirma si lo aceptó.

      3. Yo

        Reviso las ejecuciones fallidas cuando algo no cuadra.

      4. Monitorización

        Vigila la memoria del contenedor.

        • Zabbix
      5. Puerta interna

        El panel de n8n solo se abre desde casa o la VPN, con doble factor. Se retiró de internet.

      6. Ejecución programada

        El disparador del flujo.

        • Docker
      7. Lista de candidatos

        Lo que hay ahora en la fuente.

        • Docker
      8. Filtro contra el registro

        Se queda solo con lo que no se ha procesado ya.

        • JavaScript / TypeScript
      9. Entrega

        Manda cada elemento al servicio de destino, con los datos de ese elemento y no los del primero de la tanda.

        • Docker
      10. Navegador sin cabeza

        Una pequeña API con Puppeteer que abre la web como lo haría una persona y descarga el fichero.

        • Docker
        • JavaScript / TypeScript
      11. El fichero obtenido

        La API responde con su nombre; el contenido se queda en disco.

        • Docker
      12. Leer por su nombre exacto

        Cada elemento lee su fichero por el nombre que devolvió la API, no «el primero que haya en la carpeta».

        • JavaScript / TypeScript
      13. Limpieza

        Borra los ficheros temporales al terminar.

        • Linux (Debian, Alpine, Arch)
      14. Confirmación

        Se cruza cada respuesta del destino con su elemento. Solo lo que se aceptó pasa al registro.

        • JavaScript / TypeScript
      15. Registro de procesados

        Evita repetir trabajo. Si algo entra aquí sin estar hecho, se pierde para siempre: nadie lo vuelve a intentar.

      16. Pendiente

        Lo que falló se queda fuera del registro y vuelve a entrar en la siguiente ejecución.

      17. Historial de ejecuciones

        Cada ejecución, con los datos de cada nodo. De ahí salen los diagnósticos.

      18. Rol de Ansible

        Levanta el stack, importa el flujo y crea las carpetas compartidas.

        • Ansible
      19. El dueño de las carpetas

        n8n corre sin root, con su usuario. Toda carpeta en la que tenga que escribir o borrar se crea con ese dueño.

        • Linux (Debian, Alpine, Arch)
        • Docker
      20. Memoria del contenedor

        Donde se notó que algo no cerraba lo que abría.

        • Linux (Debian, Alpine, Arch)
      21. Proxy del socket de Docker

        n8n no toca el socket de Docker directamente: pasa por un proxy que solo permite lo necesario.

        • Docker
        • Linux / SSH hardening

      Lo que uso de mi árbol

      Pulsa una habilidad: se encienden en el mapa las piezas donde la uso y te cuento para qué.

      Terraform
      Crea el contenedor de las automatizaciones.
      Ansible
      El rol que levanta n8n, el navegador sin cabeza y el flujo, con las carpetas y sus dueños.
      LXC
      Corre en su propio contenedor LXC.
      Docker
      n8n, la API del navegador y el proxy del socket, en un mismo stack.
      Linux (Debian, Alpine, Arch)
      Usuarios y dueños de las carpetas compartidas, y procesos que se cierran de verdad.
      Zabbix
      Vigila la memoria del contenedor.
      Linux / SSH hardening
      Panel solo detrás de la puerta interna, n8n sin root y Docker a través de un proxy.
      JavaScript / TypeScript
      La API del navegador sin cabeza y los nodos de código del flujo, en JavaScript.

      Bitácora de incidencias

      Averías reales. Lee el síntoma, elige la causa que creas y mira cómo se arregló.

      1. #1

        Elementos que desaparecían sin dejar rastro

        Junio de 2026 · flujo

        Una ejecución encontró tres novedades. Solo una llegó al destino. Las otras dos no volvieron a intentarse nunca.

        ¿Qué crees que pasaba?

        Ver la solución
        Causa
        Dos fallos juntos. El registro se construía con todo lo que el filtro había visto como nuevo, no con lo que el destino había confirmado. Y con varios elementos en la misma tanda, la lectura de ficheros cogía «el que hubiera», no el de cada uno.
        Solución
        Solo se registra lo que el destino confirma, cruzando cada respuesta con su elemento. Cada elemento lee su fichero por el nombre que devolvió la API y se envía con sus propios datos.
        Lección
        Un registro de «hechos» se escribe después de hacer, nunca antes. Si no, un fallo deja de ser temporal y se vuelve permanente y silencioso.
      2. #2

        31 GB de 32 en uso

        05-09-2026 · memoria

        El contenedor estaba al borde de quedarse sin memoria. n8n en sí usaba 264 MB.

        ¿Qué crees que pasaba?

        Ver la solución
        Causa
        Ante cualquier error, la API soltaba su referencia al navegador sin cerrarlo. El proceso seguía vivo para siempre: 2.104 navegadores acumulados en 22 días.
        Solución
        Cerrar el navegador en cada error antes de olvidarlo. Matar los huérfanos liberó unos 28 GB al instante y, desde el arreglo, el recuento se queda en cero aunque la web falle.
        Lección
        Soltar una referencia no libera lo que hay detrás. Lo que se abre, se cierra también en el camino del error.
      3. #3

        La misma tarea, 51 veces

        18-09-2026 · permisos

        Durante 28 horas, el flujo falló cada media hora y repetía el mismo trabajo una y otra vez.

        ¿Qué crees que pasaba?

        Ver la solución
        Causa
        Tras pasar el servicio a código, el rol creaba esa carpeta sin dueño explícito. La limpieza fallaba con «Permission denied», cortaba el flujo antes de escribir el registro y la siguiente ejecución volvía a ver lo mismo como nuevo.
        Solución
        Crear esa carpeta en la misma tarea que el resto, con el dueño del usuario de n8n, y relanzar el rol: solo cambió esa tarea.
        Lección
        Al pasar algo a código, lo que antes estaba bien «porque sí» hay que escribirlo: aquí, el dueño de una carpeta.

      Contado entero en un artículo:

      Cómo se construyó

      1. Junio de 2026

        El flujo

        • Primer flujo programado con navegador sin cabeza.
        • Arreglo del registro: solo tras confirmar.
      2. 16-09-2026

        A código

        • Contenedor nuevo con Terraform y rol de Ansible para todo el stack.
        • El antiguo, parado como margen.
        • Panel fuera de internet el 26-09.

      Decisiones (y por qué)

      • Cuándo se apunta algo como hecho

        Cuando el destino lo confirma

        Apuntarlo antes es más sencillo y funciona el 99 % de las veces. El 1 % restante se pierde sin que nadie lo vea.

      • Acceso a Docker

        A través de un proxy limitado

        Dar a una herramienta de automatización el socket de Docker entero es darle el servidor. El proxy solo deja las operaciones que necesita.

      Lo que aprendí

      • Registrar después de confirmar, no antes.
      • Lo que se abre se cierra también cuando hay error.
      • Al pasar algo a código, escribir hasta lo que parecía obvio.

      Lo siguiente

      • Un aviso cuando un flujo falla varias veces seguidas, en vez de descubrirlo por el historial.

      ¿Hablamos?

      Puedo contar cualquiera de estas decisiones en detalle en una entrevista.

      Descargar CV Contactar ← Volver al rack

      Contado en genérico a propósito: sin las fuentes, los servicios de destino ni el contenido que se mueve.