SSD Nodes Learn Hosting plans →
Guías Matt ConnorPor Matt Connor · Actualizado 2026-08-24

Por qué n8n se desconecta en tu VPS

El aviso «pérdida de conexión» puede indicar websocket, reinicios, OOM Killer o una programación inactiva. Aprende a distinguir los 4 casos antes de cambiar nada.

Por qué n8n se desconecta: cuatro fallos, un síntoma

«n8n se desconecta» es una frase que puede describir cuatro fallos diferentes, y cada uno requiere una solución distinta. El editor muestra un aviso de pérdida de conexión mientras el contenedor funciona con normalidad. El contenedor se reinicia por sí solo. El kernel termina el proceso de Node.js porque consume demasiada memoria. O el proceso no tiene ningún problema y un flujo de trabajo activo simplemente nunca se ejecuta. Si cambia el ajuste equivocado, pasará todo un fin de semana resolviendo un problema que no existía.

Por tanto, determine qué fallo tiene antes de modificar la configuración. n8n se ejecuta como un único proceso de Node.js, normalmente dentro de un contenedor Docker y detrás de un proxy inverso que termina TLS (seguridad de la capa de transporte). Cada capa falla de una forma distinta, pero el navegador informa de todas con el mismo mensaje.

Diagnostique en este orden

Ejecute estos comandos en el VPS (servidor privado virtual) y lea los valores que muestra su propia máquina. No los compare con cifras de una publicación de un foro. Los valores importantes aquí describen su servidor, no el de otra persona.

docker ps -a --filter name=n8n
docker logs --tail 200 --timestamps n8n
docker inspect n8n | grep -iE 'Status|Running|RestartCount|OOMKilled|ExitCode'
docker stats --no-stream

La columna STATUS de docker ps -a indica cuánto tiempo lleva el contenedor en su estado actual. Compare ese valor con el momento en que comenzó el problema. Si el contenedor lleva activo desde mucho antes de que apareciera el aviso, n8n nunca estuvo fuera de servicio. El fallo está en la conexión entre el navegador y el backend, concretamente en la ruta websocket que se explica en la sección siguiente.

RestartCount indica cuántas veces Docker ha reiniciado este contenedor. Anote el número, espere un minuto y vuelva a consultarlo. Si el número aumenta mientras lo observa, existe un bucle de reinicios. Las líneas del registro inmediatamente anteriores a cada reinicio contienen la causa.

OOMKilled es un indicador con valor true o false. True significa que el kernel de Linux terminó el proceso porque superó un límite de memoria, ya fuera el límite propio del contenedor o el de toda la máquina. Este campo permite distinguir un proceso terminado por falta de memoria de cualquier otro tipo de salida. Por eso debe consultarlo antes de hacer suposiciones.

ExitCode muestra el código con el que terminó el contenedor la última vez. No necesita memorizar el significado de cada código. Consulte el suyo y, después, lea el final de docker logs correspondiente a la misma hora. El final del registro y el indicador de falta de memoria, considerados conjuntamente, muestran lo que ocurrió; cualquiera de los dos por separado puede inducir a error.

docker stats muestra el uso de memoria actual junto al límite vigente. Déjelo ejecutándose en una segunda terminal, active el flujo de trabajo que provoca el fallo y observe cómo cambia el valor mientras se produce.


El aviso de conexión perdida suele indicar un problema en el reverse proxy

El editor de n8n mantiene abierta una conexión push de larga duración con el backend para transmitir el progreso de la ejecución en el lienzo. De forma predeterminada, esa conexión es un WebSocket, que es lo que selecciona N8N_PUSH_BACKEND, y su valor predeterminado es websocket. Un WebSocket comienza como una solicitud HTTP normal que contiene las cabeceras Connection: Upgrade y Upgrade: websocket. El servidor responde 101 Switching Protocols y, a partir de ese momento, ambos extremos usan el mismo socket TCP en las dos direcciones.

Hay dos problemas que pueden interrumpir este proceso, y ambos se producen en el proxy, no en n8n. El proxy usa HTTP/1.0 hacia el upstream o elimina las cabeceras de upgrade, por lo que la actualización nunca se completa y el editor intenta conectarse de nuevo continuamente. También puede ocurrir que la actualización se complete, pero que el proxy cierre el socket después porque ha permanecido inactivo. Un WebSocket sin mensajes parece exactamente una conexión inactiva. En ambos casos, el contenedor está operativo. El aviso indica que el navegador ha perdido su canal.

