11 min de lecturaIntegraciones

Automatización autoalojada de n8n para enlaces: de Docker a webhooks

Ejecuta automatización de enlaces con n8n autoalojado usando webhooks de Elido, Docker Compose y modo cola, manteniendo los datos del workflow en infraestructura que controlas en la UE.

Marius Voß
DevRel · edge infra
Automatización autoalojada de n8n para enlaces: los webhooks de Elido pasan a través de un proxy inverso hacia una instancia de n8n con una cola y trabajadores, todo dentro de infraestructura que controlas

La automatización autoalojada de n8n para enlaces significa tres cosas ejecutándose en servidores que controlas: una instancia de n8n en Docker, un endpoint HTTPS público que recibe los eventos de webhook de Elido, y llamadas salientes de vuelta a la API de Elido con un token limitado. Los eventos de enlaces y dominios llegan firmados, y los eventos por clic están en la hoja de ruta. Tus workflows deciden qué pasa después, y los registros de ejecución nunca salen de tu infraestructura.

Esa es toda la arquitectura. El resto de este artículo es la parte que las guías rápidas se saltan: cómo hacer pasar los webhooks a través de un proxy inverso, cómo comprobar la firma para que un desconocido no pueda disparar tus workflows, qué cambia el modo cola, y cuándo n8n Cloud es sinceramente la mejor opción. Yo ejecuto esta configuración en una sola VM pequeña, y las piezas móviles caben en una pantalla.

Si también quieres los enlaces en sí en tu propio hardware, eso es un trabajo aparte y mucho más grande. El manual de autoalojamiento de Elido en k3s lo cubre. Aquí, Elido se queda gestionado y solo la capa de automatización se traslada a casa.

Por qué autoalojar n8n para la automatización de enlaces

La razón habitual son los datos. Un workflow de acortador de URL con n8n autoalojado ve cada payload que procesa: la URL de destino, las etiquetas, a veces un nombre de campaña que dice más de lo que te gustaría, y país, dispositivo y referrer si extraes la analítica de clics hacia él. En n8n Cloud, esas ejecuciones se almacenan en servidores de otra persona bajo los valores de retención por defecto de otra persona. Autoalojado, viven en tu Postgres, en la región que elegiste.

Según el artículo 28 del RGPD, cada responsable del tratamiento que toca datos personales necesita un contrato y un lugar en tus registros. Menos responsables del tratamiento, menos papeleo. Si tus datos de marketing ya tienen que quedarse en la UE, la guía de residencia de datos en la UE explica por qué la capa de automatización cuenta tanto como el acortador.

La segunda razón es la forma del coste. n8n Cloud cobra por ejecuciones, y un disparador de webhook activo o un sondeo de analítica frecuente consume ejecuciones rápido. Autoalojado, una ejecución es una fila en una tabla y unos milisegundos de CPU.

La tercera es el alcance. Una instancia autoalojada está en la misma red que tu base de datos de CRM o tu herramienta interna de tickets, así que un evento de enlace puede llegar a un sistema que nunca estuvo pensado para dar la cara a internet.

La pila de Docker Compose

Una pila mínima de automatización de enlaces con n8n en Docker necesita cuatro servicios. La propia guía de Docker Compose de n8n es la referencia; esta es la versión de la que yo partiría para el trabajo con enlaces, con el modo cola ya activado para que no tengas que migrar más tarde.

services:
  postgres:
    image: postgres:16
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${PG_PASSWORD}
      POSTGRES_DB: n8n
    volumes: [pgdata:/var/lib/postgresql/data]

  redis:
    image: redis:7

  n8n:
    image: docker.n8n.io/n8nio/n8n
    env_file: .env.n8n
    ports: ["127.0.0.1:5678:5678"]
    depends_on: [postgres, redis]

  n8n-worker:
    image: docker.n8n.io/n8nio/n8n
    command: worker
    env_file: .env.n8n
    depends_on: [n8n]

volumes:
  pgdata:

Y el archivo de entorno compartido:

DB_TYPE=postgresdb
DB_POSTGRESDB_HOST=postgres
DB_POSTGRESDB_USER=n8n
DB_POSTGRESDB_PASSWORD=change-me
EXECUTIONS_MODE=queue
QUEUE_BULL_REDIS_HOST=redis
N8N_ENCRYPTION_KEY=generate-a-long-random-string
N8N_WEBHOOK_URL=https://n8n.example.com/
N8N_PROXY_HOPS=1

