Мониторинг

Бэкап базы данных с шаред-хостинга в S3 одним PHP-файлом

Большинство хостингов делает бэкапы «когда-нибудь и как-нибудь»: хранят они недолго, восстановить иногда можно только через поддержку, а если хостинг пропадёт вместе с аккаунтом, пропадут и копии. Надёжный вариант: самому регулярно выгружать базу в отдельное хранилище. Для этого я написал небольшой скрипт, который работает даже на самом простом хостинге.

Исходники: github.com/rasxod/bak_sql

Что умеет скрипт

Это один файл backup.php, который запускается по cron и делает четыре вещи:

  1. Снимает дамп базы MySQL/MariaDB (или PostgreSQL).
  2. Сжимает его в .sql.gz прямо на лету, без больших промежуточных файлов.
  3. Загружает архив в любое S3-совместимое хранилище: Yandex Object Storage, Selectel, AWS S3, MinIO, Wasabi и другие.
  4. Удаляет старые копии и оставляет только N последних, чтобы хранилище не пухло.

Установка не требует Composer и сторонних библиотек: подпись запросов к S3 реализована внутри файла.

Что нужно для работы

  • PHP 7.4+ с расширениями curl, simplexml и zlib
  • утилита mysqldump (или pg_dump) на сервере
  • бакет в S3-хранилище и пара ключей доступа
  • доступ к cron (на хостингах он обычно есть в панели управления)

Настройка за пять минут

1. Скачайте backup.php с GitHub и загрузите на хостинг **за пределы публичной папки сайта**, чтобы его нельзя было открыть из браузера. Он и так отказывается работать не из консоли, но пароли в публичной директории лучше не держать.

2. Откройте файл и заполните блок $config в начале: данные базы, endpoint, бакет и ключи хранилища, префикс («папку» в бакете) и keep_copies, то есть сколько копий хранить.

3. Проверьте, что всё работает:

php backup.php test

Режим test ничего не бэкапит, а проверяет окружение: наличие нужных расширений и mysqldump, подключение к базе, доступ к бакету и реальную запись, чтение и удаление тестового файла в хранилище. Если ключи неверны или нет прав на запись, вы узнаете об этом сразу, а не в день, когда понадобится восстановить базу.

4. Сделайте первый бэкап вручную:

php backup.php backup

5. Добавьте задание в cron, например каждую ночь в 3:00:

0 3 * * * /usr/bin/php /home/user/backup.php backup >> /home/user/backup-cron.log 2>&1

Путь к PHP на разных хостингах отличается, узнать его можно командой which php или в панели.

Как работает ротация

Копия удаляется только после того, как новая успешно загружена и ее размер в хранилище совпал с локальным. Если загрузка упала, старые бэкапы останутся нетронутыми. Ротация затрагивает только файлы *.sql.gz под вашим префиксом, поэтому для каждой базы используйте свой префикс.

Безопасность

  • Не храните ключи в файле, если не хотите: пароль БД и ключи S3 можно передать через переменные окружения (BACKUP_DB_PASSWORD, BACKUP_S3_ACCESS, BACKUP_S3_SECRET).
  • Пароль MySQL не попадает в список процессов: он передаётся через временный конфиг с правами 600.
  • Выдайте S3-ключу права только на нужный бакет, а пользователю БД только необходимые для дампа (SELECT, SHOW VIEW, TRIGGER, EVENT, LOCK TABLES).
  • Архив не шифруется. Если в базе чувствительные данные, включите шифрование на стороне бакета.

Ограничения

  • На некоторых шаред-хостингах отключены функции запуска внешних программ (exec, popen) или нет mysqldump. Тогда скрипт работать не будет, и php backup.php test покажет это сразу.
  • Архив загружается одним запросом, поэтому максимальный размер файла 5 ГБ. Для баз больше этого потребуется multipart-загрузка.
  • Бэкап, который ни разу не восстанавливали, нельзя считать надёжным. Раз в какое-то время скачивайте архив и разворачивайте его на тестовой базе:
gunzip -c db_2026-11-08_03-00-00.sql.gz | mysql -u user -p test_db

Итог

Один файл, один cron-вызов, копии в отдельном хранилище и автоматическая чистка старых. Скрипт открыт, берите, правьте под себя, а если найдёте баг или захотите функцию, пишите в issues на GitHub.

Комментарии 0

Оставить комментарий