Por qué alojar n8n en su VPS
La versión cloud de n8n factura por ejecución más allá del plan y limita el número de workflows activos. En su VPS, el único coste es el del servidor, con independencia del número de automatizaciones o de llamadas API. Conserva además el control total sobre los credentials, las cargas útiles de los webhooks y el historial de ejecuciones — ningún dato transita por una infraestructura de terceros.
Las ventajas concretas de un n8n autoalojado
- Ejecuciones sin límite: ningún tope mensual, ningún sobrecoste al escalar.
- Credentials y payloads de webhooks confinados en su servidor, sin tránsito externo.
- Acceso a los nodes comunitarios y a la ejecución de código personalizado sin restricción.
- Webhooks en su propio dominio, configurables para cada integración entrante.
- Coste previsible: un precio de VPS fijo, independiente del volumen de automatizaciones.
- Persistencia controlada de los workflows y del historial en volúmenes de los que usted hace copia de seguridad.
- Compatibilidad con Ollama, Flowise o cualquier otro servicio Docker en la misma red interna.
Requisitos previos con cifras
Antes de empezar, compruebe que su VPS cumple los requisitos siguientes. Para un uso moderado, 1 vCPU y 1 GB de RAM bastan; prevea 2 vCPU y 2 GB en cuanto ejecute workflows pesados o concurrentes, y 4 GB si conecta una base PostgreSQL dedicada o integra un modelo de IA local. Cuente con 10 GB de disco como mínimo para Docker, los volúmenes y los logs. En la parte de red, el puerto 5678 no debe exponerse directamente — n8n solo escucha en 127.0.0.1:5678 y todas las peticiones pasan por el reverse proxy en el puerto 443. Se requiere un subdominio (por ejemplo n8n.su-dominio.com) que apunte a la IP del VPS para HTTPS y los webhooks entrantes. Son necesarios Docker Engine 24+ y Docker Compose v2 (plugin, no el binario docker-compose independiente).
Instalación paso a paso
Actualizar el VPS e instalar Docker
Conéctese por SSH y actualice los paquetes:
apt update && apt upgrade -y. Instale después Docker con el script oficial:curl -fsSL https://get.docker.com | sh. Compruebe la instalación:docker --version && docker compose version. Cree el directorio de trabajo:mkdir -p /opt/n8n && cd /opt/n8n.Crear el archivo docker-compose.yaml
Cree
docker-compose.yamlcon el servicio n8n, un volumen con nombre para la persistencia y las variables de entorno esenciales. Declareimage: n8nio/n8n:latest,restart: unless-stopped, y monten8n_data:/home/node/.n8n. Exponga únicamente en127.0.0.1:5678:5678para evitar cualquier exposición pública directa del puerto.Fijar las variables de entorno críticas
En la sección
environmentdel servicio, declare como mínimo:N8N_HOST=n8n.su-dominio.com,N8N_WEBHOOK_URL=https://n8n.su-dominio.com/,N8N_PROXY_HOPS=1(para que n8n acepte las cabecerasX-Forwarded-*del reverse proxy),N8N_BASIC_AUTH_ACTIVE=true,N8N_BASIC_AUTH_USER=<votre-login>yN8N_BASIC_AUTH_PASSWORD=<mot-de-passe-fort>. Para producción, guarde estos valores en un archivo.envadyacente y refiéralo conenv_file: .env.Arrancar el contenedor
Lance:
docker compose up -d. Compruebe que el contenedor funciona:docker compose ps. Consulte los logs:docker compose logs -f n8n. n8n está listo cuando aparece en los logs la líneaEditor is now accessible via: http://localhost:5678/. La interfaz solo es accesible en127.0.0.1en esta fase — es intencionado.Configurar el reverse proxy con Caddy (recomendado)
Caddy es el reverse proxy más sencillo para n8n: gestiona el certificado Let's Encrypt y su renovación sin configuración adicional. Instale Caddy (
apt install caddy) y edite/etc/caddy/Caddyfilepara añadir:n8n.su-dominio.com { reverse_proxy localhost:5678 }. Recargue:systemctl reload caddy. Con nginx, añada en su bloquelocation:proxy_set_header X-Forwarded-Host $host;,proxy_set_header X-Forwarded-Proto $scheme;yproxy_set_header X-Real-IP $remote_addr;— sin estas cabeceras, n8n reconstruye URL de webhooks incorrectas.Comprobar los webhooks entrantes
En el editor de n8n, cree un workflow de prueba con un node Webhook. La URL mostrada en modo producción debe ser exactamente
https://n8n.su-dominio.com/webhook/<su-ruta>. Dispare la llamada desde su máquina local:curl -X POST https://n8n.su-dominio.com/webhook/test -d '{}'. Si la URL mostrada contienelocalhosto el puerto5678, la variableN8N_WEBHOOK_URLno se tiene en cuenta — compruebe que el contenedor se ha reiniciado tras añadir la variable.Conectar PostgreSQL para producción
SQLite sirve para probar; en producción, prefiera PostgreSQL. Añada un servicio
postgres:15al mismodocker-compose.yaml, con un volumen dedicadopg_data. En el servicio n8n, añada:DB_TYPE=postgresdb,DB_POSTGRESDB_HOST=postgres,DB_POSTGRESDB_DATABASE=n8n,DB_POSTGRESDB_USER=n8n,DB_POSTGRESDB_PASSWORD=<mot-de-passe>. Reinicie el conjunto:docker compose up -d. La base SQLite no se migra automáticamente — exporte sus workflows antes de cambiar.
Endurecimiento y modo queue
Tres reflejos de producción: (1) No exponer nunca el puerto 5678 en la interfaz pública — mantenga el enlace 127.0.0.1:5678. (2) Active la autenticación: en v1.x, N8N_BASIC_AUTH_ACTIVE=true; en v1.27+, prefiera la autenticación nativa desde la interfaz (Ajustes → Seguridad). (3) Para workflows de IA o de larga duración, pase al modo queue con una instancia worker separada y una cola Redis: eso aísla las ejecuciones largas de la interfaz y permite escalar horizontalmente sin reconfigurar los webhooks.
Asegurar las ejecuciones persistidas (advisory GHSA-vrv8-j27g-g7cr)
En agosto de 2026, el advisory GHSA-vrv8-j27g-g7cr reveló que tres nodes vuelcan los credentials descifrados en los datos de ejecución persistidos en caso de error: el node Strapi (tokens OAuth escritos en claro en execution_data), el node SeaTable (claves API inscritas en los logs de ejecución de error) y el node Mailcheck (credenciales SMTP persistidas en execution_data). Estos secretos quedan legibles para cualquier usuario con acceso a los logs de ejecución en la interfaz de n8n. En una instancia sin pruning, se acumulan indefinidamente.
Cuatro gestos para corregir y prevenir
Actualizar a la versión que corrige el advisory
La actualización es la única corrección completa para los tres nodes. Compruebe su versión actual:
docker exec n8n n8n --version. Descargue la última imagen y relance:docker compose pull && docker compose up -d. Para la rama estable, la corrección está disponible a partir de la versión 2.35.4; para la rama v1, a partir de la versión 1.123.73. Confirme la ausencia de credentials expuestos en los logs de error tras la actualización.Activar el pruning de las ejecuciones
Añada dos variables en la sección
environmentdel servicio n8n:EXECUTIONS_DATA_PRUNE=trueyEXECUTIONS_DATA_MAX_AGE=168(7 días, expresado en horas). Reinicie el contenedor:docker compose restart n8n. El pruning elimina los datos de ejecución más allá de la antigüedad definida. Reduce la superficie de exposición pero no sustituye a la actualización — los datos expuestos antes del pruning ya han podido ser leídos.Restringir el acceso a los logs de ejecución
En modo multiusuario, compruebe en Ajustes → Usuarios que solo los administradores pueden consultar los logs de ejecución. Esta salvaguarda limita la propagación si se han persistido datos sensibles antes de la actualización. En una instancia de un solo usuario expuesta en un servidor compartido, compruebe que el puerto 5678 no es accesible directamente desde el exterior.
Medida cautelar antes de la actualización
En una instancia todavía sin actualizar: desactive o retire los workflows que utilizan los nodes Strapi, SeaTable o Mailcheck. El problema solo se desencadena en caso de error de ejecución en estos nodes, pero el error puede sobrevenir por un corte de red o un token caducado — condiciones fuera de su control directo.
Crash V8 fatal con más de 30 workflows activos
Síntoma. La instancia n8n se detiene bruscamente con el error FATAL ERROR: invalid-mark-compact are transition en los logs de Docker. El contenedor se reinicia si restart: unless-stopped está configurado, pero el crash se reproduce en cuanto la carga vuelve a pasar el mismo umbral. Ningún mensaje de error en la interfaz: el contenedor desaparece sin avisar.
Causa. Este error es un pánico del motor V8 (el motor JavaScript embebido en Node.js) durante un ciclo de garbage collection. Se desencadena cuando el heap de memoria de V8 está saturado — típicamente a partir de 30 workflows ejecutándose simultáneamente en un VPS con menos de 2 GB de RAM asignados al proceso. Cada workflow activo mantiene un contexto de ejecución en memoria; más allá de cierto umbral, el GC intenta una transición mark-compact sobre un heap ya corrupto, lo que provoca el crash fatal. El problema no tiene recuperación automática: n8n no dispone de un mecanismo de degradación elegante a este nivel.
Corrección inmediata. Aumente el límite del heap de V8 añadiendo la variable de entorno siguiente en el servicio n8n de su docker-compose.yaml: NODE_OPTIONS=--max-old-space-size=2048. Eso asigna 2 GB al heap de V8. Reinicie el contenedor: docker compose restart n8n. Observe los logs durante unos minutos para confirmar la ausencia de crash.
Corrección estructural. El límite de memoria del contenedor debe corresponder al límite de V8. Si su docker-compose.yaml declara mem_limit: 1g y usted pasa --max-old-space-size=2048, el OOM killer mata el contenedor antes de que V8 pueda usarlo. Regla: asigne al menos 2 GB de RAM a la VM por encima de 30 workflows activos, y pase NODE_OPTIONS=--max-old-space-size=1536 (deje 512 MB para el resto del sistema). Para una instalación con más de 50 workflows, prefiera el modo queue (instancia worker Redis separada), que desacopla las ejecuciones del proceso principal y reparte la carga de memoria. Fuente: community.n8n.io thread #308425.
502 Bad Gateway persistente detrás de nginx
Síntoma. Las peticiones cortas tienen éxito pero ciertos workflows devuelven 502 Bad Gateway desde nginx — en particular los workflows que llaman a APIs externas lentas, tratan grandes volúmenes de datos o encadenan numerosos nodes. El 502 se produce exactamente 60 segundos después del inicio de la ejecución, aunque n8n siga trabajando en segundo plano.
Causa. nginx espera por defecto 60 segundos una respuesta del backend antes de cerrar la conexión (proxy_read_timeout = 60 s). Para n8n, el backend es el proceso que ejecuta el workflow: si la ejecución tarda más de 60 segundos, nginx corta la conexión y devuelve un 502. n8n continúa la ejecución en segundo plano (el workflow termina en el lado del servidor), pero el cliente nunca recibe la respuesta — lo que hace creer en un fallo cuando el resultado sí se ha producido. El comportamiento se agrava con los webhooks síncronos que esperan el final del workflow para responder (node Respond to Webhook al final del flujo).
Corrección. Añada estas dos directivas en el bloque location de su configuración nginx que hace de proxy hacia n8n:
proxy_read_timeout 300;proxy_send_timeout 300;
El valor de 300 segundos (5 minutos) cubre la gran mayoría de los workflows largos. Para workflows excepcionalmente largos (importación masiva de datos, cadenas de IA de varias etapas), suba a 600 s. Recargue nginx: nginx -t && systemctl reload nginx. Tenga en cuenta que este valor no sustituye al timeout de conexión (proxy_connect_timeout, manténgalo en 60 s — solo se aplica al establecimiento inicial de la conexión TCP).
Verificación. Lance un workflow deliberadamente lento (node Wait ajustado a 90 s, por ejemplo) y compruebe que la respuesta llega más allá de los 60 segundos sin error. Si el 502 persiste tras la modificación, compruebe que ha editado el bloque location correcto — una configuración nginx fragmentada en varios archivos include puede tener un bloque más específico que anule el timeout. Fuente: community.n8n.io thread #274581.
Breaking changes que conviene conocer (v1.27–v1.31)
Tres cambios de las versiones recientes pueden romper silenciosamente una instancia existente.
Renombrado del parámetro OAuth 2.0 en HTTP Request. El campo oauthTokenData se renombró en las versiones 1.27-1.31. Las peticiones autenticadas con OAuth 2.0 en el node HTTP Request pueden dejar de funcionar sin mensaje de error explícito — n8n envía una petición no autenticada en lugar de lanzar una excepción. Compruebe cada workflow que utilice este node con credentials OAuth después de una actualización.
Formato de la URL de webhook. El formato de la URL generada por los nodes Webhook ha cambiado en este rango de versiones. Si ha copiado URL de webhook fijas en servicios de terceros (Stripe, GitHub, Slack…), vuelva a comprobarlas tras la actualización.
Obsolescencia de $item(). La función $item() disponible en las expresiones y en el node Function está marcada como obsoleta. Su reemplazo es $input.item para el item actual o $('Nom du node').item para los items de un node anterior. Todavía funciona en v1.x.
La lista completa de los breaking changes está disponible en la documentación oficial de n8n.
Resolución de los errores frecuentes
El puerto 5678 es inaccesible. Compruebe que el contenedor funciona (docker compose ps) y que escucha efectivamente en 127.0.0.1:5678. Si prueba desde la máquina local, curl http://127.0.0.1:5678/ debe responder.
Los webhooks muestran localhost en lugar del dominio. La variable N8N_WEBHOOK_URL está ausente o mal definida. Añada N8N_WEBHOOK_URL=https://n8n.su-dominio.com/ (con la barra final) y reinicie: docker compose restart n8n.
N8N_PROXY_HOPS ausente: error 502 o bucle. Sin esta variable, n8n rechaza las cabeceras X-Forwarded-* o entra en bucle con ellas. Añada N8N_PROXY_HOPS=1 en el entorno del contenedor.
Error de permisos en el volumen. El contenedor n8n funciona bajo el UID 1000. Si la carpeta de datos fue creada por root, los permisos son incorrectos: chown -R 1000:1000 /opt/n8n/data y después docker compose restart n8n.
La base PostgreSQL rechaza la conexión. Compruebe que el servicio postgres está en la misma red Docker que n8n (docker network inspect <nom>) y que las variables DB_POSTGRESDB_HOST, DB_POSTGRESDB_USER y DB_POSTGRESDB_PASSWORD se corresponden exactamente con las definidas en el servicio postgres.
Crash V8 brutal (FATAL ERROR: invalid-mark-compact). El heap de memoria de V8 está saturado: más de 30 workflows simultáneos con una RAM insuficiente. Añada NODE_OPTIONS=--max-old-space-size=2048 en el entorno del servicio n8n y aumente la RAM del VPS a 2 GB como mínimo. Vea la sección dedicada más arriba.
502 Bad Gateway persistente (exactamente 60 s). El proxy_read_timeout de nginx está en su valor por defecto (60 s). Llévelo a 300 s en el bloque location de nginx que apunta a n8n. Vea la sección dedicada más arriba.
Credentials visibles en los logs de ejecución. Utiliza uno de los nodes Strapi, SeaTable o Mailcheck en una versión anterior a la corrección del advisory GHSA-vrv8-j27g-g7cr. Actualice a la versión que corrige el advisory y active el pruning de las ejecuciones. Vea la sección dedicada más arriba.
Mantener y hacer evolucionar la instancia
Para las actualizaciones, dos enfoques: Watchtower (vigilancia automática de la imagen y reinicio) o una tarea cron manual (docker pull n8nio/n8n:latest && docker compose up -d). En ambos casos, lea las notas de versión antes de una actualización mayor — los breaking changes enumerados más arriba son representativos del ritmo de los cambios. Mantenga sus exportaciones de workflows al día en un repositorio git: es la copia de seguridad más rápida de restaurar en caso de incidente.
Para los advisories de seguridad, siga la página GitHub Security Advisories del repositorio n8n — las versiones estables publican rápidamente las correcciones críticas, y cada advisory enumera las versiones afectadas y la versión mínima que corrige el problema.