Как я потерял 4 дня данных в n8n Docker и восстановил систему: подробный опыт и советы

👁 45 IVOL

Введение

В ноябре 2025 года я столкнулся с критической потерей данных в продакшен-инстансе n8n, который работал в Docker, использовал SQLite и Redis в queue-режиме. За 4 дня все воркфлоу работали, проходили исполнения — но НИ ОДНА запись не попадала в базу. Классические бэкапы тоже оказались бесполезны — так как они снимались с уже "замороженной" базы.

В статье рассказываю:

  • как всё произошло,
  • как я нашёл причину,
  • какие уроки вынес,
  • что делать, чтобы у вас этого не случилось.

Хронология

1. Система:

  • n8n в Docker (bind-mount volume на SQLite файл)
  • Redis для очередей
  • Ежедневные бэкапы базы методом копирования файла с хоста в 01:30 ночи

2. Симптомы:

  • 7 ноября в 16:30 все остановилось; новых записей в базе нет, но воркфлоу продолжают исполняться.
  • n8n UI показывает старые данные, а в кроне идут успешные executions.
  • После обновления системы и docker force recreate никаких "потерь" не видно — workflows запускаются, но результат не появляется.
  • Проверка БД за каждый из "потерянных" дней: workflows не менялись, новых executions нет.

Причина

  1. Платформа: Docker + SQLite + WAL mode

    • SQLite работает в WAL-режиме (Write-Ahead Logging) и создает отдельные файлы *.wal, *.shm.
    • При работе с Docker bind mount (volume) может произойти lock corruption: БД считает что она пишет, но реально все записи "висят" в памяти контейнера (или в незакоммиченных журналах).
    • При рестарте/обновлении контейнера содержимое WAL-журнала теряется — диск остается как был, последние записи исчезают.
  2. n8n с Redis queue

    • При испольовании queue mode часть исполнительных данных хранится в Redis, а запись в SQLite может блокироваться при deadlock. Если checkpoint не проходит, все выполнения просто висят в оперативной памяти.
    • После перезапуска контейнера никакие данные не попадают на диск: они были только в памяти воркера!
  3. Backup копирует старый SQLite

    • Классический backup в 01:30 копировал файл, который уже был "заморожен" — новые данные так и не попадали в backup. Таким образом потеря подтвердилась по всем старым копиям.

Диагностика

  • Проверка workflow_entity в БД sqlite3 database.sqlite "SELECT id, name, updatedAt FROM workflow_entity;" показала затмение: последние обновления были 7 ноября.
  • Все ежедневные *.sqlite файлы, даже 11 ноября 01:30, содержали только старые данные.
  • Эксперименты с восстановлением и .recover показали corrupt базы — WAL плохо дружит с докером.

Решение

1. Срочно перейти на PostgreSQL

  • Использовать капитальный docker-compose.yml с отдельным postgres сервисом.
  • Настроить bind-mount volume данных для postgres (например, /www/wwwroot/n8n_ivol/postgres_ivol_data).
  • n8n полностью поддерживает миграцию с SQLite на PostgreSQL, делает всё автоматически при запуске (главное правильно прописать переменные). Ваши воркфлоу, executions, credentials переносятся.

2. Проверить, нет ли недописанных WAL-журналов, делать ручной checkpoint:

sqlite3 /path/to/database.sqlite "PRAGMA wal_checkpoint(TRUNCATE);"

(но это только частично спасает, если уже нет corrupt)

3. Перенос через .dump (если всё плохо):

sqlite3 old.sqlite ".dump" > /tmp/all_dump.sql
psql -h localhost -U n8n -d n8n < /tmp/all_dump.sql

Или через готовые экспорт/импорт решения.

4. Бэкапить не только файл БД, но и журнал (WAL+SHM) — и делать раз в час!


Рекомендации

  • НЕ используйте SQLite с production Docker!
  • Если нужен действительно надёжный production — только PostgreSQL.
  • Бэкапить базу с проверкой, что в журнале нет незакоммиченных данных.
  • Следить за логами n8n и искать "deadlock", "WAL checkpoint".
  • Для disaster recovery: минимум один cron-скрипт wal_checkpoint, минимум один pg_dump.

Тех, кому досталось это в реальном проде — не грустите, вы не одиноки! Это распространённая проблема среди self-hosted n8n.


**#n8n #docker #sqlite #postgresql #devops #selfhosted #data-loss #disaster-revery


Время чтения: 4 мин
Всего слов: 607
Обновлено: