#!/bin/bash # # Скрипт восстановления Gitea из бэкапа # Основан на рекомендациях: https://docs.gitea.com/administration/backup-and-restore # # Поддерживает: # - Архивы созданные через `gitea dump` # - Нативные дампы PostgreSQL # - Ручные бэкапы директорий # # База данных: PostgreSQL # Запускать в LXC контейнере ПОСЛЕ установки Gitea # set -e # ============================================ # НАСТРОЙКИ # ============================================ # Путь к архиву бэкапа BACKUP_ARCHIVE="${1:-}" # Новый домен/IP (оставьте пустым для автоопределения) NEW_DOMAIN="${NEW_DOMAIN:-$(hostname -I | awk '{print $1}')}" # Новый порт NEW_PORT="${NEW_PORT:-3000}" # Credentials для PostgreSQL DB_USER="${DB_USER:-gitea}" DB_NAME="${DB_NAME:-gitea}" DB_PASSWORD="${DB_PASSWORD:-gitea}" DB_HOST="${DB_HOST:-127.0.0.1}" # Пути Gitea (для нативной установки в LXC) # Согласно https://docs.gitea.com/administration/backup-and-restore#restore-command-restore GITEA_USER="git" GITEA_HOME="/home/git" GITEA_WORK_DIR="/var/lib/gitea" GITEA_CONFIG="/etc/gitea/app.ini" GITEA_CUSTOM="/var/lib/gitea/custom" GITEA_DATA="/var/lib/gitea/data" GITEA_REPOS="/var/lib/gitea/data/gitea-repositories" GITEA_LOG="/var/lib/gitea/log" GITEA_BIN="/usr/local/bin/gitea" # ============================================ # ФУНКЦИИ # ============================================ log() { echo -e "\033[1;32m[$(date '+%H:%M:%S')]\033[0m $1" } warn() { echo -e "\033[1;33m[WARNING]\033[0m $1" } error() { echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 exit 1 } # ============================================ # ПРОВЕРКИ # ============================================ if [ "$EUID" -ne 0 ]; then error "Запустите скрипт от root: sudo $0 /path/to/backup.tar.gz" fi if [ -z "$BACKUP_ARCHIVE" ]; then echo "Использование: $0 <путь_к_архиву_бэкапа>" echo "" echo "Примеры:" echo " $0 /tmp/gitea-backup-20240115-120000.tar.gz" echo "" echo "Переменные окружения:" echo " NEW_DOMAIN - новый домен/IP для Gitea (default: auto)" echo " NEW_PORT - HTTP порт (default: 3000)" echo " DB_USER - пользователь PostgreSQL (default: gitea)" echo " DB_PASSWORD - пароль PostgreSQL (default: gitea)" exit 1 fi if [ ! -f "$BACKUP_ARCHIVE" ]; then error "Файл бэкапа не найден: $BACKUP_ARCHIVE" fi # Установка необходимых утилит log "Проверка зависимостей..." if ! command -v unzip &> /dev/null; then log " Установка unzip..." apt-get update -qq && apt-get install -y -qq unzip fi log "==========================================" log " Восстановление Gitea из бэкапа" log "==========================================" log "" log "Архив: $BACKUP_ARCHIVE" log "Новый домен: $NEW_DOMAIN" log "Новый порт: $NEW_PORT" log "База данных: PostgreSQL ($DB_USER@$DB_NAME)" log "" # ============================================ # РАСПАКОВКА # ============================================ log "Распаковка архива..." TEMP_DIR=$(mktemp -d) cd "$TEMP_DIR" # Определяем тип архива и распаковываем case "$BACKUP_ARCHIVE" in *.tar.gz|*.tgz) tar -xzf "$BACKUP_ARCHIVE" ;; *.zip) unzip -q "$BACKUP_ARCHIVE" ;; *) tar -xf "$BACKUP_ARCHIVE" 2>/dev/null || unzip -q "$BACKUP_ARCHIVE" 2>/dev/null ;; esac # Находим директорию с данными BACKUP_DIR=$(find . -maxdepth 1 -type d -name "gitea-backup*" | head -1) if [ -z "$BACKUP_DIR" ] || [ "$BACKUP_DIR" = "." ]; then BACKUP_DIR="." fi log "Директория бэкапа: $BACKUP_DIR" log "Содержимое:" ls -la "$BACKUP_DIR" echo "" # ============================================ # ОСТАНОВКА GITEA # ============================================ log "Остановка Gitea..." systemctl stop gitea 2>/dev/null || true sleep 2 # ============================================ # ОПРЕДЕЛЕНИЕ ТИПА БЭКАПА # ============================================ log "Анализ бэкапа..." # Читаем информацию о версии if [ -f "$BACKUP_DIR/gitea-version.txt" ]; then OLD_VERSION=$(cat "$BACKUP_DIR/gitea-version.txt") log " Версия Gitea в бэкапе: $OLD_VERSION" fi # Проверяем наличие gitea dump архива GITEA_DUMP="" for ext in zip tar.gz; do if [ -f "$BACKUP_DIR/gitea-dump.$ext" ]; then GITEA_DUMP="$BACKUP_DIR/gitea-dump.$ext" break fi done # Или ищем по паттерну if [ -z "$GITEA_DUMP" ]; then GITEA_DUMP=$(find "$BACKUP_DIR" -name "gitea-dump-*.zip" -o -name "gitea-dump-*.tar.gz" 2>/dev/null | head -1) fi if [ -n "$GITEA_DUMP" ]; then log " Найден gitea dump: $(basename $GITEA_DUMP)" fi # Проверяем нативный дамп PostgreSQL NATIVE_DB_DUMP="" if [ -f "$BACKUP_DIR/gitea-db-native.sql" ]; then NATIVE_DB_DUMP="$BACKUP_DIR/gitea-db-native.sql" log " Найден нативный дамп PostgreSQL: gitea-db-native.sql" fi # ============================================ # ВОССТАНОВЛЕНИЕ POSTGRESQL # ============================================ log "Восстановление базы данных PostgreSQL..." if [ -n "$NATIVE_DB_DUMP" ]; then log " Восстановление из нативного дампа..." # Пересоздаём БД sudo -u postgres psql -c "DROP DATABASE IF EXISTS $DB_NAME;" 2>/dev/null || true sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" 2>/dev/null || \ sudo -u postgres psql -c "CREATE DATABASE $DB_NAME;" 2>/dev/null # Импортируем PGPASSWORD="$DB_PASSWORD" psql -U "$DB_USER" -h "$DB_HOST" -d "$DB_NAME" < "$NATIVE_DB_DUMP" log " ✓ PostgreSQL база восстановлена" else # Пробуем из gitea dump if [ -n "$GITEA_DUMP" ]; then DUMP_TEMP=$(mktemp -d) case "$GITEA_DUMP" in *.zip) unzip -q "$GITEA_DUMP" -d "$DUMP_TEMP" ;; *.tar.gz) tar -xzf "$GITEA_DUMP" -C "$DUMP_TEMP" ;; esac SQL_FILE=$(find "$DUMP_TEMP" -name "gitea-db.sql" 2>/dev/null | head -1) if [ -n "$SQL_FILE" ]; then warn " Используем дамп из gitea dump (рекомендуется нативный)" sudo -u postgres psql -c "DROP DATABASE IF EXISTS $DB_NAME;" 2>/dev/null || true sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" 2>/dev/null PGPASSWORD="$DB_PASSWORD" psql -U "$DB_USER" -h "$DB_HOST" -d "$DB_NAME" < "$SQL_FILE" log " ✓ PostgreSQL база восстановлена из gitea dump" else warn " SQL дамп не найден в бэкапе" fi else warn " Дамп базы данных не найден!" fi fi # ============================================ # ВОССТАНОВЛЕНИЕ ДАННЫХ ИЗ GITEA DUMP # Согласно: https://docs.gitea.com/administration/backup-and-restore#restore-command-restore # Структура gitea dump: # - app.ini (опционально) # - custom/ - кастомизации # - data/ - данные (attachments, avatars, lfs, indexers) # - repos/ - репозитории # - gitea-db.sql - дамп БД # - log/ - логи (не нужны для восстановления) # ============================================ if [ -n "$GITEA_DUMP" ]; then log "Восстановление данных из gitea dump..." # Убедимся что архив распакован if [ -z "$DUMP_TEMP" ]; then DUMP_TEMP=$(mktemp -d) case "$GITEA_DUMP" in *.zip) unzip -q "$GITEA_DUMP" -d "$DUMP_TEMP" ;; *.tar.gz) tar -xzf "$GITEA_DUMP" -C "$DUMP_TEMP" ;; esac fi log " Содержимое gitea dump:" ls -la "$DUMP_TEMP" echo "" # Создаём необходимые директории mkdir -p "$GITEA_DATA" "$GITEA_REPOS" "$GITEA_CUSTOM" "$GITEA_LOG" # 1. Репозитории: repos/ -> GITEA_REPOS if [ -d "$DUMP_TEMP/repos" ]; then log " → Репозитории (repos/ -> $GITEA_REPOS)..." cp -r "$DUMP_TEMP/repos/"* "$GITEA_REPOS/" 2>/dev/null || true log " Скопировано: $(ls -1 "$GITEA_REPOS" 2>/dev/null | wc -l) элементов" else warn " Директория repos/ не найдена в dump" fi # 2. Data директория: data/ -> GITEA_DATA if [ -d "$DUMP_TEMP/data" ]; then log " → Data директория (data/ -> $GITEA_DATA)..." for item in "$DUMP_TEMP/data/"*; do if [ -e "$item" ]; then item_name=$(basename "$item") if [ "$item_name" != "conf" ]; then cp -r "$item" "$GITEA_DATA/" 2>/dev/null || true fi fi done log " Скопировано в data/" fi # 3. Custom директория: custom/ -> GITEA_CUSTOM if [ -d "$DUMP_TEMP/custom" ]; then log " → Custom директория (custom/ -> $GITEA_CUSTOM)..." cp -r "$DUMP_TEMP/custom/"* "$GITEA_CUSTOM/" 2>/dev/null || true fi # 4. Логи: log/ -> GITEA_LOG (опционально) if [ -d "$DUMP_TEMP/log" ]; then log " → Логи (log/ -> $GITEA_LOG)..." cp -r "$DUMP_TEMP/log/"* "$GITEA_LOG/" 2>/dev/null || true fi # 5. LFS данные (если отдельно) if [ -d "$DUMP_TEMP/lfs" ]; then log " → LFS данные..." mkdir -p "$GITEA_DATA/lfs" cp -r "$DUMP_TEMP/lfs/"* "$GITEA_DATA/lfs/" 2>/dev/null || true fi log " ✓ Данные из gitea dump восстановлены" fi # ============================================ # ВОССТАНОВЛЕНИЕ ИЗ РУЧНОГО БЭКАПА (fallback) # ============================================ if [ -z "$GITEA_DUMP" ] && [ -d "$BACKUP_DIR/data" ]; then log "Восстановление из ручного бэкапа..." # Репозитории for repo_dir in "gitea-repositories" "git/repositories" "repositories"; do if [ -d "$BACKUP_DIR/data/$repo_dir" ]; then log " → Репозитории ($repo_dir)..." mkdir -p "$GITEA_REPOS" cp -r "$BACKUP_DIR/data/$repo_dir/"* "$GITEA_REPOS/" 2>/dev/null || true break fi done # Остальные данные for subdir in avatars attachments lfs packages; do if [ -d "$BACKUP_DIR/data/$subdir" ]; then log " → $subdir..." mkdir -p "$GITEA_DATA/$subdir" cp -r "$BACKUP_DIR/data/$subdir/"* "$GITEA_DATA/$subdir/" 2>/dev/null || true fi done fi # ============================================ # ВОССТАНОВЛЕНИЕ КОНФИГУРАЦИИ # ============================================ log "Восстановление конфигурации..." if [ -f "$BACKUP_DIR/app.ini" ]; then # Сохраняем бэкап текущего конфига if [ -f "$GITEA_CONFIG" ]; then cp "$GITEA_CONFIG" "$GITEA_CONFIG.new-install-backup" fi # Копируем конфиг из бэкапа cp "$BACKUP_DIR/app.ini" "$GITEA_CONFIG" log " ✓ app.ini восстановлен" fi # ============================================ # ОБНОВЛЕНИЕ КОНФИГУРАЦИИ ДЛЯ НОВОГО СЕРВЕРА # ============================================ log "Обновление конфигурации для нового сервера..." if [ -f "$GITEA_CONFIG" ]; then log " Исходный app.ini:" grep -E "^(DOMAIN|ROOT_URL|ROOT|WORK_PATH|RUN_USER|HOST)\s*=" "$GITEA_CONFIG" 2>/dev/null | head -10 || true echo "" # === [server] секция === sed -i "s|^DOMAIN\s*=.*|DOMAIN = $NEW_DOMAIN|" "$GITEA_CONFIG" sed -i "s|^SSH_DOMAIN\s*=.*|SSH_DOMAIN = $NEW_DOMAIN|" "$GITEA_CONFIG" sed -i "s|^ROOT_URL\s*=.*|ROOT_URL = http://$NEW_DOMAIN:$NEW_PORT/|" "$GITEA_CONFIG" sed -i "s|^HTTP_PORT\s*=.*|HTTP_PORT = $NEW_PORT|" "$GITEA_CONFIG" # === [repository] секция === sed -i "s|^ROOT\s*=.*/git/repositories.*|ROOT = $GITEA_REPOS|" "$GITEA_CONFIG" sed -i "s|^ROOT\s*=.*/data/git/repositories.*|ROOT = $GITEA_REPOS|" "$GITEA_CONFIG" sed -i "s|^ROOT\s*=.*/gitea-repositories.*|ROOT = $GITEA_REPOS|" "$GITEA_CONFIG" # === Глобальные пути === sed -i "s|^WORK_PATH\s*=.*/var/lib/gitea.*|WORK_PATH = $GITEA_WORK_DIR|" "$GITEA_CONFIG" sed -i "s|^WORK_PATH\s*=.*/data.*|WORK_PATH = $GITEA_WORK_DIR|" "$GITEA_CONFIG" sed -i "s|^WORK_PATH\s*=.*/app/gitea.*|WORK_PATH = $GITEA_WORK_DIR|" "$GITEA_CONFIG" # === [database] секция - PostgreSQL === sed -i "s|^HOST\s*=.*db:.*|HOST = $DB_HOST:5432|" "$GITEA_CONFIG" sed -i "s|^HOST\s*=.*gitea-db.*|HOST = $DB_HOST:5432|" "$GITEA_CONFIG" # === [log] секция === sed -i "s|^ROOT_PATH\s*=.*/log.*|ROOT_PATH = $GITEA_LOG|" "$GITEA_CONFIG" # === [server] LFS === sed -i "s|^LFS_CONTENT_PATH\s*=.*|LFS_CONTENT_PATH = $GITEA_DATA/lfs|" "$GITEA_CONFIG" # === [security] секция === sed -i "s|^INSTALL_LOCK\s*=.*|INSTALL_LOCK = true|" "$GITEA_CONFIG" # === Глобальные настройки === sed -i "s|^RUN_USER\s*=.*|RUN_USER = $GITEA_USER|" "$GITEA_CONFIG" log " Обновлённый app.ini:" grep -E "^(DOMAIN|ROOT_URL|ROOT|WORK_PATH|RUN_USER|HOST)\s*=" "$GITEA_CONFIG" 2>/dev/null | head -10 || true echo "" log " ✓ Конфигурация обновлена" log " Domain: $NEW_DOMAIN" log " Port: $NEW_PORT" log " Repos: $GITEA_REPOS" fi # ============================================ # ПРАВА ДОСТУПА # ============================================ log "Установка прав доступа..." chown -R $GITEA_USER:$GITEA_USER "$GITEA_WORK_DIR" chown -R $GITEA_USER:$GITEA_USER "$GITEA_HOME" 2>/dev/null || true chown root:$GITEA_USER "$GITEA_CONFIG" chmod 640 "$GITEA_CONFIG" chmod -R 750 "$GITEA_REPOS" 2>/dev/null || true log " ✓ Права установлены" # ============================================ # РЕГЕНЕРАЦИЯ SSH КЛЮЧЕЙ # ============================================ log "Регенерация SSH authorized_keys..." mkdir -p "$GITEA_HOME/.ssh" touch "$GITEA_HOME/.ssh/authorized_keys" chown -R $GITEA_USER:$GITEA_USER "$GITEA_HOME/.ssh" chmod 700 "$GITEA_HOME/.ssh" chmod 600 "$GITEA_HOME/.ssh/authorized_keys" sudo -u $GITEA_USER $GITEA_BIN admin regenerate keys -c "$GITEA_CONFIG" 2>/dev/null && \ log " ✓ SSH ключи регенерированы" || \ warn " Не удалось регенерировать SSH ключи (возможно нет пользователей с ключами)" # ============================================ # РЕГЕНЕРАЦИЯ GIT HOOKS (КРИТИЧНО!) # Согласно документации: ./gitea admin regenerate hooks # Без этого git push не будет работать! # ============================================ log "Регенерация Git hooks..." sudo -u $GITEA_USER $GITEA_BIN admin regenerate hooks -c "$GITEA_CONFIG" 2>/dev/null && \ log " ✓ Git hooks регенерированы" || \ warn " Не удалось регенерировать hooks (выполните вручную после запуска)" # ============================================ # ОЧИСТКА # ============================================ log "Очистка временных файлов..." rm -rf "$TEMP_DIR" [ -n "$DUMP_TEMP" ] && rm -rf "$DUMP_TEMP" # ============================================ # ЗАПУСК GITEA # ============================================ log "Запуск Gitea..." systemctl start gitea sleep 3 if systemctl is-active --quiet gitea; then log "✅ Gitea успешно запущена!" else warn "Gitea не запустилась автоматически" echo "" echo "Проверьте логи:" echo " journalctl -u gitea -e" echo " cat $GITEA_WORK_DIR/log/gitea.log" fi # ============================================ # ИТОГИ # ============================================ echo "" echo "==========================================" echo " ✅ Восстановление завершено!" echo "==========================================" echo "" echo " Gitea доступна: http://$NEW_DOMAIN:$NEW_PORT" echo "" echo " Конфигурация: $GITEA_CONFIG" echo " Данные: $GITEA_WORK_DIR" echo "" echo " Проверьте:" echo " ☐ Авторизация пользователей" echo " ☐ Список репозиториев" echo " ☐ Git clone/push операции" echo " ☐ Webhooks (если используются)" echo "" echo " Если есть проблемы, выполните:" echo " sudo -u git $GITEA_BIN doctor check --all --fix -c $GITEA_CONFIG" echo " sudo -u git $GITEA_BIN admin regenerate hooks -c $GITEA_CONFIG" echo "" echo " Логи: journalctl -u gitea -f" echo "" echo "=========================================="