Confírmelo en el navegador antes de modificar nada. Abra las herramientas de desarrollo, vaya a la pestaña Network, filtre por WS y vuelva a cargar el editor. La solicitud push debería llegar a 101 Switching Protocols y permanecer abierta. Si la solicitud push devuelve un código de estado normal o vuelve a aparecer cada pocos segundos, el problema está en el proxy.

Configuración de nginx para mantener conectado el editor

nginx no reenvía una actualización si no se le indica. proxy_pass usa HTTP/1.0 para comunicarse con el backend de forma predeterminada, y Connection y Upgrade son cabeceras salto a salto que nginx elimina al reenviar la solicitud. Debe volver a añadir ambas. El bloque map va en el contexto http, no dentro de server. Si el resto del bloque de servidor que aparece a continuación no le resulta familiar, el recorrido línea por línea de un bloque de servidor de nginx explica qué hace cada directiva.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
server {
    listen 443 ssl;
    http2 on;
    server_name n8n.example.com;

    location / {
        proxy_pass http://127.0.0.1:5678;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
    }
}

proxy_read_timeout es la línea que se suele omitir. Su valor predeterminado es 60 segundos y también se aplica a un WebSocket actualizado, por lo que una pestaña del editor que queda abierta en una instancia sin actividad pierde la conexión aproximadamente un minuto después de que haya pasado el último mensaje. Aumentar este valor corrige el aviso que aparece al volver a una pestaña que se dejó abierta.

sudo nginx -t && sudo systemctl reload nginx
sudo nginx -T | grep -iE 'proxy_http_version|upgrade|proxy_read_timeout'

nginx -T muestra toda la configuración activa en lugar de un solo archivo, por lo que confirma que la modificación se ha cargado realmente. Si la configuración está en un archivo que ninguna línea include incorpora, una corrección correcta parecerá no tener efecto.

A continuación, indique a n8n que está detrás de un proxy, porque genera las URL a partir de estos valores.

environment:
  - N8N_HOST=n8n.example.com
  - N8N_PROTOCOL=https
  - N8N_PORT=5678
  - N8N_PROXY_HOPS=1
  - N8N_WEBHOOK_URL=https://n8n.example.com/

N8N_PROXY_HOPS tiene el valor predeterminado 0, lo que significa que n8n trata la dirección de conexión como la dirección del cliente e ignora X-Forwarded-For. Establézcalo en el número de proxies situados delante del contenedor. En agosto de 2026, N8N_WEBHOOK_URL es el nombre actual y WEBHOOK_URL, el nombre anterior, todavía funciona, aunque muestra un aviso de obsolescencia al iniciar.

Traefik reenvía WebSocket, pero después agota el tiempo de espera

Traefik reenvía la actualización a WebSocket sin middleware ni etiquetas adicionales. Por eso, cuando un usuario de Traefik ve este aviso, normalmente se encuentra con un tiempo de espera agotado y no con una cabecera ausente. Los parámetros se configuran en entryPoint. En agosto de 2026, en Traefik v3, idleTimeout tiene un valor predeterminado de 180 segundos y readTimeout tiene un valor predeterminado de 60 segundos.

entryPoints:
  websecure:
    address: ":443"
    transport:
      respondingTimeouts:
        readTimeout: 0
        idleTimeout: 3600s

Caddy gestiona automáticamente la actualización en reverse_proxy y no necesita ninguna directiva para ello. Si no puede cambiar el proxy porque pertenece a otra persona, cambie el canal de envío mediante N8N_PUSH_BACKEND=sse. SSE (eventos enviados por el servidor) es una respuesta HTTP normal que permanece abierta. Por eso funciona aunque el proxy rechace las actualizaciones. Sin embargo, un tiempo de espera por inactividad demasiado agresivo también puede interrumpirla. Elegir el proxy es una decisión independiente. La comparación entre nginx, Caddy y Traefik explica cuánto trabajo operativo requiere cada uno.

Cuando el contenedor realmente se reinicia

Si RestartCount aumenta, el contenedor está fallando y Docker lo vuelve a iniciar. Compare las marcas de tiempo del registro con cada reinicio y lea lo que ocurrió inmediatamente antes. Casi todos los casos se deben a una de estas cuatro causas: un error de configuración que impide el arranque, una base de datos a la que n8n no puede conectarse, un bloqueo después del arranque o una terminación por falta de memoria.

