Бэкап базы данных с шаред-хостинга в S3 одним PHP-файлом
Большинство хостингов делает бэкапы «когда-нибудь и как-нибудь»: хранят они недолго, восстановить иногда можно только через поддержку, а если хостинг пропадёт вместе с аккаунтом, пропадут и копии. Надёжный вариант: самому регулярно выгружать базу в отдельное хранилище. Для этого я написал небольшой скрипт, который работает даже на самом простом хостинге.
Исходники: github.com/rasxod/bak_sql
Что умеет скрипт
Это один файл backup.php, который запускается по cron и делает четыре вещи:
- Снимает дамп базы MySQL/MariaDB (или PostgreSQL).
- Сжимает его в
.sql.gzпрямо на лету, без больших промежуточных файлов. - Загружает архив в любое S3-совместимое хранилище: Yandex Object Storage, Selectel, AWS S3, MinIO, Wasabi и другие.
- Удаляет старые копии и оставляет только 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