Чому n8n переходить в автономний режим на VPS
Чотири проблеми виглядають як збій n8n: банер websocket, цикл перезапусків, завершення Node.js через нестачу пам’яті або пропущений запуск workflow.
Чому n8n постійно переходить в автономний режим: чотири причини, один симптом
Фраза «n8n постійно переходить в автономний режим» може означати чотири різні проблеми, і для кожної потрібне окреме виправлення. Редактор показує повідомлення про втрату з’єднання, хоча контейнер працює нормально. Контейнер самостійно перезапускається. Ядро завершує процес Node.js через надмірне використання пам’яті. Або з процесом узагалі все гаразд, але активний workflow просто не запускається. Якщо змінити неправильний параметр, можна витратити всі вихідні на усунення проблеми, якої насправді не було.
Спочатку визначте, яка саме проблема виникла, і лише потім змінюйте конфігурацію. n8n працює як один процес Node.js, зазвичай усередині одного Docker-контейнера, за reverse proxy, який завершує TLS (transport layer security). Кожен із цих рівнів виходить із ладу по-своєму, але браузер повідомляє про всі такі проблеми однаковим повідомленням.
Діагностуйте в такому порядку
Виконайте ці команди на VPS (virtual private server) і перегляньте значення, які виводить саме ваш сервер. Не порівнюйте їх із числами з допису на форумі. Тут важливі значення, що описують ваш сервер, а не чужий.
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У стовпці STATUS з docker ps -a зазначено, як довго контейнер перебуває в поточному стані. Порівняйте це значення з моментом початку проблеми. Якщо контейнер працює ще від часу задовго до появи банера, n8n не ставав недоступним. Проблема виникла у з’єднанні між браузером і бекендом. Це websocket-шлях, описаний у наступному розділі.
RestartCount — кількість перезапусків цього контейнера, виконаних Docker. Запишіть число, зачекайте хвилину й перевірте його ще раз. Якщо під час спостереження число зростає, контейнер потрапив у цикл перезапусків. Причину містять рядки журналу безпосередньо перед кожним перезапуском.
OOMKilled — логічний прапорець зі значенням true або false. Значення true означає, що ядро Linux завершило процес через перевищення ліміту пам’яті контейнера або всієї машини. Це поле дає змогу відрізнити завершення через нестачу пам’яті від будь-якого іншого завершення. Саме тому його потрібно перевірити до пошуку причини.
ExitCode — код, з яким контейнер завершив роботу востаннє. Не потрібно запам’ятовувати значення всіх кодів. Перевірте свій код, а потім перегляньте кінець docker logs за тією самою часовою позначкою. Останні рядки журналу та прапорець out of memory разом показують, що сталося. Окремо кожен із них може ввести в оману.
docker stats показує поточне використання пам’яті поруч із чинним лімітом. Залиште команду запущеною в іншому терміналі, запустіть workflow, під час якого виникає проблема, і спостерігайте за зміною значення під час збою.
Банер про втрату з’єднання зазвичай спричинений вашим reverse proxy
Редактор n8n підтримує одне довготривале push-з’єднання з бекендом, щоб передавати перебіг виконання на canvas. За замовчуванням це WebSocket-з’єднання. Його вибирає N8N_PUSH_BACKEND, а значення за замовчуванням — websocket. WebSocket починається як звичайний HTTP-запит із заголовками Connection: Upgrade і Upgrade: websocket. Сервер відповідає 101 Switching Protocols, після чого обидві сторони використовують той самий TCP-сокет для передавання даних в обох напрямках.
Це з’єднання може перериватися з двох причин, і в обох випадках проблема виникає в proxy, а не в n8n. Proxy використовує HTTP/1.0 для підключення до upstream або видаляє заголовки upgrade. Через це upgrade не відбувається, і редактор безперервно перепідключається. Або upgrade успішно завершується, але пізніше proxy закриває сокет через відсутність трафіку. WebSocket без повідомлень виглядає як неактивне з’єднання. В обох випадках контейнер працює нормально. Банер повідомляє, що браузер втратив свій канал зв’язку.
Перш ніж щось змінювати, перевірте це в браузері. Відкрийте інструменти розробника, перейдіть на вкладку Network, встановіть фільтр WS і перезавантажте редактор. Push-запит має досягти 101 Switching Protocols і залишатися відкритим. Якщо push-запит повертає звичайний код стану або з’являється знову кожні кілька секунд, проблема, найімовірніше, у proxy.
Налаштування nginx, які підтримують підключення редактора
nginx не пересилає upgrade-запит, якщо явно не вказати це в конфігурації. proxy_pass за замовчуванням використовує HTTP/1.0 для підключення до бекенду, а Connection і Upgrade — це hop-by-hop заголовки, які nginx видаляє під час пересилання. Потрібно додати обидва заголовки знову. Блок map потрібно розмістити в контексті http, а не всередині server.
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 — це директива, яку часто пропускають. За замовчуванням її значення становить 60 секунд, і вона також застосовується до оновленого WebSocket-з’єднання. Тому вкладка редактора, залишена відкритою для екземпляра без активності, втрачає з’єднання приблизно через хвилину після проходження останнього повідомлення. Збільшення цього значення усуває банер, який відображається після повернення до вкладки, залишеної відкритою.
sudo nginx -t && sudo systemctl reload nginx
sudo nginx -T | grep -iE 'proxy_http_version|upgrade|proxy_read_timeout'nginx -T виводить усю активну конфігурацію, а не лише один файл, тому дає змогу перевірити, що внесені зміни справді завантажено. Якщо конфігурація міститься у файлі, який не підхоплює жодна директива include, правильне виправлення не матиме видимого ефекту.
Після цього повідомте n8n, що він працює за проксі, оскільки n8n формує URL на основі цих значень.
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 за замовчуванням має значення 0. Це означає, що n8n вважає адресою клієнта адресу безпосереднього підключення та ігнорує X-Forwarded-For. Установіть значення, що відповідає кількості проксі перед контейнером. Станом на August 2026 поточною назвою є N8N_WEBHOOK_URL, а старе ім’я WEBHOOK_URL все ще працює, але під час запуску виводить попередження про застарілу назву.
Traefik передає WebSocket-з’єднання, а потім завершує його за тайм-аутом
Traefik передає запит на оновлення WebSocket без middleware і додаткових labels, тому користувач Traefik, який бачить цей банер, зазвичай стикається з тайм-аутом, а не з відсутнім заголовком. Параметри налаштовуються на entryPoint. Станом на August 2026 у Traefik v3 параметр idleTimeout за замовчуванням має значення 180 seconds, а readTimeout — 60 seconds.
entryPoints:
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: 0
idleTimeout: 3600sCaddy автоматично обробляє оновлення в reverse_proxy, тому окрема директива для цього не потрібна. Якщо ви взагалі не можете змінити проксі, оскільки ним керує інша сторона, перемкніть канал push за допомогою N8N_PUSH_BACKEND=sse. SSE (server-sent events) — це звичайна HTTP-відповідь, яку залишають відкритою, тому вона працює через проксі, що відхиляє оновлення, хоча надто короткий тайм-аут простою все одно перерве з’єднання. Вибір самого проксі — окреме рішення, а порівняння nginx, Caddy і Traefik описує операційні витрати для кожного варіанта.
Коли контейнер справді перезапускається
Якщо RestartCount зростає, контейнер завершує роботу через помилку, а Docker запускає його знову. Порівняйте часові позначки в журналі з кожним перезапуском і прочитайте, що сталося безпосередньо перед ним. Майже всі випадки пояснюються чотирма причинами: помилка конфігурації, яка зупиняє запуск, база даних, до якої n8n не може підключитися, збій уже після запуску та завершення процесу через нестачу пам’яті.
Почніть із тому, оскільки проблеми з правами доступу часто залишаються непомітними. Офіційний образ працює від непривілейованого користувача node і зберігає дані в /home/node/.n8n. Bind mount, створений користувачем root, недоступний для запису цьому користувачеві. Тому процес щоразу завершується під час запуску, а політика перезапуску приховує причину за нескінченним циклом.
docker compose config
docker run --rm -it --entrypoint sh docker.n8n.io/n8nio/n8n -c 'id'
docker exec n8n ls -ld /home/node/.n8nІменований том повністю усуває цю проблему, оскільки Docker створює його з правильним власником. Якщо потрібен bind mount, chown каталог на хості на числовий ідентифікатор користувача, який вивела перша команда. Відповідність власників між хостом і контейнером достатньо зрозуміти один раз. У поясненні PUID і PGID описано, як ці образи визначають користувача, від імені якого записуються файли.
Вивільнення пам’яті, яке виглядає як аварійне завершення
Для процесу n8n діють дві окремі верхні межі пам’яті, і в разі перевищення вони поводяться по-різному. Ліміт control group контейнера забезпечує kernel: після його перевищення процес негайно завершується без можливості щось записати, а OOMKilled повертає true. Ліміт heap V8 забезпечує сам Node.js: після його перевищення Node генерує помилку heap зі stack trace і завершує роботу самостійно, тому OOMKilled повертає false. У браузері ці ситуації виглядають однаково. У docker inspect вони відрізняються лише одним полем.
Установіть верхню межу heap Node нижче за ліміт контейнера. Якщо верхня межа heap більша за ліміт контейнера, V8 продовжує виділяти пам’ять після моменту, коли kernel припиняє процес. Тому його garbage collector не досягає власного ліміту, і ви завжди отримуєте жорсткіший збій без журналу для аналізу.
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>Визначте обидва значення на основі фактичних ресурсів вашого VPS і залиште запас для бази даних, проксі та операційної системи. docker stats --no-stream виводить поточне використання поруч із чинним лімітом, тому можна перевірити, що встановлений вами ліміт застосував Docker. Як застосовуються ліміти пам’яті Compose пояснює, який параметр має пріоритет, якщо задано кілька лімітів.
Дані виконання — це те, що накопичується непомітно
Одне виконання містить вихідні дані кожного вузла протягом усього запуску, а потім n8n зберігає ці дані. З цього випливають два наслідки. Пікове споживання пам’яті одним запуском визначається найбільшою порцією даних, яку ви через нього передаєте. Тому workflow, який одночасно обробляє десять тисяч рядків, — це інша програма порівняно з тим самим workflow, що обробляє по двісті рядків. Збережена копія також продовжує зростати, доки її щось не видалить.
Очищення вирішує другу проблему. Станом на серпень 2026 року за замовчуванням очищення увімкнене, EXECUTIONS_DATA_MAX_AGE становить 336 годин (14 днів), а EXECUTIONS_DATA_PRUNE_MAX_COUNT — 10000. Для невеликого VPS із SQLite це досить великі значення: усі дані зберігаються в одному файлі, а той самий процес, який обслуговує редактор, має читати й записувати їх.
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=falseEXECUTIONS_DATA_SAVE_ON_SUCCESS=none — це агресивний режим. Він зберігає невдалі виконання для налагодження та видаляє успішні. Увімкніть цей режим лише свідомо, оскільки workflow може створити неправильний результат без помилки, після чого вам не залишиться нічого для перевірки. Спочатку очищення також лише позначає рядки як видалені, а фактично видаляє їх під час наступного проходу. Крім того, SQLite повторно використовує звільнені сторінки, а не повертає їх операційній системі. Тому файл на диску не зменшиться одразу після зміни налаштування.
Щоб зменшити пікове споживання пам’яті, а не лише обсяг збережених даних, передавайте менше даних за один запуск. Розділяйте великі завдання на sub-workflows, які повертають батьківському workflow невеликі результати. Обробляйте дані порціями за допомогою вузла Loop Over Items і не передавайте цілі набори даних у вузол Code.
Двійкові файли не повинні зберігатися в пам’яті
N8N_DEFAULT_BINARY_DATA_MODE за замовчуванням має значення default, через що двійкові дані зберігаються в пам’яті запущеного виконання. Кожен файл, який завантажує node, і кожна копія, передана наступному node, залишаються там до завершення виконання. Один workflow, який отримує кілька великих вкладень, може перевищити ліміт, до якого звичайна робота з JSON навіть не наближається. Саме тому збій виникає в одному конкретному workflow, а не через певний час роботи.
environment:
- N8N_DEFAULT_BINARY_DATA_MODE=filesystemЯкщо використати filesystem, двійкові дані записуються в N8N_BINARY_DATA_STORAGE_PATH. Типово цей каталог розташований у папці користувача n8n, тому дані потрапляють на той самий том, що й решта файлів. Перед перемиканням перевірте, чи достатньо вільного місця на томі. N8N_PAYLOAD_SIZE_MAX задає максимальний розмір вхідного payload вебхука в MiB (мебібайтах), а типове значення становить 16. Збільшення цього значення дає змогу приймати більші запити, але водночас збільшує споживання пам’яті.
Усе, що додатково працює на сервері, використовує ту саму RAM. Якщо OOM kill почалися після додавання контейнера бази даних, запуск бази даних у Docker або на хості — це компроміс, який тепер потрібно врахувати.
Політика перезапуску та відновлення після перезавантаження
Контейнер без політики перезапуску залишається зупиненим після завершення роботи та після перезавантаження хоста. restart: unless-stopped запускає його знову в обох випадках, але не запускає контейнер, який ви зупинили вручну. restart: always також перезапускає контейнер, який ви зупинили навмисно, після наступного запуску Docker.
n8n надає endpoint перевірки стану, назву якого визначає N8N_ENDPOINT_HEALTH. Значення за замовчуванням — healthz. Спочатку перевірте його з хоста, щоб переконатися, що шлях у вашому екземплярі правильний.
curl -fsS http://127.0.0.1:5678/healthz
docker exec n8n which wget curl
sudo systemctl is-enabled dockerСам по собі healthcheck нічого не перезапускає. Compose позначає контейнер як несправний і на цьому зупиняється. Тому healthcheck потребує політики перезапуску або зовнішнього watcher-процесу, який працює разом із ним, щоб мати практичний ефект. Написання healthcheck, який справді виконує дію і налаштування повторного запуску stack після перезавантаження охоплюють обидві частини.
Робочий процес не запускається, хоча n8n працює
У цьому випадку банер не з’являється, а перезапуск не відбувається. Контейнер запущений, редактор працює, але очікуваного запуску немає у списку виконань. Найчастіше причина одна з чотирьох.
- Робочий процес неактивний. Schedule Trigger запускається лише у production-шляху, тому тестування на canvas нічого не планує.
- Вибрано неправильний часовий пояс.
GENERIC_TIMEZONEза замовчуванням має значенняAmerica/New_York, тому розклад на 09:00 запускається о 09:00 у цьому часовому поясі, доки ви не встановитеGENERIC_TIMEZONEіTZдля свого часового поясу. - Пропущені запуски не виконуються пізніше. Тригери реєструються під час запуску n8n, тому розклад, час якого настав під час перезапуску контейнера, не запускається із запізненням. Наступний запуск відбудеться в найближчий запланований час після запуску.
- Робочий процес було деактивовано автоматично.
N8N_WORKFLOW_AUTODEACTIVATION_ENABLEDза замовчуванням вимкнено. Якщо його ввімкнути, робочий процес, який постійно завершується з помилкою, буде знято з публікації. Після цього він виглядає так само, як робочий процес, який ніколи не активували.
Відкрийте список виконань і відфільтруйте його за цим робочим процесом. Наявний запис із помилкою означає проблему в робочому процесі. Повна відсутність запису означає проблему з тригером. У такому разі перевірте чотири наведені вище причини.
Що змінити спочатку
- Перед редагуванням будь-якого файла прочитайте
STATUS,RestartCountіOOMKilledу власному контейнері. - Якщо контейнер не зупинявся, виправте заголовки для оновлення proxy-з’єднання та тайм-аут простою.
- Якщо
OOMKilledмає значення true, встановіть ліміт контейнера свідомо вибраного розміру, задайте максимальний розмір heap Node нижче за цей ліміт і перемкніть двійкові дані наfilesystem. - Якщо нічого не спрацювало, перевірте, чи workflow активний і чи відповідає часовий пояс інстансу вашому часовому поясу.
Більшість цих параметрів налаштовують один раз і надалі не змінюють, якщо базове встановлення вже працює. Якщо ви ще налаштовуєте це встановлення, інструкція з n8n у Docker через HTTPS є основою для цих параметрів.
FAQ
Чому редактор n8n показує повідомлення про втрату з’єднання, коли контейнер працює?
Редактор підтримує відкрите WebSocket-з’єднання для передавання даних про перебіг виконання. Якщо reverse proxy не передає заголовки Connection: Upgrade і Upgrade: websocket або не використовує HTTP/1.1 для upstream-з’єднання, оновлення з’єднання не завершується, і браузер безперервно підключається повторно, хоча n8n працює штатно. У nginx потрібен proxy_http_version 1.1 разом із двома директивами proxy_set_header, а також proxy_read_timeout, значення якого перевищує стандартні 60 секунд, щоб неактивна вкладка не втрачала з’єднання. Перевіряйте активну конфігурацію за допомогою sudo nginx -T, а не файл, який ви редагували.
Як відрізнити завершення процесу через нестачу пам’яті від звичайного аварійного завершення?
Виконайте docker inspect n8n | grep -iE 'OOMKilled|ExitCode|RestartCount' і перегляньте прапорець OOMKilled. Значення True означає, що kernel завершив процес через перевищення ліміту пам’яті. У журналі контейнера не буде корисних даних, оскільки процес не встиг записати їх. Значення False разом із помилкою heap і stack trace наприкінці docker logs означає, що Node.js досяг власного ліміту V8 heap і завершився самостійно. Задайте NODE_OPTIONS=--max-old-space-size нижче за ліміт контейнера, щоб отримати другий тип помилки, який залишає діагностичні дані.
Чи звільняє очищення даних виконань дисковий простір одразу?
Ні. EXECUTIONS_DATA_PRUNE позначає старі виконання для видалення, а наступний прохід видаляє їх за розкладом, заданим у EXECUTIONS_DATA_PRUNE_HARD_DELETE_INTERVAL. У SQLite файл також повторно використовує звільнені сторінки, а не повертає їх файловій системі, тому його розмір на диску певний час не змінюється після видалення рядків. Задайте EXECUTIONS_DATA_MAX_AGE і EXECUTIONS_DATA_PRUNE_MAX_COUNT відповідно до параметрів вашого сервера, а потім перевірте результат наступного дня, а не одразу.
Чому запланований workflow не виконався, коли n8n перезапускався?
n8n реєструє тригери під час запуску процесу й не відтворює розклади, час виконання яких настав, поки процес був зупинений. Тому цикл перезапусків призводить до відсутності запусків, а не до серії накопичених запусків. Наступне виконання відбудеться в найближчий запланований час після запуску. Якщо виконання не можна пропускати, запускайте workflow із зовнішнього клієнта через webhook, щоб логіка повторних спроб працювала за межами n8n.
Чи перезапустить healthcheck n8n, якщо він перестане відповідати?
Ні, не самостійно. Healthcheck у Compose лише позначає контейнер як справний або несправний. Перезапуск виконує restart policy, тому саме restart: unless-stopped повертає контейнер до роботи після його завершення. Вона також запускає контейнер після перезавантаження хоста, якщо сервіс Docker увімкнено. Перевірте це за допомогою sudo systemctl is-enabled docker. Щоб реагувати саме на статус unhealthy, потрібен зовнішній щодо Docker watcher, який читає статус і перезапускає сервіс.