Empiece por el volumen, porque los permisos suelen fallar sin mostrar una causa evidente. La imagen oficial se ejecuta con el usuario sin privilegios node y guarda sus datos en /home/node/.n8n. Un bind mount creado por root no permite escribir a ese usuario. Por eso el proceso termina durante el arranque cada vez y la política de reinicio oculta el problema detrás de un ciclo.

docker compose config
docker run --rm -it --entrypoint sh docker.n8n.io/n8nio/n8n -c 'id'
docker exec n8n ls -ld /home/node/.n8n

Un volumen con nombre evita completamente el problema, porque Docker lo crea con el propietario correcto. Si necesita un bind mount, chown el directorio del host al identificador numérico de usuario que mostró el primer comando. Conviene entender una vez cómo se asignan los propietarios entre el host y el contenedor. La explicación de PUID y PGID describe cómo estas imágenes determinan qué usuario escribe los archivos.

El cierre por falta de memoria que parece un bloqueo

Hay dos límites de memoria independientes por encima de un proceso de n8n, y fallan de forma diferente. El límite del grupo de control del contenedor lo aplica el kernel: si se supera, el proceso termina de inmediato, sin posibilidad de escribir nada, y OOMKilled devuelve true. El límite del heap de V8 lo aplica Node.js internamente: si se supera, Node genera un error del heap con un seguimiento de pila y termina por su cuenta, por lo que OOMKilled devuelve false. Desde el navegador, ambos casos parecen idénticos. Desde docker inspect, están separados por un solo campo.

Establezca el límite del heap de Node por debajo del límite del contenedor. Si el límite del heap es el mayor de los dos, V8 sigue asignando memoria después de que el kernel debería intervenir. Por tanto, su recolector de basura nunca alcanza su propio límite y siempre se produce el fallo más grave, sin ningún registro que revisar.

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n
    restart: unless-stopped
    environment:
      - NODE_OPTIONS=--max-old-space-size=<MiB, below the container limit>
    deploy:
      resources:
        limits:
          memory: <your container limit>

Elija ambos valores según los recursos reales de su VPS y deje margen para la base de datos, el proxy y el sistema operativo. docker stats --no-stream muestra el uso actual junto al límite aplicado, de modo que puede comprobar que el límite configurado es el que Docker aplicó. Cómo se aplican los límites de memoria de Compose explica qué clave tiene prioridad cuando se establecen varias.

Los datos de ejecución crecen por debajo

Una sola ejecución contiene la salida de todos los nodos mientras el flujo está en curso, y n8n almacena esos datos. De ahí se siguen dos consecuencias. La memoria máxima de una ejecución depende del lote de datos más grande que se procese. Por tanto, un flujo que procesa diez mil filas de una vez es un programa distinto del mismo flujo cuando procesa doscientas cada vez. Además, la copia almacenada sigue creciendo hasta que algo la elimina.

La depuración resuelve el segundo problema. En agosto de 2026, los valores predeterminados son la depuración habilitada, EXECUTIONS_DATA_MAX_AGE en 336 horas (14 días) y EXECUTIONS_DATA_PRUNE_MAX_COUNT en 10000. Son valores generosos para un VPS pequeño que ejecuta SQLite, donde un solo archivo contiene todos los datos y el mismo proceso que sirve el editor debe leerlo y escribirlo.

environment:
  - EXECUTIONS_DATA_PRUNE=true
  - EXECUTIONS_DATA_MAX_AGE=72
  - EXECUTIONS_DATA_PRUNE_MAX_COUNT=1000
  - EXECUTIONS_DATA_SAVE_ON_SUCCESS=none
  - EXECUTIONS_DATA_SAVE_MANUAL_EXECUTIONS=false

EXECUTIONS_DATA_SAVE_ON_SUCCESS=none es la configuración más agresiva. Conserva las ejecuciones fallidas para depuración y elimina las que terminan correctamente. Decídalo de forma explícita, porque un flujo que genere una salida incorrecta sin producir un error no dejará nada que inspeccionar. La depuración también marca primero las filas como eliminadas y las borra en una pasada posterior. Además, SQLite reutiliza las páginas liberadas en lugar de devolverlas, por lo que el archivo del disco no se reduce en cuanto cambia la configuración.

