Горячая копия сайта на другом сервере: дамп БД по ssh + rsync файлов + (опционально) развёртывание дампа. Запускается из cron.
mysqldump/pg_dump, каталога сайта и временного каталога на источнике; при RESTORE=yes — доступ к локальной БД.DB_DUMP=yes): дамп БД с gzip во временный файл. Если gzip на источнике нет, дамп делается без сжатия (см. REMOTE_COMPRESS). Пароль БД не передаётся в аргументах и не виден в ps..partial, проверка размера и gzip -t (несжатый дамп сжимается локально), затем переименование в <БД>_ГГГГ-ММ-ДД_ЧЧММСС.sql.gz. Временный дамп на источнике удаляется.KEEP_DUMPS последних дампов.--delete и исключениями).RESTORE=yes): заливка скачанного дампа в локальную БД.Порядок намеренно такой: сначала дамп, потом файлы. При любой ошибке скрипт останавливается, развёртывание не выполняется, уже скачанный дамп остаётся.
DB_DUMP='no' шаги с дампом, ротацией и развёртыванием пропускаются, переносятся только файлы.bash, ssh (OpenSSH), rsync; gzip — если делается дамп БДRESTORE=yes: клиент БД — mysql/mariadb или psqlSSH_AUTH=sshpass: пакет sshpass (для key и plain не нужен)sh и rsync (всегда)DB_DUMP=yes): mysqldump (или mariadb-dump) либо pg_dump; gzip желателен, но не обязателенREMOTE_TMP_DIR, по умолчанию /tmp) с местом под дамп (без gzip — под несжатый)cp site_sync.conf.example /etc/site_sync.conf
chmod 600 /etc/site_sync.conf
nano /etc/site_sync.conf # заполнить параметры
chmod +x site_sync.sh
./site_sync.sh -c /etc/site_sync.conf --check # проверка без изменений
./site_sync.sh -c /etc/site_sync.conf # первый боевой запуск
Без аргументов скрипт читает site_sync.conf из своего каталога. Конфиг можно передать флагом -c или первым позиционным аргументом.
SSH_HOST='example.com'
SSH_USER='deploy'
SSH_AUTH='key'
SSH_KEY='/root/.ssh/id_ed25519'
DB_DUMP='no'
REMOTE_SITE_DIR='/var/www/mysite'
LOCAL_SITE_DIR='/var/www/mysite'
RSYNC_DELETE='yes'
LOG_FILE='/var/log/site_sync_mysite.log'
Конфиг — обычный bash-файл (подключается через source). Значения с пробелами берите в одинарные кавычки. Полный пример с комментариями: site_sync.conf.example.
| Параметр | По умолчанию | Описание |
|---|---|---|
SSH_HOST, SSH_USER | — (обязательно) | Сервер-источник и пользователь |
SSH_PORT | 22 | Порт |
SSH_AUTH | key | key / plain / sshpass (см. ниже) |
SSH_KEY | пусто | Путь к приватному ключу (пусто = ключи по умолчанию) |
SSH_PASS | — | Пароль для plain |
SSH_PASS_FILE | — | Файл с паролем (1 строка) для sshpass |
SSH_STRICT_HOST_KEY | accept-new | accept-new / yes / no. accept-new требует OpenSSH 7.6+ |
SSH_KNOWN_HOSTS | пусто | Свой файл known_hosts |
SSH_CONNECT_TIMEOUT | 20 | Таймаут подключения, сек |
| Параметр | По умолчанию | Описание |
|---|---|---|
DB_DUMP | yes | no — дамп БД отключён, переносятся только файлы (сайты без БД). Параметры БД, LOCAL_BACKUP_DIR и RESTORE тогда не нужны (RESTORE игнорируется с предупреждением) |
REMOTE_DB_TYPE | mysql | mysql (MySQL/MariaDB) или pgsql |
REMOTE_DB_HOST | localhost | Хост БД, как он виден с источника |
REMOTE_DB_PORT | 3306 / 5432 | Порт |
REMOTE_DB_NAME, REMOTE_DB_USER | — (обязательно при DB_DUMP=yes) | Допустимы только A-Z a-z 0-9 _ . -, не должны начинаться с - |
REMOTE_DB_PASS | пусто | Пароль БД |
REMOTE_DUMP_OPTS | mysql: --single-transaction --routines --triggers --eventspgsql: --no-owner --no-privileges | Параметры дампа |
REMOTE_DUMP_BIN | mysqldump / pg_dump | Например mariadb-dump для MariaDB 11+ |
REMOTE_COMPRESS | auto | auto — сжимать gzip на источнике, а если gzip там нет, делать дамп без сжатия (передача идёт с rsync -z, в .sql.gz дамп упаковывается на приёмнике). yes — требовать gzip на источнике, no — не сжимать на источнике |
REMOTE_TMP_DIR | /tmp | Куда на источнике класть временный дамп |
| Параметр | По умолчанию | Описание |
|---|---|---|
REMOTE_SITE_DIR | — (обязательно) | Каталог сайта на источнике, абсолютный путь, без пробелов |
LOCAL_SITE_DIR | — (обязательно) | Куда копировать у себя, абсолютный путь |
RSYNC_DELETE | no | yes — удалять локально файлы, которых нет на источнике |
RSYNC_EXCLUDES | пусто | Массив исключений: ('cache/' '*.log') |
RSYNC_OPTS | -az | Базовые опции rsync |
RSYNC_TIMEOUT | 600 | Таймаут ввода-вывода rsync, сек |
RETRY_COUNT / RETRY_DELAY | 3 / 30 | Число попыток и пауза (сек) при сбоях rsync |
LOCAL_BACKUP_DIR | — (обязательно при DB_DUMP=yes) | Каталог для дампов; не должен совпадать с LOCAL_SITE_DIR |
KEEP_DUMPS | 7 | Сколько последних дампов хранить (0 — все) |
LOG_FILE | пусто | Если задан — весь вывод в файл, ошибки дублируются в stderr |
| Параметр | По умолчанию | Описание |
|---|---|---|
RESTORE | no | yes — залить скачанный дамп в локальную БД |
LOCAL_DB_TYPE | как REMOTE_DB_TYPE | mysql / pgsql |
LOCAL_DB_HOST / LOCAL_DB_PORT | localhost / 3306 или 5432 | Адрес локальной БД |
LOCAL_DB_NAME | как REMOTE_DB_NAME | Целевая БД |
LOCAL_DB_USER, LOCAL_DB_PASS | — (user обязателен при RESTORE) | Доступ к локальной БД |
LOCAL_DB_RECREATE | no | yes — перед заливкой удалить и создать БД (mysql) / схему public (pgsql). При no таблицы из дампа перезаписываются, лишние остаются |
LOCAL_CLIENT_BIN | mysql / psql | Например mariadb |
LOCAL_RESTORE_OPTS | пусто | Доп. опции клиента |
ALLOW_RESTORE_TO_SOURCE | no | Снимает защиту от заливки в БД самого источника |
SSH_AUTH | Как работает | Что нужно |
|---|---|---|
key | ssh-ключ (SSH_KEY), без паролей. Рекомендуется для cron. | Ничего дополнительного |
plain | Пароль прямо в конфиге (SSH_PASS). Передаётся ssh через SSH_ASKPASS-помощник (временный файл с правами 700, удаляется при выходе). Пароля нет в аргументах процессов. | Ничего дополнительного |
sshpass | Пароль из отдельного файла SSH_PASS_FILE (chmod 600). | Пакет sshpass |
plain и sshpass обязательно chmod 600 на конфиг/файл пароля (скрипт предупредит о слишком широких правах).ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519 -N ''
ssh-copy-id -i /root/.ssh/id_ed25519.pub -p 22 deploy@example.com
# каждые 30 минут
*/30 * * * * /opt/site_sync/site_sync.sh /etc/site_sync.conf
# раз в сутки в 03:15
15 3 * * * /opt/site_sync/site_sync.sh /etc/site_sync.conf
Скрипт сам добавляет стандартные каталоги в PATH (в cron он обычно урезан). Если задан LOG_FILE, весь обычный вывод идёт в файл, а ошибки дополнительно уходят в stderr — cron пришлёт письмо (если настроен MAILTO). Одновременный запуск двух экземпляров блокируется.
LOCAL_BACKUP_DIR/.site_sync.lock с PID; устаревшая блокировка (процесса нет) снимается автоматически.mysqldump/pg_dump и gzip проверяются на источнике; локально — совпадение размера и gzip -t. Битый дамп не попадёт в хранилище и не вытеснит хорошие при ротации..partial удаляются при любом завершении, включая ошибки и сигналы.<БД>_ГГГГ-ММ-ДД_ЧЧММСС.sql.gz; остальное в каталоге не трогается.LOCAL_SITE_DIR=/ и системных каталогов (/etc, /usr, /var, $HOME и др.), запрет заливки в БД источника.REMOTE_COMPRESS=auto дамп создаётся без сжатия, передаётся с rsync -z и сжимается на приёмнике; в хранилище лежит обычный .sql.gz. Целостность проверяется кодом возврата дампа, размером и gzip -t.RESTORE=yes), свободное место под дамп и наличие нужных утилит на источнике проверяются до тяжёлых операций.--delete: файлы, попавшие под RSYNC_EXCLUDES, на приёмнике не удаляются.CREATE DATABASE IF NOT EXISTS, при наличии прав). Для PostgreSQL БД должна существовать заранее.plain) подбирается автоматически, если /tmp смонтирован с noexec.--single-transaction).| Код | Значение |
|---|---|
| 0 | Успех |
| 1 | Ошибка выполнения (ssh, дамп, rsync, развёртывание) |
| 2 | Ошибка конфига или аргументов |
| 3 | Уже запущен другой экземпляр |
--check, проверьте хост, порт, ключ, SSH_STRICT_HOST_KEY. Для проверки вручную: ssh -p PORT USER@HOST.REMOTE_DUMP_OPTS (для MySQL 8 нередко нужно добавить --no-tablespaces; MariaDB этой опции не знает).REMOTE_DUMP_BIN='mariadb-dump' и LOCAL_CLIENT_BIN='mariadb'.plain.LOCAL_BACKUP_DIR/.site_sync.lock/pid.LOG_FILE; при его отсутствии весь вывод идёт в stdout.