vm:chatwoot:03-backup

Это старая версия документа!


Резервное копирование Chatwoot

Автоматизированный скрипт для создания резервных копий Chatwoot с поддержкой:

  • Дампов базы данных PostgreSQL
  • Дампов Redis
  • Архивирования файлов storage, данных БД и Redis
  • Автоматической очистки старых бекапов
  • Мониторинга дискового пространства
  • Уведомлений в Telegram
  • Docker и Docker Compose
  • Bash 4.0+
  • Утилиты: tar, gzip, find, curl
  • Права root или sudo
# Создаем необходимые директории
sudo mkdir -p /opt/scripts
sudo mkdir -p /opt/backups/chatwoot
 
# Устанавливаем права доступа
sudo chmod 755 /opt/scripts
sudo chmod 755 /opt/backups
sudo nano /opt/scripts/chatwoot-backup.sh

Скопируйте в файл следующий скрипт:

#!/bin/bash
 
# Скрипт резервного копирования Chatwoot
# Запуск: /opt/scripts/chatwoot-backup.sh
 
# Настройки
COMPOSE_FILE="/opt/chatwoot/chatwoot_dock/docker-compose.yml"
CHATWOOT_DIR="/opt/chatwoot/chatwoot_dock"
BACKUP_DIR="/opt/backups/chatwoot"
DATE=$(date +"%Y%m%d_%H%M%S")
BACKUP_NAME="chatwoot_backup_${DATE}"
RETENTION_DAYS=10  # Храним бекапы 10 дней
 
# Настройки базы данных
DB_CONTAINER="chatwoot_postgres"
DB_USER="postgres"
DB_PASSWORD="ваш_пароль_postgresql"
DB_NAME="chatwoot_production"
 
# Настройки Redis
REDIS_CONTAINER="chatwoot_redis"
REDIS_PASSWORD="ваш_пароль_redis"
 
# Логирование
LOG_FILE="${BACKUP_DIR}/backup.log"
 
# Функция логирования
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
 
# Создаем директорию для бекапов если не существует
mkdir -p "$BACKUP_DIR"
 
log "=== Начало резервного копирования Chatwoot ==="
 
# Проверяем что compose файл существует
if [ ! -f "$COMPOSE_FILE" ]; then
    log "ОШИБКА: Файл $COMPOSE_FILE не найден!"
    exit 1
fi
 
# Переходим в директорию с Chatwoot
cd "$CHATWOOT_DIR" || {
    log "ОШИБКА: Не удалось перейти в директорию $CHATWOOT_DIR"
    exit 1
}
# Проверяем что контейнеры запущены
log "Проверяем статус контейнеров..."
if ! docker-compose -f "$COMPOSE_FILE" ps | grep -q "Up"; then
    log "ОШИБКА: Контейнеры не запущены! Запустите их перед созданием бекапа."
    exit 1
fi
# Создаем дамп базы данных (пока контейнеры работают)
log "Создаем дамп базы данных..."
DB_DUMP_PATH="${BACKUP_DIR}/${BACKUP_NAME}_database.sql"
# Экспортируем пароль для pg_dump
export PGPASSWORD="$DB_PASSWORD"
docker exec "$DB_CONTAINER" pg_dump -U "$DB_USER" -d "$DB_NAME" --no-password --verbose > "$DB_DUMP_PATH" 2>> "$LOG_FILE"
if [ $? -eq 0 ] && [ -s "$DB_DUMP_PATH" ]; then
    log "Дамп базы данных создан: $DB_DUMP_PATH"
 
    # Получаем размер дампа
    DB_DUMP_SIZE=$(du -h "$DB_DUMP_PATH" | cut -f1)
    log "Размер дампа БД: $DB_DUMP_SIZE"
else
    log "ОШИБКА: Не удалось создать дамп базы данных или файл пуст"
    rm -f "$DB_DUMP_PATH"
    exit 1
fi
 
# Создаем дамп Redis
log "Создаем дамп Redis..."
REDIS_DUMP_PATH="${BACKUP_DIR}/${BACKUP_NAME}_redis.rdb"
docker exec "$REDIS_CONTAINER" redis-cli -a "$REDIS_PASSWORD" --rdb "$REDIS_DUMP_PATH" 2>> "$LOG_FILE"
if [ $? -eq 0 ]; then
    # Копируем дамп из контейнера
    docker cp "$REDIS_CONTAINER:$REDIS_DUMP_PATH" "$REDIS_DUMP_PATH" 2>> "$LOG_FILE"
    if [ -f "$REDIS_DUMP_PATH" ]; then
        log "Дамп Redis создан: $REDIS_DUMP_PATH"
        REDIS_DUMP_SIZE=$(du -h "$REDIS_DUMP_PATH" | cut -f1)
        log "Размер дампа Redis: $REDIS_DUMP_SIZE"
    else
        log "ПРЕДУПРЕЖДЕНИЕ: Файл дампа Redis не найден"
        REDIS_DUMP_SIZE="0B"
    fi