Para reducir el pico en lugar del total almacenado, mueva menos datos en cada ejecución. Divida los trabajos grandes en subflujos de trabajo que devuelvan resultados pequeños al flujo principal, procese los datos por lotes con el nodo Loop Over Items y evite cargar conjuntos de datos completos en el nodo Code.

Los archivos binarios no deben pasar por la memoria

N8N_DEFAULT_BINARY_DATA_MODE tiene el valor predeterminado default, que mantiene los datos binarios en la memoria de la ejecución en curso. Cada archivo que descarga un nodo y cada copia que se entrega al nodo siguiente permanecen allí hasta que termina la ejecución. Un workflow que obtiene varios archivos adjuntos grandes puede hacer que el proceso supere un límite al que el procesamiento normal de JSON nunca se acerca. Por eso el fallo afecta a un workflow concreto y no depende del tiempo transcurrido.

environment:
  - N8N_DEFAULT_BINARY_DATA_MODE=filesystem

Con filesystem, los datos binarios se escriben en N8N_BINARY_DATA_STORAGE_PATH, que de forma predeterminada se encuentra dentro de la carpeta de usuario de n8n y, por tanto, en el mismo volumen que todo lo demás. Compruebe que el volumen tenga espacio disponible antes de cambiar esta opción. N8N_PAYLOAD_SIZE_MAX establece el tamaño máximo, en MiB (mebibytes), de la carga útil entrante de un webhook y tiene el valor predeterminado 16. Al aumentarlo, se permiten solicitudes más grandes, pero debe asumir el coste de memoria correspondiente.

Todo lo demás que comparta el servidor compite por la misma RAM. Si los procesos OOM killer empezaron cuando añadió un contenedor de base de datos, ejecutar la base de datos en Docker o en el host es la decisión que debe tomar ahora.

Política de reinicio y recuperación tras un reinicio

Un contenedor sin una política de reinicio permanece detenido después de salir y después de que se reinicie el host. restart: unless-stopped lo vuelve a iniciar en ambos casos, pero respeta un contenedor que haya detenido manualmente. restart: always también reinicia un contenedor detenido de forma deliberada cuando Docker vuelve a iniciarse.

n8n ofrece un endpoint de estado, indicado por N8N_ENDPOINT_HEALTH, cuyo valor predeterminado es healthz. Compruébelo primero desde el host para confirmar que la ruta es correcta en su instancia.

curl -fsS http://127.0.0.1:5678/healthz
docker exec n8n which wget curl
sudo systemctl is-enabled docker

Un healthcheck por sí solo no reinicia nada. Compose marca el contenedor como no saludable y no hace nada más. Por tanto, el healthcheck necesita una política de reinicio o un monitor externo junto a él para tener algún efecto. Escribir un healthcheck que realmente actúe y hacer que la pila vuelva a iniciarse tras un reinicio cubren ambas partes.

El flujo de trabajo que nunca se ejecuta aunque n8n funciona

Este flujo no muestra ningún banner ni reinicia nada. El contenedor está activo, el editor funciona y la ejecución esperada no aparece en la lista de ejecuciones. Cuatro causas explican la mayoría de estos casos.

  • El flujo de trabajo no está activo. Un Schedule Trigger sólo se ejecuta en la ruta de producción, por lo que probarlo en el lienzo no programa ninguna ejecución.
  • La zona horaria no es la suya. GENERIC_TIMEZONE usa America/New_York de forma predeterminada, por lo que una programación establecida para las 09:00 se ejecuta a las 09:00 en esa zona hasta que configure GENERIC_TIMEZONE y TZ con su propia zona.
  • El tiempo de inactividad no se recupera después. Los triggers se registran cuando n8n se inicia, por lo que una programación cuyo momento llegó mientras el contenedor se reiniciaba no se ejecuta con retraso. La siguiente ejecución será la próxima programada después del arranque.
  • El flujo de trabajo se desactivó automáticamente. N8N_WORKFLOW_AUTODEACTIVATION_ENABLED está desactivado de forma predeterminada. Cuando está activado, un flujo que sigue fallando se despublica, y después parece exactamente uno que nunca se activó.