Dos líneas importan más de lo que parece. La clave de cifrado debe ser idéntica en el proceso principal y en cada worker, o los workers no podrán descifrar la credencial de Elido y cada ejecución fallará con un error de autenticación confuso. Y el puerto 5678 está enlazado solo a localhost, porque el proxy inverso es lo único que debería dar la cara a internet.

Arquitectura autoalojada de n8n para automatización de enlaces: Elido envía webhooks firmados por HTTPS a un proxy inverso, que reenvía al proceso principal de n8n, que encola ejecuciones en Redis para workers respaldados por Postgres, mientras los workers llaman a la API de Elido de forma saliente con un token limitado

Llamar a la API de Elido desde n8n autoalojado

Las llamadas salientes no necesitan nada más allá de lo que ya incluye n8n. Crea una credencial Header Auth con el nombre Authorization y el valor Bearer seguido de una clave de API del dashboard de Elido, y luego úsala desde el nodo integrado HTTP Request. n8n la cifra en reposo con la clave del archivo de entorno, que es una razón más por la que esa clave tiene que coincidir en todas partes.

Cada ruta de enlaces está limitada a un workspace. Para acortar una URL, envía un POST a https://api.elido.app/v1/workspaces/{workspace_id}/links con un cuerpo JSON:

{
  "domain_id": 12,
  "destination_url": "{{ $json.url }}",
  "title": "Spring launch",
  "tags": ["n8n", "spring"]
}

Deja fuera slug y Elido genera uno. El domain_id es el dominio corto en el que vive el enlace; un GET a /v1/workspaces/{workspace_id}/domains lista los tuyos, y yo codificaría el ID directamente en el workflow en vez de buscarlo en cada ejecución. Un GET sobre la misma ruta de enlaces lista los enlaces, y PATCH /v1/workspaces/{workspace_id}/links/{link_id} cambia un destino o etiquetas después del hecho.

Fija una cabecera Idempotency-Key en el POST, construida a partir de algo estable en el elemento que dispara la ejecución, como un ID de fila. Si n8n reintenta el nodo tras un timeout, la API repite la primera respuesta en vez de crear un segundo enlace. La guía rápida de la API y los SDKs cubre el resto de la superficie, y la página de API y SDKs está ahí si prefieres mover un paso a código más adelante.

También existe un nodo comunitario empaquetado, n8n-nodes-elido, pensado para envolver estas llamadas en una forma más amigable. Está publicado en npm (versión 0.2.0), pero sigue siendo opcional y, como no es un nodo verificado, solo puede instalarse en n8n autoalojado, que es la configuración que da por supuesta este artículo. Mantén la versión con HTTP Request como tu base. Si instalas paquetes comunitarios en modo cola, recuerda que la GUI solo instala en el contenedor principal; los workers nunca lo ven. A partir de n8n 2.21, la ruta de instalación por variable de entorno soluciona eso reconciliando cada contenedor al arrancar, aunque la primera vez desinstala cualquier cosa que no esté en su lista.

Hacer llegar los webhooks de Elido a través de tu proxy inverso

Los eventos fluyen en la otra dirección. Elido emite link.created, link.updated y domain.verified (entre otros) a un endpoint que registras bajo Settings, Webhooks, y en n8n autoalojado ese endpoint es la URL de producción de un nodo Webhook. Un evento click.created por cada clic está en la hoja de ruta pero todavía no disponible, así que por ahora los datos de clics vienen de una extracción programada de la API de analítica. La lista completa de eventos y las formas del payload están en la referencia webhooks para eventos de enlaces.

Detrás de un proxy, n8n construye su URL de webhook a partir de su propio protocolo, host y puerto, lo que significa que anunciará alegremente http://localhost:5678/webhook/... a cualquiera que pregunte. La página de configuración de proxy inverso es corta y vale la pena leerla entera: fija N8N_WEBHOOK_URL a tu dirección pública, fija N8N_PROXY_HOPS=1, y haz que el último proxy reenvíe X-Forwarded-For, X-Forwarded-Host y X-Forwarded-Proto. Las guías más antiguas dicen WEBHOOK_URL; las versiones actuales todavía lo leen pero registran una advertencia de obsolescencia.