else
    log "ПРЕДУПРЕЖДЕНИЕ: Не удалось создать дамп Redis"
    REDIS_DUMP_SIZE="0B"
fi
 
# Очищаем переменную окружения
unset PGPASSWORD
# Останавливаем контейнеры
log "Останавливаем контейнеры Chatwoot..."
docker-compose -f "$COMPOSE_FILE" down
 
if [ $? -eq 0 ]; then
    log "Контейнеры успешно остановлены"
else
    log "ОШИБКА: Не удалось остановить контейнеры"
    exit 1
fi
 
# Ждем пару секунд для полной остановки
sleep 5
 
# Создаем архив с данными (включая дампы БД и Redis)
log "Создаем архив данных..."
BACKUP_PATH="${BACKUP_DIR}/${BACKUP_NAME}.tar.gz"
 
tar -czf "$BACKUP_PATH" \
    --exclude='*.log' \
    --exclude='**/lost+found' \
    -C "$BACKUP_DIR" "${BACKUP_NAME}_database.sql" \
    $([ -f "$REDIS_DUMP_PATH" ] && echo "-C $BACKUP_DIR ${BACKUP_NAME}_redis.rdb") \
    -C "/opt/chatwoot/chatwoot_data" \
    postgres_data/ \
    redis_data/ \
    storage/ \
    -C "$CHATWOOT_DIR" \
    docker-compose.yml \
    .env
 
if [ $? -eq 0 ]; then
    log "Архив создан: $BACKUP_PATH"
 
    # Получаем размер архива
    BACKUP_SIZE=$(du -h "$BACKUP_PATH" | cut -f1)
    log "Размер архива: $BACKUP_SIZE"
 
    # Удаляем отдельные файлы дампов, так как они теперь в архиве
    rm -f "$DB_DUMP_PATH"
    [ -f "$REDIS_DUMP_PATH" ] && rm -f "$REDIS_DUMP_PATH"
    log "Отдельные файлы дампов удалены (включены в архив)"
else
    log "ОШИБКА: Не удалось создать архив"
 
    # Пытаемся запустить контейнеры даже при ошибке
    log "Запускаем контейнеры после ошибки..."
    docker-compose -f "$COMPOSE_FILE" up -d
    exit 1
fi
 
# Запускаем контейнеры обратно
log "Запускаем контейнеры Chatwoot..."
docker-compose -f "$COMPOSE_FILE" up -d
 
if [ $? -eq 0 ]; then
    log "Контейнеры успешно запущены"
else
    log "ОШИБКА: Не удалось запустить контейнеры"
    exit 1
fi
 
# Ждем запуска сервисов
sleep 15
 
# Проверяем что все контейнеры работают
log "Проверяем статус контейнеров..."
RUNNING_CONTAINERS=$(docker-compose -f "$COMPOSE_FILE" ps --services --filter "status=running" | wc -l)
TOTAL_CONTAINERS=$(docker-compose -f "$COMPOSE_FILE" ps --services | wc -l)
if [ "$RUNNING_CONTAINERS" -eq "$TOTAL_CONTAINERS" ]; then
    log "Все контейнеры ($RUNNING_CONTAINERS/$TOTAL_CONTAINERS) работают корректно"
else
    log "ПРЕДУПРЕЖДЕНИЕ: Работают только $RUNNING_CONTAINERS из $TOTAL_CONTAINERS контейнеров"
fi
# Проверяем доступность базы данных
log "Проверяем подключение к базе данных..."
export PGPASSWORD="$DB_PASSWORD"
if docker exec "$DB_CONTAINER" pg_isready -U "$DB_USER" -d "$DB_NAME" > /dev/null 2>&1; then
    log "База данных доступна и готова к работе"
else
    log "ПРЕДУПРЕЖДЕНИЕ: База данных может быть недоступна"
fi
 
# Проверяем что база данных Chatwoot содержит нужные таблицы
log "Проверяем структуру базы данных Chatwoot..."
if docker exec "$DB_CONTAINER" psql -U "$DB_USER" -d "$DB_NAME" -c "\dt" 2>/dev/null | grep -q "accounts\|users\|conversations"; then
    log "База данных Chatwoot содержит основные таблицы"
