Введение
В ноябре 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 нет.
Причина
-
Платформа: Docker + SQLite + WAL mode
- SQLite работает в WAL-режиме (Write-Ahead Logging) и создает отдельные файлы *.wal, *.shm.
- При работе с Docker bind mount (volume) может произойти lock corruption: БД считает что она пишет, но реально все записи "висят" в памяти контейнера (или в незакоммиченных журналах).
- При рестарте/обновлении контейнера содержимое WAL-журнала теряется — диск остается как был, последние записи исчезают.
-
n8n с Redis queue
- При испольовании queue mode часть исполнительных данных хранится в Redis, а запись в SQLite может блокироваться при deadlock. Если checkpoint не проходит, все выполнения просто висят в оперативной памяти.
- После перезапуска контейнера никакие данные не попадают на диск: они были только в памяти воркера!
-
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