Abra la lista de ejecuciones y filtre por ese flujo de trabajo. Una entrada con error indica un problema del flujo. Si falló con un 429 contra otro servicio alojado en el mismo servidor, el límite pertenece a ese servicio y no a n8n. El tutorial sobre errores 429 de SearXNG explica cómo distinguir su propio limitador de tasa de los motores que bloquean la IP de su servidor. Si no hay ninguna entrada, el problema está en el trigger. Las cuatro causas anteriores son los primeros puntos que debe revisar.

Qué cambiar primero

  1. Lea STATUS, RestartCount y OOMKilled en su propio contenedor antes de editar cualquier archivo.
  2. Si el contenedor nunca se detuvo, corrija las cabeceras de actualización del proxy y el tiempo de espera de inactividad.
  3. Si OOMKilled es verdadero, establezca deliberadamente un límite para el contenedor, configure por debajo el límite máximo del heap de Node y cambie los datos binarios a filesystem.
  4. Si no se activó nada, compruebe que el flujo de trabajo esté activo y que la zona horaria de la instancia sea la suya.

La mayor parte de estos ajustes se configura una vez y después no requiere más cambios, siempre que la instalación funcione. Si todavía está preparando esa instalación, la guía para ejecutar n8n en Docker con HTTPS es la base a la que pertenecen estos ajustes.

FAQ

¿Por qué el editor de n8n muestra un aviso de pérdida de conexión mientras el contenedor está en ejecución?

El editor mantiene abierto un WebSocket para transmitir el progreso de las ejecuciones. Si el proxy inverso no reenvía las cabeceras Connection: Upgrade y Upgrade: websocket, o no usa HTTP/1.1 hacia el upstream, la actualización nunca se completa y el navegador intenta conectarse de nuevo continuamente mientras n8n sigue funcionando. En nginx necesita proxy_http_version 1.1 y las dos líneas proxy_set_header, además de un proxy_read_timeout superior a los 60 segundos predeterminados para que una pestaña inactiva no se desconecte. Compruebe la configuración activa con sudo nginx -T, no el archivo que editó.

¿Cómo distingo una terminación por falta de memoria de un fallo normal?

Ejecute docker inspect n8n | grep -iE 'OOMKilled|ExitCode|RestartCount' y consulte el indicador OOMKilled. El valor True significa que el kernel terminó el proceso porque superó un límite de memoria. No habrá información útil en el registro del contenedor porque el proceso no tuvo oportunidad de escribirla. El valor False, junto con un error de heap y un stack trace al final de docker logs, significa que Node.js alcanzó su propio límite de heap de V8 y terminó por sí mismo. Configure NODE_OPTIONS=--max-old-space-size por debajo del límite del contenedor para obtener el segundo tipo de fallo. Es el que deja pruebas.

¿La depuración de los datos de ejecución libera espacio en disco inmediatamente?

No. EXECUTIONS_DATA_PRUNE marca las ejecuciones antiguas para eliminarlas y una pasada posterior las elimina, según el calendario definido por EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL. Con SQLite, el archivo también reutiliza las páginas liberadas en lugar de devolverlas al sistema de archivos. Por eso, el tamaño en disco permanece estable durante un tiempo después de eliminar las filas. Configure EXECUTIONS_DATA_MAX_AGE y EXECUTIONS_DATA_PRUNE_MAX_COUNT con valores adecuados para su servidor y vuelva a comprobarlo al día siguiente, no inmediatamente.

¿Por qué no se ejecutó mi workflow programado mientras n8n se reiniciaba?

n8n registra los triggers cuando se inicia el proceso y no vuelve a ejecutar las programaciones cuyo momento llegó mientras estaba detenido. Por tanto, un ciclo de reinicios produce silencio en lugar de una ráfaga de ejecuciones pendientes. La siguiente ejecución será la siguiente hora programada después del arranque. Si necesita ejecuciones que no se puedan perder, haga que un sistema externo active el workflow mediante una petición a un webhook. Así, la lógica de reintento queda fuera de n8n.

¿Un healthcheck reiniciará n8n cuando deje de responder?

No por sí solo. Un healthcheck de Compose sólo marca el contenedor como healthy o unhealthy. El reinicio depende de la política de reinicio. Por eso, restart: unless-stopped devuelve el contenedor a la ejecución después de que termine y también lo inicia después de reiniciar el host, siempre que el servicio Docker esté habilitado. Confírmelo con sudo systemctl is-enabled docker. Para actuar específicamente cuando el contenedor esté unhealthy, necesita un watcher externo a Docker que lea el estado y reinicie el servicio.