else
    log "ПРЕДУПРЕЖДЕНИЕ: База данных Chatwoot может быть неполной"
fi
 
# Проверяем Redis контейнер
log "Проверяем Redis..."
if docker exec "$REDIS_CONTAINER" redis-cli -a "$REDIS_PASSWORD" ping 2>/dev/null | grep -q "PONG"; then
    log "Redis работает корректно"
else
    log "ПРЕДУПРЕЖДЕНИЕ: Redis может работать некорректно"
fi
 
# Проверяем Rails контейнер
log "Проверяем Rails приложение..."
if docker exec chatwoot_rails bundle exec rails runner "puts 'Chatwoot OK'" 2>/dev/null | grep -q "Chatwoot OK"; then
    log "Rails приложение работает корректно"
else
    log "ПРЕДУПРЕЖДЕНИЕ: Rails приложение может работать некорректно"
fi
 
unset PGPASSWORD
 
# Удаляем старые бекапы
log "Удаляем бекапы старше $RETENTION_DAYS дней..."
DELETED_COUNT=$(find "$BACKUP_DIR" -name "chatwoot_backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete -print | wc -l)
log "Удалено старых бекапов: $DELETED_COUNT"
 
# Показываем статистику бекапов
BACKUP_COUNT=$(ls -1 "${BACKUP_DIR}"/chatwoot_backup_*.tar.gz 2>/dev/null | wc -l)
TOTAL_SIZE=$(du -sh "${BACKUP_DIR}" 2>/dev/null | cut -f1)
log "Общее количество бекапов: $BACKUP_COUNT"
log "Общий размер папки бекапов: $TOTAL_SIZE"
# Получаем информацию о свободном месте на диске
BACKUP_DISK_USAGE=$(df -h "$BACKUP_DIR" | awk 'NR==2 {print $4 " свободно из " $2 " (" $5 " занято)"}')
ROOT_DISK_USAGE=$(df -h / | awk 'NR==2 {print $4 " свободно из " $2 " (" $5 " занято)"}')
log "Свободное место на диске бекапов: $BACKUP_DISK_USAGE"
if [ "$BACKUP_DIR" != "/" ] && [ "$(df "$BACKUP_DIR" | awk 'NR==2 {print $1}')" != "$(df / | awk 'NR==2 {print $1}')" ]; then
    log "Свободное место на корневом диске: $ROOT_DISK_USAGE"
fi
# Получаем процент заполнения диска с бекапами для предупреждений
BACKUP_DISK_PERCENT=$(df "$BACKUP_DIR" | awk 'NR==2 {print $5}' | sed 's/%//')
if [ "$BACKUP_DISK_PERCENT" -gt 90 ]; then
    log "⚠️ ПРЕДУПРЕЖДЕНИЕ: Диск заполнен более чем на 90%!"
elif [ "$BACKUP_DISK_PERCENT" -gt 80 ]; then
    log "⚠️ ВНИМАНИЕ: Диск заполнен более чем на 80%"
fi
 
log "=== Резервное копирование завершено успешно ==="
# Формируем сообщение для Telegram
TELEGRAM_MESSAGE="✅ Chatwoot backup completed
📁 Backup: $BACKUP_NAME ($BACKUP_SIZE)
💾 DB dump: $DB_DUMP_SIZE
🗄️ Redis dump: $REDIS_DUMP_SIZE
📊 Total backups: $BACKUP_COUNT
💿 Disk space: $BACKUP_DISK_USAGE"
# Добавляем предупреждение о месте, если нужно
if [ "$BACKUP_DISK_PERCENT" -gt 90 ]; then
    TELEGRAM_MESSAGE="$TELEGRAM_MESSAGE
⚠️ WARNING: Disk >90% full!"
elif [ "$BACKUP_DISK_PERCENT" -gt 80 ]; then
    TELEGRAM_MESSAGE="$TELEGRAM_MESSAGE
⚠️ ATTENTION: Disk >80% full"
fi
# Отправляем уведомление в Telegram (опционально)
curl -s -X POST "https://api.telegram.org/bot[ВАШ_ТОКЕН]/sendMessage" \
     -d chat_id="[ВАШ_CHAT_ID]" \
     -d text="$TELEGRAM_MESSAGE" > /dev/null
exit 0

Обязательно измените следующие параметры:

  • DB_PASSWORD=«ваш_пароль_postgresql» - пароль PostgreSQL
  • REDIS_PASSWORD=«ваш_пароль_redis» - пароль Redis
  • DB_NAME=«chatwoot_production» - убедитесь, что указано правильное имя БД (обычно chatwoot_production для production окружения)
  • [ВАШ_ТОКЕН] - токен Telegram бота
  • [ВАШ_CHAT_ID] - ID чата для уведомлений
sudo chmod +x /opt/scripts/chatwoot-backup.sh

<WRAP tip> Важно: Убедитесь в правильном имени базы данных в вашей установке: </WRAP>

# Проверяем список баз данных
docker exec chatwoot_postgres psql -U postgres -l
 
# Если база называется по-другому, измените переменную DB_NAME в скрипте

1. Создайте бота через @BotFather 2. Получите токен бота и chat_id 3. Замените в скрипте соответствующие плейсхолдеры

# Редактируем crontab
sudo crontab -e
 
# Добавляем задание - ежедневно в 4:00  
0 4 * * * /opt/scripts/chatwoot-backup.sh >> /var/log/chatwoot-backup.log 2>&1
sudo /opt/scripts/chatwoot-backup.sh
# Список бекапов
ls -la /opt/backups/chatwoot/
 
# Просмотр лога
tail -f /opt/backups/chatwoot/backup.log
/opt/backups/chatwoot/
├── chatwoot_backup_20250830_201456.tar.gz   # Основной архив
├── backup.log                               # Лог операций
└── [старые бекапы...]

Содержимое архива:

  • chatwoot_backup_YYYYMMDD_HHMMSS_database.sql - дамп PostgreSQL
  • chatwoot_backup_YYYYMMDD_HHMMSS_redis.rdb - дамп Redis
  • postgres_data/ - данные PostgreSQL
  • redis_data/ - данные Redis
  • storage/ - файлы storage Chatwoot
  • docker-compose.yml - конфигурация Docker
  • .env - переменные окружения
# Останавливаем сервисы
cd /opt/chatwoot/chatwoot_dock
docker-compose down
 
# Создаем бекап текущего состояния
sudo mv /opt/chatwoot/chatwoot_data /opt/chatwoot/chatwoot_data.backup.$(date +%Y%m%d_%H%M%S)
 
# Создаем новую директорию данных
sudo mkdir -p /opt/chatwoot/chatwoot_data
 
# Извлекаем архив
sudo tar -xzf /opt/backups/chatwoot/chatwoot_backup_YYYYMMDD_HHMMSS.tar.gz -C /
 
# Запускаем сервисы
docker-compose up -d
# Извлекаем SQL дамп
tar -xzf backup.tar.gz chatwoot_backup_YYYYMMDD_HHMMSS_database.sql
 
# Восстанавливаем в контейнер
docker exec -i chatwoot_postgres psql -U postgres -d chatwoot < chatwoot_backup_YYYYMMDD_HHMMSS_database.sql

При успешном бекапе приходит уведомление:

✅ Chatwoot backup completed
📁 Backup: chatwoot_backup_20250830_201456 (125M)
💾 DB dump: 45M
🗄️ Redis dump: 8M
📊 Total backups: 7
💿 Disk space: 2.1G свободно из 10G (79% занято)

Предупреждения при заполнении диска:

⚠️ ATTENTION: Disk >80% full
⚠️ WARNING: Disk >90% full!

Контейнеры не запущены

cd /opt/chatwoot/chatwoot_dock
docker-compose ps
docker-compose up -d

Ошибка дампа БД

# Проверяем доступность БД
docker exec chatwoot_postgres pg_isready -U postgres
 
# Проверяем правильную базу данных
docker exec chatwoot_postgres psql -U postgres -d chatwoot_production -c "\dt"
 
# Проверяем логи
docker logs chatwoot_postgres

Ошибка дампа Redis

# Проверяем Redis
docker exec chatwoot_redis redis-cli -a [пароль] ping
 
# Проверяем логи
docker logs chatwoot_redis

Нет места на диске

# Проверяем использование
df -h /opt/backups
 
# Удаляем старые бекапы
find /opt/backups -name "*backup*.tar.gz" -mtime +5 -delete
# Устанавливаем правильные права
sudo chmod 700 /opt/scripts/chatwoot-backup.sh
sudo chown root:root /opt/scripts/chatwoot-backup.sh
 
# Защищаем директорию бекапов
sudo chmod 755 /opt/backups
sudo chown root:root /opt/backups

Документация обновлена: currentuser i/

  • vm/chatwoot/03-backup.1756578209.txt.gz
  • Последнее изменение: 2025/08/30 18:23
  • admin