Бэкапы базы PostgreSQL — npm run db:backup
Бэкап снимает дамп любой базы PostgreSQL — панели, базы ботов на Railway или на VPS — и кладёт его в хранилище. Восстановление проверяет дамп и после загрузки сверяет число строк в каждой таблице. Это же основа переезда базы между площадками: бэкап со старого места, восстановление на новом.
История версий проектов: после переноса снимков в S3 этот дамп содержит только метаданные и ключи объектов. Для полного восстановления истории сохраняйте также приватный бакет версий и сверяйте его с базой по инструкции Снимки версий проектов в S3. Не считайте проверку числа строк достаточной проверкой самих снимков.
Команды
# бэкап базы панели (DATABASE_URL)
npm run db:backup
# бэкап другой базы под своей меткой
npm run db:backup -- --url postgresql://... --label railway-tbb-bots
# список бэкапов метки
npm run db:backups -- --label railway-tbb-bots
# восстановление последнего бэкапа в пустую базу
npm run db:restore -- --url postgresql://... --label railway-tbb-bots
# конкретный бэкап; перезапись непустой базы
npm run db:restore -- --url postgresql://... --id 20261001-141147 --force
Общие флаги: --label (по умолчанию DB_BACKUP_LABEL или panel), --storage <id> (по умолчанию DB_BACKUPS_STORAGE_ID), --keep N для бэкапа.
Как устроено
- Дамп —
pg_dump --format=custom(сжатый) без владельцев и прав, чтобы восстанавливаться под любым пользователем. - Снимок. Дамп и подсчёт строк идут в одном снимке базы (
pg_export_snapshot), поэтому числа строк точно соответствуют дампу, даже если боты в это время пишут в базу. - Хранение:
db-backups/<метка>/<время UTC>.dump, рядомindex.jsonсо списком: размер, SHA-256, версия PostgreSQL, строки по таблицам. Список лежит в хранилище, а не в базе панели: бэкап можно найти и восстановить, даже если база панели потеряна. - Ротация: хранится
DB_BACKUPS_KEEPпоследних бэкапов на метку, старые удаляются. - Восстановление:
- Скачать дамп и сверить размер и SHA-256.
- Проверить целевую базу: она должна быть пустой, иначе нужен
--force(тогда её объекты пересоздаются). - Восстановить одной транзакцией: при ошибке база не меняется.
- Сверить число строк по каждой таблице. Расхождение даёт код выхода 2.
- Пароль передаётся утилитам через
PGPASSWORD, а не в аргументах: аргументы процесса видны черезps.
Хранилище
Те же поля задаются в админке, раздел «Бэкапы» (настройки рантайма). Пока значение не сохранено, читается переменная окружения. Сохранение раздела перезапускает планировщик без рестарта процесса.
DB_BACKUPS_STORAGE_ID — S3 из «Хранилищ» панели (storage_configs). Отдельное S3 можно добавить кнопкой «Подключить S3» в настройках бэкапов, затем сохранить выбранное хранилище. Создание не переключает хранилище обычных загрузок и не включает расписание. Проверка подключения не проверяет запись и приватность: права доступа и политику бакета нужно проверить у провайдера.
Без выбранного хранилища бэкапы идут в папку DB_BACKUPS_DIR (.db-backups/); в Docker её нужно монтировать постоянным томом, иначе дампы и индекс пропадут вместе с контейнером. Пустой выбор хранилища не выключает бэкапы: для отключения расписания установите интервал 0 и отдельно выключите доставку в Telegram, если она не нужна.
В дампе есть токены ботов и сессии userbot. Не используйте публичное local-default (uploads/) или хранилище с публичным базовым адресом (publicUrlBase, CDN). Отсутствие publicUrlBase само по себе не гарантирует приватность S3: убедитесь, что политика и права бакета запрещают публичное чтение. Бакет лучше держать не на той же машине, что и база.
Изменение общих конфигураций хранилищ доступно только администратору. Выбранное отдельное хранилище бэкапов нельзя указать для пользовательской загрузки файлов, если оно не настроено явно как общее хранилище загрузок. Эта проверка сравнивает ID конфигурации: не создавайте вторую общую конфигурацию для того же бакета.
Автоматический бэкап
DB_BACKUP_INTERVAL_HOURS=24 — следующая автоматическая копия создаётся не раньше чем через сутки после последней успешной копии в сохранённом индексе. Через пять минут после старта и далее каждые пять минут панель проверяет срок; перезапуск backend не создаёт новый дамп при свежей копии. Задержка после наступления срока может составлять до пяти минут при исправном хранилище и отсутствии выполняющегося бэкапа. Без успешных копий первая попытка выполняется после стартовой задержки.
Ручной бэкап работает как прежде и тоже обновляет срок следующей автоматической копии. Ошибка создания повторяется при следующей проверке. При ошибке чтения индекса новый дамп не запускается; ошибка пишется в журнал с префиксом [DbBackup:<метка>], после восстановления доступа срок проверяется снова. Это не останавливает панель.
Срок определяется отдельно для каждой метки в выбранном хранилище. При смене базы за той же меткой задайте новую метку либо создайте ручной бэкап: индекс не различает источники с одинаковой меткой. Хранилище индекса должно сохраняться между деплоями. Блокировка одновременных запусков действует внутри одного процесса; распределённая блокировка между несколькими репликами не добавлена.
Другие базы добавляются в то же расписание через DB_BACKUP_TARGETS: пары метка=адрес, разделённые пробелом, переводом строки или ;. Базы бэкапятся по очереди, сбой одной не мешает остальным.
DB_BACKUP_INTERVAL_HOURS=1
DB_BACKUPS_KEEP=48
DB_BACKUP_TARGETS=railway-tbb-bots=postgresql://postgres:...@mainline.proxy.rlwy.net:53922/railway
Базу ботов на Railway панель достаёт через TCP Proxy сервиса Postgres, поэтому нужен внешний адрес, а не postgres.railway.internal. Храните бэкапы вне Railway (папка на сервере панели или S3 у другого провайдера): если аккаунт Railway ограничат, база и бэкапы не пропадут вместе.
Если бэкап не удался, а последний удачный старше двух интервалов (или бэкапов ещё нет), в журнал пишется ⚠️ [DbBackup:<метка>].
Доставка в Telegram
В админке «Бэкапы» доступны переключатель «Отправлять в Telegram», секретное поле «Токен бота Telegram» и «Chat ID Telegram». Создайте бота через BotFather и добавьте его в закрытую группу либо начните личную переписку с ним. Сохраните реквизиты, затем нажмите «Проверить Telegram»: придёт небольшой проверочный файл без данных базы. Кнопка использует сохранённые настройки и недоступна при несохранённых изменениях.
Переменные окружения: DB_BACKUP_TELEGRAM_ENABLED=true, DB_BACKUP_TELEGRAM_BOT_TOKEN, DB_BACKUP_TELEGRAM_CHAT_ID. Настройки админки имеют приоритет над окружением. Токен не возвращается в форме; пустой ввод сохраняет прежний секрет. Проверка отправки работает и при выключенной автоматической доставке.
После ручного или автоматического бэкапа каждой базы дамп сначала сохраняется в выбранном приватном хранилище вместе с индексом, затем отправляется в Telegram отдельным документом с меткой базы и датой. Лимит обычного Telegram Bot API — 50 МБ, ожидание отправки ограничено двумя минутами. Ошибка или превышение размера не отменяют сохранённый бэкап: предупреждение появляется в журнале, а при ручном запуске — также в ответе API и уведомлении формы. Ротация хранилища не удаляет сообщения из Telegram.
Дамп содержит токены и сессии: используйте личный чат или закрытую группу с нужными участниками. Доставка дополняет S3 или локальную папку. Endpoint проверки: POST /admin/api/runtime-settings/backups/telegram/test, доступен только с admin-сессией.
Версии PostgreSQL
pg_dumpне снимает сервер новее себя, поэтому берётся самая свежая установленная версия:PG_BIN_DIR,/usr/lib/postgresql/<N>/bin(Debian, Ubuntu),/usr/libexec/postgresql<N>(Alpine) или PATH. В образ панели ставитсяpostgresql18-client.- Восстановление в сервер старше исходного (например, дамп с 18 в 16) запрещено: PostgreSQL такой переход не поддерживает, схема может не встать. На новой площадке нужна та же версия или новее.
- Если целевой сервер старше утилит (дамп с 16 через
pg_restore18 в 16), дамп разворачивается в SQL, из него убираются неизвестные серверу настройки сессии (transaction_timeout), и скрипт выполняется черезpsqlодной транзакцией.
Проверено
- База панели (PostgreSQL 16, 34 таблицы) — бэкап в S3 на Railway, восстановление в пустую базу, числа строк совпали. Повторное восстановление без
--forceотклонено, с--forceпрошло. - База ботов на Railway (PostgreSQL 18, 33 таблицы, бот в это время работал) — восстановлена в PostgreSQL 18 на другой машине, числа строк совпали. В PostgreSQL 16 восстановление отклонено с понятной ошибкой.
- Расписание с
DB_BACKUP_TARGETS: за один проход сняты база панели (PostgreSQL 16, 34 таблицы) и база ботовtbb-botsна Railway (PostgreSQL 18.6, 33 таблицы); бэкап базы ботов восстановлен в чистый PostgreSQL 18 в Docker, числа строк совпали. --keep 2при трёх бэкапах — остались два последних.- Испорченный дамп отклонён по SHA-256, целевая база не тронута.
Ограничения
- При создании дамп записывается во временный файл; загрузка в S3 выполняется частями. Для этого нужен свободный локальный диск. При восстановлении сжатый дамп по-прежнему читается целиком в память; для больших баз нужен запас RAM.
- Роли и настройки сервера не переносятся — только объекты базы и данные. Расширения попадают в дамп командой
CREATE EXTENSION, но должны быть установлены на целевом сервере. - Встроенные бэкапы Railway (снимки тома, восстановление на момент времени) — отдельная настройка в Railway, этот инструмент их не заменяет и не включает.