1 de sept de 20262.069 palabras10 min de lectura
Cómo instalar n8n self-hosted en Coolify (con PostgreSQL y webhooks funcionando)
Instalá n8n en Coolify con PostgreSQL, hacé funcionar los webhooks detrás de Traefik o de un Cloudflare Tunnel y mantenelo sano. Sin límite de ejecuciones.

Introducción
n8n es una herramienta de automatización de workflows: conectás disparadores (un webhook, un cron, una fila nueva en una base de datos) con acciones (mandar un mensaje, llamar a una API, correr un poco de JavaScript) uniendo nodos en un editor visual. Pensá en Zapier o Make, pero que podés correr en tu propio servidor.
Hacerlo self-hosted tiene sentido por varias razones. Los planes hosteados cobran por ejecución: el plan Starter de n8n Cloud te da 2.500 ejecuciones por mes por USD 24 (20 si pagás anual), y un solo workflow que corre cada cinco minutos se las gasta en unos nueve días. La cuenta en dólares se hace sola: un VPS chico, como los más básicos de Hetzner, sale alrededor de USD 5 por mes. La versión self-hosted no tiene ese límite y es gratis para uso propio bajo su licencia fair-code. Tus datos y credenciales quedan en tu máquina. Y son un puñado de contenedores de Docker con una base de datos al lado, que es exactamente el tipo de cosa en la que Coolify es bueno.
En este artículo te muestro cómo desplegar n8n en Coolify con una base de datos PostgreSQL, ponerlo detrás de tu propio dominio, dejar bien las variables de entorno para que los webhooks funcionen y probar un primer workflow. Se apoya en mi post sobre cómo instalar Coolify, y si seguiste el de Cloudflare Tunnels, también hay una sección para vos.
Para esta guía asumo que ya tenés una instancia de Coolify corriendo en un servidor Linux y un dominio, o un subdominio, que podés apuntar a ella.
Qué necesitás
- Un servidor con Coolify instalado. n8n en sí es liviano, pero tené en cuenta que cada ejecución de un workflow se guarda en la base de datos, así que dejale algo de lugar:
2 GBde RAM van cómodos para uso personal. - Un dominio para el editor, por ejemplo
n8n.example.com. Los webhooks son la razón principal para tener n8n online, y los servicios de terceros solo van a llamar a una URL pública con HTTPS. - Diez minutos.
Creando el servicio
Coolify trae n8n como servicio de un clic, así que no hay que escribir ningún compose. Andá a Projects, abrí tu proyecto y entorno, hacé clic en + New y escribí n8n en el buscador. Vas a ver dos variantes: n8n a secas, que guarda todo en un archivo SQLite, y n8n with PostgreSQL. Elegí la de PostgreSQL.
SQLite funciona, pero n8n escribe una fila por cada ejecución y sus datos, y ese archivo crece rápido y se vuelve lento de compactar. PostgreSQL lo maneja sin quejarse, y es la base de datos que n8n recomienda para cualquier cosa que no sea una prueba rápida. Coolify crea los contenedores por vos (n8n, un task runner chico donde se ejecutan tus nodos Code, y PostgreSQL), los conecta en la misma red privada y genera la contraseña de la base de datos.
Una vez creado el servicio caés en su página. El compose que lo define está ahí mismo en el editor, y podés retocarlo después; por ahora, fijate en las dos cosas que importan:
- El volumen montado en
/home/node/.n8n. Ahí n8n guarda su configuración y la clave de cifrado que protege todas las credenciales que guardes. Aparece en la pestaña Persistent Storage y tiene que sobrevivir a los redeploys. - Las variables mágicas como
SERVICE_URL_N8N. Coolify las completa a partir del dominio que configures en el servicio (la URL completa en este caso;SERVICE_FQDN_N8Nes solo el host), y el template las usa para decirle a n8n cuál es su URL pública.
Configurando el dominio
En la página del servicio, buscá el contenedor de n8n y configurale el dominio. Cómo lo escribís depende de cómo esté expuesto tu servidor.
Con un servidor público
Si tu servidor tiene IP pública y Coolify se encarga del TLS, como en mi primer post, configurá el dominio como https://n8n.example.com y creá el registro DNS correspondiente si no cae ya dentro de tu wildcard. Traefik pide el certificado de Let's Encrypt en el primer deploy:
n8n.example.com A IP_DE_TU_SERVIDORDetrás de un Cloudflare Tunnel
Si tus apps pasan por un tunnel, aplica la regla del post anterior: configurá el dominio en Coolify como http://n8n.example.com (http plano, el TLS termina en Cloudflare) y agregá un public hostname en Zero Trust apuntando a localhost:80, o coolify-proxy:80 si tu conector corre como contenedor.
Configurando el entorno
Abrí la pestaña Environment Variables del servicio. El template ya configura lo esencial, pero hay un puñado de variables que vale la pena agregar o cambiar antes del primer deploy:
# URL pública que n8n anuncia (necesaria detrás de un tunnel, inofensiva si no)
N8N_PROTOCOL=https
N8N_EDITOR_BASE_URL=https://n8n.example.com/
WEBHOOK_URL=https://n8n.example.com/
# Cuántos proxies agregan cabeceras X-Forwarded-* antes de n8n. El Traefik de Coolify es uno; mirá más abajo para tunnels
N8N_PROXY_HOPS=1
# Tu zona horaria, para los schedules y los nodos de fecha
GENERIC_TIMEZONE=America/Argentina/Buenos_Aires
TZ=America/Argentina/Buenos_Aires
# Clave con la que se cifran las credenciales guardadas. Generala una vez, guardala para siempre.
N8N_ENCRYPTION_KEY=<UNA_CADENA_LARGA_AL_AZAR>
# Borrar ejecuciones viejas. Por defecto se guardan 14 días o 10.000 filas; una semana sobra para uso personal
EXECUTIONS_DATA_PRUNE=true
EXECUTIONS_DATA_MAX_AGE=168N8N_PROXY_HOPS le dice a n8n cuántos reverse proxies agregan cabeceras de reenvío delante de él, para que pueda leer la IP real del visitante de X-Forwarded-For (la usa, entre otras cosas, para limitar los intentos de login). En un servidor público es solo Traefik. Detrás de un Cloudflare Tunnel hay dos proxies, pero 1 sigue siendo el valor correcto: el Traefik de Coolify no confía por defecto en las cabeceras que le manda el conector, así que descarta las que puso Cloudflare y escribe las suyas, y n8n solo ve un salto. El costo es que n8n registra la dirección del conector en vez de la del visitante. Si necesitás la IP real, agregá la dirección del conector a --entrypoints.http.forwardedHeaders.trustedIPs en la configuración del proxy de Coolify y poné N8N_PROXY_HOPS=2.
En guías viejas vas a ver N8N_RUNNERS_ENABLED. Desde n8n 2.0 los task runners están siempre activos y la variable quedó deprecada; el template ya los corre en su propio contenedor, que es donde se ejecutan tus nodos Code.
La clave de cifrado la podés generar en cualquier máquina con openssl rand -hex 32. Lo que nos lleva a la única cosa que de verdad no querés perder:
Desplegando
Apretá Deploy y mirá los logs. Coolify descarga las imágenes, levanta primero PostgreSQL y después n8n con su task runner; n8n corre sus migraciones de base de datos en el primer arranque. Cuando los contenedores aparecen como healthy, abrí tu dominio.
La primera pantalla te pide crear la cuenta de owner: email, nombre y contraseña. Después de esto no hay un registro aparte, así que hacelo enseguida. Más adelante podés invitar usuarios desde Settings -> Users.
Probándolo
Un webhook es la forma más rápida de comprobar que toda la cadena funciona, desde internet hasta el contenedor y de vuelta. Creá un workflow nuevo, agregá un disparador Webhook, dejá el método en GET y copiá la URL de prueba que muestra. Hacé clic en Listen for test event y llamala desde tu computadora:
curl -i https://n8n.example.com/webhook-test/TU_RUTA_DE_WEBHOOKEl nodo debería iluminarse en el editor con los detalles de la solicitud, y la terminal debería recibir un 200. Dos cosas para revisar en esa salida:
- La URL que copiaste empieza con
https://n8n.example.com. Si dice http,WEBHOOK_URLno se está tomando. - La respuesta es un
200, no un301ni un308. Una redirección significa que quien mande un POST va a perder el payload.
Ahora agregá un segundo nodo, por ejemplo Respond to Webhook con un mensaje fijo, guardalo y apretá Publish (n8n 2.0 reemplazó el viejo toggle de activo por un paso explícito de publicación). La URL de producción pierde el sufijo -test:
curl https://n8n.example.com/webhook/TU_RUTA_DE_WEBHOOKSi te vuelve tu mensaje, tenés un servidor de automatización funcionando. Cualquier cosa que pueda hacer una solicitud HTTP ahora puede disparar un workflow.
Mantenimiento
- Actualizaciones: n8n saca versiones seguido y sus versiones menores pueden incluir migraciones de base de datos. En el editor del compose, fijá la imagen a una versión en vez de latest, y cuando quieras actualizar, leé las release notes, cambiá el tag y volvé a desplegar. Volver atrás es entonces solo cambiar el tag de vuelta.
- Backups: la base de datos es el estado. Hacé backup del volumen de PostgreSQL, o de la base en sí, de forma programada, y guardá la clave de cifrado junto con él. Un extra barato es exportar tus workflows como JSON desde adentro del contenedor con el comando de abajo y mandar los archivos a donde quieras.
- Ejecuciones: si la base de datos sigue creciendo, bajá
EXECUTIONS_DATA_MAX_AGEo configurá a nivel de workflow que guarde solo las ejecuciones fallidas. La mayoría de las veces no necesitás el payload de cada corrida exitosa.
docker exec -u node -it <CONTENEDOR_N8N> n8n export:workflow --all --output=/home/node/.n8n/workflows-backup.jsonProblemas frecuentes
Las preguntas que más veo, con la respuesta corta. Los detalles están en las secciones de arriba.
¿Por qué la URL de mi webhook empieza con http en vez de https?
n8n la arma a partir de N8N_EDITOR_BASE_URL y WEBHOOK_URL, y detrás de un tunnel Coolify las completa con el dominio http:// que configuraste en el servicio. Poné las dos variables con tu dirección https://, configurá N8N_PROTOCOL=https, volvé a desplegar y comprobá con curl -i que la URL de prueba responde 200 y no una redirección.
n8n se queja de la secure cookie y no me deja iniciar sesión
La cookie de sesión solo viaja por HTTPS, así que estás abriendo n8n por HTTP plano: por la IP del servidor, por un puerto o por un dominio que Cloudflare no está proxeando. Arreglá el dominio para que llegue a n8n por HTTPS de punta a punta. Poner N8N_SECURE_COOKIE=false hace desaparecer el error, pero tu sesión viaja sin cifrar, así que dejalo solo para pruebas locales.
Los webhooks no funcionan detrás de un Cloudflare Tunnel
Tres cosas para revisar: el dominio en Coolify es http:// (Traefik nunca ve TLS), WEBHOOK_URL es https:// y Always Use HTTPS está activado en Cloudflare. Si la URL que muestra n8n es http, a quien llama lo redirigen, y un POST redirigido pierde el cuerpo. Con curl -i querés un 200, no un 301 ni un 308.
Las credenciales quedaron ilegibles después de un restore
La base se restauró con una N8N_ENCRYPTION_KEY distinta de la que las cifró. Configurá la clave original y reiniciá; si se perdió, las credenciales también, y vas a tener que cargarlas de nuevo. Guardá la clave junto con tus backups.
¡Eso es todo! Tenés n8n corriendo en tu propio servidor, accesible por HTTPS, con sus credenciales cifradas con una clave que controlás vos. Desde acá podés conectarlo con lo que ya tengas corriendo en Coolify (una base de datos, una API, este blog) y empezar a automatizar las partes aburridas. Cuando una sola instancia deje de alcanzar, el siguiente paso es el queue mode de n8n con Redis y contenedores worker, que también encaja bien en un servicio compose de Coolify.

