Резервная копия PostgreSQL: скрипт pg_dump и проверка восстановления
Готовый скрипт дампа PostgreSQL, контрольная сумма и восстановление в отдельную базу. Проверенный опыт: три записи из копии и нетронутая рабочая база.

Резервная копия PostgreSQL полезна тогда, когда из неё действительно можно получить работающую базу. В этом руководстве сделаем логический дамп одной базы, проверим контрольную сумму, восстановим его в отдельную пустую базу и сравним данные. Рабочую базу при проверке не заменяем.
Проверено 29 октября 2026 года: Ubuntu 24.04.5, PostgreSQL 16.15, локальный кластер на порту 5432. Перед опытом в базе было три записи. После создания копии мы добавили четвёртую: восстановление вернуло три исходные записи, а исходная база сохранила все четыре.
Когда подходит pg_dump
Этот сценарий подходит небольшой или средней базе, для которой приемлемо восстановление из последнего логического дампа. pg_dump одной базы не сохраняет весь VPS, системные роли кластера, настройки PostgreSQL и файлы приложения. Для восстановления на точный момент времени между копиями нужна другая схема с физическими копиями и WAL.
Пример продолжает установку PostgreSQL: база hf_app, владелец hf_app, таблица lessons. Если у вас другое приложение, замените имена и заранее выберите собственные проверки данных. Не копируйте каталог работающего PostgreSQL обычным cp как замену штатному резервированию.
Скачать скрипт и проверить содержимое
Скачать hostfera-pg-backup-1.0.0.sh. Скрипт работает через sudo на сервере с локальным PostgreSQL и установленными pg_dump/pg_restore. Пароль он не запрашивает: запускает клиент от системного пользователя postgres через Unix-сокет. Это рассчитано на стандартную локальную аутентификацию Ubuntu.
curl --fail --show-error --location \
https://hostfera.ru/static/downloads/hostfera-pg-backup-1.0.0.sh \
--output hostfera-pg-backup-1.0.0.sh
sha256sum hostfera-pg-backup-1.0.0.sh
less hostfera-pg-backup-1.0.0.sh
SHA-256 версии 1.0.0:
6910855c038d98c2344168d2cfead05a23677990d9f5624f4739199d8f80dad1
Сначала прочитайте скрипт. Сверка с хешем на этой же странице помогает заметить повреждение или другую версию файла; она не заменяет независимую проверку происхождения. Не запускайте скачанное сразу через curl | sudo bash.
Полный код скрипта
#!/usr/bin/env bash
# Hostfera: custom-format dump of one local PostgreSQL database.
set -Eeuo pipefail
umask 077
[[ $EUID -eq 0 ]] || { echo 'Запустите через sudo bash.' >&2; exit 1; }
[[ $# -eq 1 && $1 =~ ^[a-z][a-z0-9_]{0,62}$ ]] || {
echo 'Использование: sudo bash hostfera-pg-backup-1.0.0.sh имя_базы' >&2; exit 1;
}
DB=$1
BASE=/var/backups/hostfera-postgresql
[[ ! -L $BASE ]] || { echo 'Каталог копий не должен быть символической ссылкой.' >&2; exit 1; }
if [[ -e $BASE ]]; then
[[ -d $BASE && $(stat -c %u "$BASE") == 0 ]] || { echo 'Проверьте владельца каталога копий.' >&2; exit 1; }
fi
command -v pg_dump >/dev/null
command -v pg_restore >/dev/null
id postgres >/dev/null
install -d -m 0700 -o root -g root "$BASE"
DIR=$(mktemp -d "$BASE/${DB}_$(date -u +%Y%m%dT%H%M%SZ)_XXXXXXXX")
trap 'rm -f -- "$DIR/database.dump.partial"' EXIT
runuser -u postgres -- pg_dump --host=/var/run/postgresql --port=5432 \
--format=custom --dbname="$DB" > "$DIR/database.dump.partial"
pg_restore --list < "$DIR/database.dump.partial" > "$DIR/contents.txt"
mv -- "$DIR/database.dump.partial" "$DIR/database.dump"
(cd "$DIR" && sha256sum database.dump > SHA256SUMS && sha256sum --check SHA256SUMS)
{
printf 'database=%s\ncreated_utc=%s\n' "$DB" "$(date -u +%FT%TZ)"
pg_dump --version
stat -c 'dump_bytes=%s' "$DIR/database.dump"
} > "$DIR/metadata.txt"
printf 'Резервная копия: %s\n' "$DIR"
printf 'Оглавление: %s/contents.txt\nПроверка SHA-256: успешно\n' "$DIR"
printf 'Теперь проверьте восстановление в отдельную пустую базу.\n'
Скрипт принимает одно простое имя базы: строчная латинская буква, затем буквы, цифры или подчёркивания, всего до 63 символов. Имена с пробелами, дефисами и кавычками эта версия намеренно не поддерживает. Сокет /var/run/postgresql и порт 5432 заданы явно. При другом порте или нестандартной аутентификации сначала адаптируйте и проверьте копию скрипта.
Создать копию и понять результат
pg_dump --version
sudo -u postgres psql -X -c 'SHOW server_version;'
sudo bash hostfera-pg-backup-1.0.0.sh hf_app
Для повторения проверенного сценария используйте клиентские утилиты той же основной версии, что и сервер. Старый pg_dump не подходит для более нового сервера; перенос между основными версиями требует отдельной проверки совместимости и расширений.
Копия появится в новом закрытом каталоге /var/backups/hostfera-postgresql/hf_app_.... Внутри — database.dump в custom-формате, contents.txt, SHA256SUMS и metadata.txt. При ошибке pg_dump незавершённый .partial удаляется, успешный database.dump не создаётся. Уже созданные копии скрипт не удаляет.
pg_restore --list читает оглавление архива, а SHA-256 позволяет обнаружить изменение байтов относительно сохранённой суммы. Обе проверки не заменяют восстановление: оглавление может читаться при проблеме с данными, а корректный хеш ничего не говорит о пригодности схемы для приложения.
Восстановить в новую пустую базу
Ниже команды для собственной доверенной копии. Замените путь на тот, который напечатал скрипт. Роль hf_app должна уже существовать. Имя hf_restorecheck зарезервируйте только для этой проверки.
sudo -i
BACKUP_DIR=/var/backups/hostfera-postgresql/ЗАМЕНИТЕ_НА_ВАШ_КАТАЛОГ
cd "$BACKUP_DIR"
sha256sum --check SHA256SUMS
sudo -u postgres createdb --template=template0 --owner=hf_app hf_restorecheck
sudo -u postgres pg_restore \
--dbname=hf_restorecheck \
--no-owner --no-privileges --role=hf_app \
--exit-on-error --single-transaction < database.dump
exit
Выполняйте команды последовательно и продолжайте только после успешного завершения каждой. Если createdb сообщает, что база уже существует, остановитесь и выберите другое новое имя. Не запускайте восстановление в существующую базу. Не добавляйте --clean и не подставляйте имя рабочей базы ради повторного опыта.
Перенаправление < database.dump выполняет root-оболочка: закрытый каталог копий не приходится открывать другим пользователям. Параметр --role=hf_app назначает создаваемые объекты роли приложения, а сохранённые владельцы и разрешения не переносятся. Такой упрощённый вариант подходит нашей базе с одним владельцем. Для нескольких ролей, расширений и сложных ACL заранее спроектируйте восстановление прав.
--exit-on-error --single-transaction прекращает восстановление при ошибке и откатывает изменения этой операции. Команда может потребовать заметного времени и ресурсов на большой базе; учебный пример не является замером скорости восстановления вашего проекта.
Проверить данные и приложение
sudo -u postgres psql -X -d hf_restorecheck \
-c 'SELECT id, title FROM lessons ORDER BY id;'
sudo -u postgres psql -X -d hf_app \
-c 'SELECT count(*) FROM lessons;'
На снимке — фактический результат нашего стенда: три записи из снимка в hf_restorecheck и четыре в исходной hf_app. В своём проекте проверьте не только число строк, но и критичные связи, несколько объектов и чтение данных приложением, подключённым именно к тестовой базе. Не направляйте туда рабочие платежи, письма и фоновые задания.
После проверки можно удалить только созданную для неё базу. Сначала сверьте имя и убедитесь, что тестовое приложение отключено:
sudo -u postgres dropdb --interactive hf_restorecheck
Где хранить копии и как автоматизировать
Каталог на том же VPS помогает при ошибке приложения, но не защищает от потери сервера. Нужна независимая копия, например в приватном объектном хранилище S3, со своими правами доступа и политикой хранения. Дамп содержит данные приложения: не кладите его в каталог сайта и не делайте бакет публичным.
Прежде чем добавлять расписание, добейтесь успешного ручного восстановления. Затем настройте отдельную службу и таймер по руководству о ежедневных копиях, заменив команду создания архива на этот скрипт. Установите скрипт в каталог, доступный для изменения только root. Контролируйте код завершения, возраст последней копии, свободное место и результат отправки во внешнее хранилище. Эта версия сама не ставит таймер, не отправляет файлы и не удаляет старые дампы.
Первоисточники
Сообщите адрес статьи и фрагмент через контакты редакции.