Nginx, Traefik, lo que ya uses está bien. Lo que importa es el TLS en el lado público y que la ruta /webhook/* llegue a n8n sin tocar.

Un detalle de tiempo me mordió. Elido espera diez segundos por una respuesta antes de contar una entrega como fallida. Un workflow que escribe en una API de hojas de cálculo lenta y luego responde puede superar eso, ser reintentado, y escribir la misma fila dos veces. Configura el nodo Webhook para que responda de inmediato y haga el trabajo después.

Si estás conectando esto para un cliente y quieres que el lado del webhook esté resuelto de antemano, la página de la función de webhooks muestra a qué te puedes suscribir antes de construir nada.

Verificar la firma antes de que se ejecute nada

Una URL de webhook pública es una URL pública. Cualquiera que la encuentre puede enviar con POST un evento falso y disparar tu workflow, así que el primer nodo después del disparador debería ser una comprobación de firma.

Cada entrega de Elido lleva X-Webhook-Signature (valor v1= más un resumen hexadecimal), X-Webhook-Timestamp en segundos Unix, X-Webhook-Event y X-Webhook-Delivery. El resumen es HMAC-SHA256 sobre la marca de tiempo, un punto y el cuerpo de la solicitud sin procesar, con clave el secreto whsec_ que se muestra una sola vez cuando creaste el endpoint.

Activa Raw Body en el nodo Webhook primero. Ese es el paso que la gente se salta. Si haces hash de JSON.stringify($json.body) en vez de los bytes exactos que envió Elido, el orden de las claves o los espacios en blanco difieren y cada firma falla, y te pasarás una noche convencido de que el secreto está mal. Luego un nodo Code:

const crypto = require("crypto");
const item = $input.first();
const h = item.json.headers;
const raw = (await this.helpers.getBinaryDataBuffer(0, "data")).toString(
  "utf8",
);

const ts = Number(h["x-webhook-timestamp"]);
if (Math.abs(Date.now() / 1000 - ts) > 300) throw new Error("stale delivery");

const expected =
  "v1=" +
  crypto
    .createHmac("sha256", $env.ELIDO_WEBHOOK_SECRET)
    .update(`${ts}.${raw}`)
    .digest("hex");
const got = h["x-webhook-signature"] || "";
if (
  got.length !== expected.length ||
  !crypto.timingSafeEqual(Buffer.from(got), Buffer.from(expected))
) {
  throw new Error("bad signature");
}
return [{ json: JSON.parse(raw) }];

El módulo crypto está disponible en el nodo Code por defecto, así que no hace falta configuración extra ahí. La ventana de cinco minutos bloquea la repetición de una solicitud capturada. Cuando rotas el secreto, Elido también envía X-Elido-Signature-Previous durante el periodo de gracia, así que puedes aceptar cualquiera de las dos claves mientras actualizas la variable. La guía de verificación de firmas de webhooks incluye una versión de este nodo que comprueba ambas cabeceras, además de la misma comprobación en Node, Python y Go.

Verificación de firma de webhook en n8n autoalojado: lee la marca de tiempo y el cuerpo sin procesar, rechaza entregas de más de 300 segundos, recalcula HMAC-SHA256 sobre timestamp punto cuerpo sin procesar con el secreto del endpoint, compara en tiempo constante, y luego ejecuta el workflow o detiene la ejecución

Modo cola y reintentos

Con la comprobación de firma en su sitio, la pregunta que queda es qué pasa bajo carga o cuando algo está caído. Hay dos sistemas de reintento en juego aquí, y cubren fallos distintos.

En modo cola de n8n el proceso principal recibe el webhook, crea una ejecución y entrega su ID a Redis; los workers lo recogen. Una ráfaga de eventos se acumula en la cola en vez de bloquear la respuesta HTTP. Para más volumen entrante puedes añadir procesadores de webhooks dedicados detrás de un balanceador de carga, aunque para la mayoría de las cargas de trabajo de enlaces un proceso principal y dos workers son de sobra.

El lado de Elido se encarga de que n8n sea inalcanzable. Cualquier respuesta que no sea 2xx o un timeout se reintenta tras 1, 5 y 15 minutos; tras tres intentos, la entrega se marca como fallida y puedes rearmarla desde el dashboard. Eso cubre el reinicio de un contenedor o un despliegue rápido. No cubre una caída de todo un fin de semana, que es por lo que yo emparejaría los webhooks con una reconciliación nocturna que liste los enlaces a través de la API, como argumenta el artículo webhooks frente a sondeo.

Usa X-Webhook-Delivery como clave de idempotencia. Los reintentos la reutilizan.

n8n autoalojado frente a n8n Cloud: compromisos honestos

Yo prefiero el autoalojamiento para esto, pero he visto a equipos arrepentirse. Aquí está la comparación sin el discurso de ventas de ninguno de los dos lados.

Aspecton8n autoalojadon8n Cloud
Dónde viven los datos de ejecuciónTus servidores, tu región, tu retenciónInfraestructura y valores por defecto de n8n
Alcanzar sistemas internosMisma red que tu CRM y tus bases de datosSolo lo que expongas públicamente
URL de webhook pública y TLSTú gestionas el proxy y los certificadosProvisto
Actualizaciones, copias de seguridad, parchesTu trabajo, cada mesGestionado
Coste a alto volumen de eventosCoste de servidor fijoEscala con las ejecuciones

La última fila corta en ambos sentidos. Una VM pequeña es barata, pero la hora de un ingeniero en una actualización rota no lo es, y n8n publica versiones a menudo. Si nadie en el equipo es responsable de la máquina, Cloud con el nodo HTTP Request y la API REST de Elido es la opción más sensata, y las recetas de Make e IFTTT o la guía de Zapier muestran cómo se ve esa ruta gestionada en otras plataformas.

Lo que no puedo decirte es si tu responsable de protección de datos aceptará una máquina autoalojada como algo más sencillo que un DPA de proveedor. En mi experiencia, normalmente sí, pero eso depende de lo bien que esté gestionada la máquina. Para cómo funciona el lado del contrato del acortador, la guía de RGPD para acortadores de URL es el punto de partida. Y si estás listo para conectar el primer workflow, consigue un token de API en un workspace y apunta un nodo Webhook a él.

Relacionado en el blog

Preguntas frecuentes

¿Puedo usar un acortador de URL con n8n autoalojado?

Sí. n8n autoalojado puede llamar a cualquier acortador con una API REST a través del nodo integrado HTTP Request. Para Elido eso significa una credencial Header Auth con tu clave de API y un POST a la ruta de enlaces limitada al workspace. Los eventos entrantes como link.created llegan a través del nodo integrado Webhook de n8n, que necesita una URL HTTPS pública. Un evento click.created por cada clic está previsto pero todavía no disponible.

¿Cómo instalo nodos comunitarios en n8n autoalojado?

En una instancia única, usa Settings, luego Community Nodes, y pega el nombre del paquete de npm. En modo cola, la instalación desde la GUI no llega a tus workers, así que instala el paquete dentro de cada contenedor o, a partir de n8n 2.21, indícalo en N8N_COMMUNITY_PACKAGES con N8N_COMMUNITY_PACKAGES_MANAGED_BY_ENV en true. Para Elido no necesitas uno: el nodo HTTP Request cubre la API.

¿Qué es WEBHOOK_URL en n8n?

Le indica a n8n qué dirección pública mostrar en el editor y registrar con servicios externos, porque detrás de un proxy inverso n8n no puede deducirlo a partir de su propio host y puerto. Las versiones actuales de n8n leen N8N_WEBHOOK_URL y registran una advertencia de obsolescencia para el WEBHOOK_URL más antiguo. Combínalo con N8N_PROXY_HOPS=1 y las cabeceras reenviadas en el proxy.

¿Cómo verifico una firma de webhook en n8n?

Activa la opción Raw Body en el nodo Webhook, y luego añade un nodo Code que recalcule HMAC-SHA256 sobre la cabecera de marca de tiempo, un punto y el cuerpo sin procesar, usando tu secreto de endpoint. Compáralo con la cabecera de firma en tiempo constante y rechaza cualquier cosa de más de cinco minutos de antigüedad. Verifica contra los bytes sin procesar, nunca contra JSON reserializado.

¿El modo cola de n8n necesita Redis?

Sí. En modo cola, la instancia principal y cualquier procesador de webhooks convierten los disparadores entrantes en IDs de ejecución y los empujan a una cola respaldada por Redis, y los workers los extraen de ahí. n8n también desaconseja el modo cola con SQLite, así que planifica con Postgres. Cada proceso debe compartir la misma clave de cifrado o los workers no podrán leer las credenciales almacenadas.

¿Es n8n autoalojado mejor que n8n Cloud para el RGPD?

Puede serlo, porque tú eliges dónde viven físicamente los datos del workflow, los registros de ejecución y las credenciales, y quién los administra. No es automáticamente conforme: te vuelves responsable de los parches, el control de acceso, las copias de seguridad y la retención. Para la automatización de enlaces que maneja datos de clics, autoalojar en una región de la UE elimina un responsable del tratamiento de tus registros, lo que simplifica el papeleo.

Prueba Elido

Pega una URL, obtén un enlace corto

Sin registro. El enlace vive 30 días. Crea una cuenta para conservarlo.

Gratis, sin registro · 2 por día

Prueba Elido

Acortador de URL alojado en la UE: dominios personalizados, análisis profundo y API abierta. Plan gratuito - sin tarjeta de crédito.

Etiquetas
self-hosted n8n automation links
n8n self hosted url shortener
n8n docker link automation
n8n webhook signature verification
n8n queue mode
n8n http request node api

Seguir leyendo