From 12f57baa26487408ea58792948612121c950f9f1 Mon Sep 17 00:00:00 2001 From: tactile Date: Tue, 6 Jan 2026 22:12:07 +0500 Subject: [PATCH] init --- BACKUP_README.md | 143 +++++ MIGRATION_GUIDE.md | 205 ++++++++ MIGRATION_README.md | 60 +++ backup-scripts/backup-gitea-lxc.sh | 240 +++++++++ backup-scripts/backup-proxmox.sh | 207 ++++++++ backup-scripts/restore-gitea.sh | 494 ++++++++++++++++++ backup-scripts/setup-backup-cron.sh | 60 +++ .../backup-gitea-for-migration.sh | 383 ++++++++++++++ migration-scripts/full-migration.sh | 363 +++++++++++++ migration-scripts/install-gitea-lxc.sh | 260 +++++++++ migration-scripts/lxc/create-lxc.sh | 159 ++++++ migration-scripts/restore-gitea.sh | 494 ++++++++++++++++++ migration-scripts/systemd/gitea.service | 42 ++ 13 files changed, 3110 insertions(+) create mode 100644 BACKUP_README.md create mode 100644 MIGRATION_GUIDE.md create mode 100644 MIGRATION_README.md create mode 100755 backup-scripts/backup-gitea-lxc.sh create mode 100755 backup-scripts/backup-proxmox.sh create mode 100755 backup-scripts/restore-gitea.sh create mode 100755 backup-scripts/setup-backup-cron.sh create mode 100755 migration-scripts/backup-gitea-for-migration.sh create mode 100755 migration-scripts/full-migration.sh create mode 100755 migration-scripts/install-gitea-lxc.sh create mode 100755 migration-scripts/lxc/create-lxc.sh create mode 100755 migration-scripts/restore-gitea.sh create mode 100644 migration-scripts/systemd/gitea.service diff --git a/BACKUP_README.md b/BACKUP_README.md new file mode 100644 index 0000000..dfa2ce4 --- /dev/null +++ b/BACKUP_README.md @@ -0,0 +1,143 @@ +# Бэкап и восстановление Gitea + +Скрипты для бэкапа и восстановления Gitea в LXC контейнере на Proxmox. + +## Файлы + +| Скрипт | Где запускать | Описание | +|--------|---------------|----------| +| `backup-gitea-lxc.sh` | Внутри LXC | Бэкап на уровне приложения | +| `backup-proxmox.sh` | На Proxmox хосте | Оркестрация бэкапа + vzdump | +| `setup-backup-cron.sh` | На Proxmox хосте | Настройка автоматического бэкапа | +| `restore-gitea.sh` | Внутри LXC | Восстановление из бэкапа | + +## backup-gitea-lxc.sh + +Запускается внутри LXC контейнера. Создаёт: +- `database.sql` — pg_dump базы PostgreSQL +- `gitea-dump.zip` — репозитории, LFS, attachments, avatars +- `app.ini` — конфигурация Gitea + +Настройки: + +| Переменная | По умолчанию | Описание | +|------------|--------------|----------| +| `BACKUP_BASE` | `/var/backups/gitea` | Директория для бэкапов | +| `DB_USER` | `gitea` | Пользователь PostgreSQL | +| `DB_NAME` | `gitea` | Имя базы данных | +| `KEEP_BACKUPS` | `7` | Сколько бэкапов хранить | +| `REMOTE_BACKUP` | — | scp путь для копирования | + +Пример: + +```bash +sudo ./backup-gitea-lxc.sh + +KEEP_BACKUPS=14 REMOTE_BACKUP=user@nas:/backups ./backup-gitea-lxc.sh +``` + +## backup-proxmox.sh + +Запускается на Proxmox хосте. Выполняет: +1. Запуск `backup-gitea-lxc.sh` внутри контейнера +2. Копирование архива из LXC на Proxmox хост +3. Создание vzdump контейнера (если `DO_VZDUMP=true`) +4. Ротация старых бэкапов + +Настройки: + +| Переменная | По умолчанию | Описание | +|------------|--------------|----------| +| `LXC_ID` | `300` | ID контейнера Gitea | +| `BACKUP_STORAGE` | `/var/lib/vz/dump` | Где хранить бэкапы | +| `DO_VZDUMP` | `false` | Делать полный бэкап контейнера | +| `VZDUMP_COMPRESS` | `zstd` | Сжатие vzdump | +| `KEEP_BACKUPS` | `7` | Сколько gitea бэкапов хранить | +| `KEEP_VZDUMP` | `3` | Сколько vzdump хранить | +| `REMOTE_BACKUP` | — | scp путь для копирования | + +Пример: + +```bash +LXC_ID=300 ./backup-proxmox.sh + +LXC_ID=300 DO_VZDUMP=true ./backup-proxmox.sh +``` + +## setup-backup-cron.sh + +Настраивает автоматический бэкап через cron. + +| Переменная | По умолчанию | Описание | +|------------|--------------|----------| +| `LXC_ID` | `300` | ID контейнера | +| `BACKUP_TIME` | `12:00` | Время ежедневного бэкапа | + +Расписание: +- Ежедневно в указанное время: gitea dump + pg_dump +- Воскресенье в 13:00: + полный vzdump контейнера + +Пример: + +```bash +LXC_ID=300 BACKUP_TIME=03:00 ./setup-backup-cron.sh +``` + +После установки: + +```bash +gitea-backup # ручной запуск +DO_VZDUMP=true gitea-backup # с полным бэкапом +tail -f /var/log/gitea-backup.log +``` + +## restore-gitea.sh + +Восстановление Gitea из бэкапа. Запускается внутри LXC после установки Gitea. + +Поддерживает: +- Архивы созданные через `gitea dump` +- Нативные дампы PostgreSQL +- Ручные бэкапы директорий + +Настройки: + +| Переменная | По умолчанию | Описание | +|------------|--------------|----------| +| `NEW_DOMAIN` | auto | Новый домен/IP | +| `NEW_PORT` | `3000` | HTTP порт | +| `DB_USER` | `gitea` | Пользователь PostgreSQL | +| `DB_NAME` | `gitea` | Имя базы данных | +| `DB_PASSWORD` | `gitea` | Пароль PostgreSQL | + +Пример: + +```bash +sudo ./restore-gitea.sh /tmp/gitea-backup-20240115-120000.tar.gz + +NEW_DOMAIN=git.example.com DB_PASSWORD=secret ./restore-gitea.sh /tmp/backup.tar.gz +``` + +Выполняет: +1. Распаковка архива +2. Восстановление PostgreSQL +3. Восстановление репозиториев и данных +4. Обновление app.ini для нового сервера +5. Регенерация SSH ключей и Git hooks +6. Запуск Gitea + +После восстановления проверьте: +- Авторизация пользователей +- Список репозиториев +- Git clone/push операции + +## Структура бэкапа + +``` +gitea-backup-YYYYMMDD-HHMMSS.tar.gz +├── database.sql # PostgreSQL дамп +├── gitea-dump.zip # Данные Gitea +├── app.ini # Конфигурация +├── gitea-version.txt # Версия Gitea +└── dump.log # Лог gitea dump +``` diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md new file mode 100644 index 0000000..7d610a5 --- /dev/null +++ b/MIGRATION_GUIDE.md @@ -0,0 +1,205 @@ +# Миграция Gitea из Docker VM в LXC контейнер + +## Обзор миграции + +| Параметр | Исходный | Целевой | +|----------|----------|---------| +| Proxmox Host | 192.168.0.32 | 192.168.0.33 | +| IP сервиса | 192.168.0.38 (VM) | 192.168.0.XX (LXC) | +| Тип развертывания | Docker в VM | LXC контейнер | + +--- + +## Пошаговая инструкция + +### Этап 1: Подготовка (на исходном сервере) + +#### 1.1 Определить структуру Docker Gitea + +```bash +ssh user@192.168.0.38 + +docker ps | grep -i gitea +docker volume ls | grep -i gitea +docker inspect gitea | jq '.[0].Mounts' +``` + +#### 1.2 Создать бэкап + +```bash +# Используйте интерактивный скрипт или запустите вручную: +./migration-scripts/backup-gitea-for-migration.sh +``` + +--- + +### Этап 2: Создание LXC контейнера (на Proxmox) + +#### Через CLI: + +```bash +pct create 200 local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst \ + --hostname gitea \ + --memory 2048 \ + --cores 2 \ + --rootfs local-lvm:20 \ + --net0 name=eth0,bridge=vmbr0,ip=192.168.0.40/24,gw=192.168.0.1 \ + --features nesting=1 \ + --start 1 + +pct enter 200 +``` + +--- + +### Этап 3: Установка Gitea в LXC + +#### 3.1 Базовая подготовка + +```bash +apt update && apt upgrade -y +apt install -y git sqlite3 wget curl + +adduser --system --shell /bin/bash --gecos 'Git Version Control' \ + --group --disabled-password --home /home/git git +``` + +#### 3.2 Установка Gitea + +```bash +mkdir -p /var/lib/gitea/{custom,data,log} +mkdir -p /etc/gitea +chown -R git:git /var/lib/gitea +chown root:git /etc/gitea +chmod 770 /etc/gitea + +GITEA_VERSION="1.25.3" +wget -O /usr/local/bin/gitea https://dl.gitea.io/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64 +chmod +x /usr/local/bin/gitea + +gitea --version +``` + +#### 3.3 Настройка systemd + +```bash +cp gitea.service /etc/systemd/system/gitea.service + +systemctl daemon-reload +systemctl enable gitea +systemctl start gitea +systemctl status gitea +``` + +--- + +### Этап 4: Миграция данных + +#### 4.1 Перенос файлов + +```bash +scp /tmp/gitea-backup-*.tar.gz root@192.168.0.40:/tmp/ +``` + +#### 4.2 Восстановление данных + +```bash +cd /tmp +tar -xzf gitea-backup-*.tar.gz + +systemctl stop gitea + +# Репозитории +cp -r gitea-backup/repositories/* /var/lib/gitea/data/gitea-repositories/ + +# Данные +cp -r gitea-backup/data/* /var/lib/gitea/data/ + +# База данных (SQLite) +cp gitea-backup/gitea.db /var/lib/gitea/data/gitea.db + +# Для PostgreSQL: +# psql -U gitea -d gitea < gitea-backup/gitea-db.sql + +# Конфигурация +cp gitea-backup/app.ini /etc/gitea/app.ini + +# Права +chown -R git:git /var/lib/gitea +chown root:git /etc/gitea/app.ini +chmod 640 /etc/gitea/app.ini + +systemctl start gitea +``` + +--- + +### Этап 5: Обновление конфигурации + +Редактируйте `/etc/gitea/app.ini`: + +```ini +[server] +DOMAIN = 192.168.0.40 +HTTP_PORT = 3000 +ROOT_URL = http://192.168.0.40:3000/ +SSH_DOMAIN = 192.168.0.40 +SSH_PORT = 22 + +[database] +PATH = /var/lib/gitea/data/gitea.db + +[repository] +ROOT = /var/lib/gitea/data/gitea-repositories +``` + +```bash +systemctl restart gitea +journalctl -u gitea -f +``` + +--- + +### Этап 6: Проверка миграции + +- [ ] Открыть веб-интерфейс: `http://192.168.0.40:3000` +- [ ] Войти под существующим пользователем +- [ ] Проверить список репозиториев +- [ ] Клонировать репозиторий через HTTP +- [ ] Клонировать репозиторий через SSH +- [ ] Сделать push в репозиторий + +#### Обновление git remote на клиентах: + +```bash +git remote set-url origin http://192.168.0.40:3000/user/repo.git +# или +git remote set-url origin git@192.168.0.40:user/repo.git +``` + +--- + +## Troubleshooting + +### Gitea не запускается + +```bash +journalctl -u gitea -e +cat /var/lib/gitea/log/gitea.log + +ls -la /var/lib/gitea/ +ls -la /etc/gitea/ +``` + +### Ошибки базы данных + +```bash +sqlite3 /var/lib/gitea/data/gitea.db "PRAGMA integrity_check;" +``` + +### Проблемы с SSH + +```bash +cat /home/git/.ssh/authorized_keys +sudo -u git gitea admin regenerate keys +``` diff --git a/MIGRATION_README.md b/MIGRATION_README.md new file mode 100644 index 0000000..ce2c6ed --- /dev/null +++ b/MIGRATION_README.md @@ -0,0 +1,60 @@ +# Миграция Gitea: Docker VM → LXC + +Набор скриптов для миграции Gitea из Docker в VM на нативную установку в LXC контейнере Proxmox. + +## Структура проекта + +``` +gitee-migration/ +├── MIGRATION_README.md +├── MIGRATION_GUIDE.md +├── migration-scripts/ +│ ├── full-migration.sh # Интерактивный скрипт миграции +│ ├── backup-gitea-for-migration.sh # Бэкап Gitea из Docker +│ ├── install-gitea-lxc.sh # Установка Gitea в LXC +│ ├── restore-gitea.sh # Восстановление из бэкапа +│ ├── lxc/ +│ │ └── create-lxc.sh # Создание LXC контейнера +│ └── systemd/ +│ └── gitea.service # Systemd unit для Gitea +└── backup-scripts/ + ├── backup-gitea-lxc.sh # Регулярный бэкап Gitea в LXC + ├── backup-proxmox.sh # Бэкап Proxmox + └── setup-backup-cron.sh # Настройка cron для бэкапов +``` + +## Быстрый старт + +```bash +# 1. Отредактируйте настройки в скрипте +nano migration-scripts/full-migration.sh + +# 2. Запустите интерактивную миграцию +./migration-scripts/full-migration.sh +``` + +## Конфигурация + +Отредактируйте переменные в `migration-scripts/full-migration.sh`: + +| Переменная | Описание | +|------------|----------| +| `SOURCE_HOST` | IP исходного сервера с Docker Gitea | +| `PROXMOX_HOST` | IP Proxmox хоста | +| `LXC_ID` | ID создаваемого LXC контейнера | +| `LXC_IP` | IP для LXC контейнера | +| `GITEA_CONTAINER` | Имя Docker контейнера Gitea | +| `DB_CONTAINER` | Имя Docker контейнера PostgreSQL | +| `DB_PASSWORD` | Пароль PostgreSQL | + +## Требования + +- SSH доступ ко всем серверам по ключам +- Docker на исходном сервере +- Proxmox VE на целевом хосте + +## Важно + +1. Сделайте бэкап перед началом миграции +2. Используйте ту же версию Gitea или новее +3. Не удаляйте старую установку до полной проверки новой diff --git a/backup-scripts/backup-gitea-lxc.sh b/backup-scripts/backup-gitea-lxc.sh new file mode 100755 index 0000000..a809765 --- /dev/null +++ b/backup-scripts/backup-gitea-lxc.sh @@ -0,0 +1,240 @@ +#!/bin/bash +# +# Скрипт бэкапа Gitea в LXC контейнере +# Запускать ВНУТРИ LXC контейнера +# +# Создаёт: +# - pg_dump базы данных +# - gitea dump (репозитории, конфиг, данные) +# - Единый архив +# + +set -e + +# ============================================ +# НАСТРОЙКИ +# ============================================ + +# Директория для бэкапов +BACKUP_BASE="${BACKUP_BASE:-/var/backups/gitea}" + +# PostgreSQL +DB_USER="${DB_USER:-gitea}" +DB_NAME="${DB_NAME:-gitea}" + +# Gitea пути +GITEA_BIN="${GITEA_BIN:-/usr/local/bin/gitea}" +GITEA_CONFIG="${GITEA_CONFIG:-/etc/gitea/app.ini}" +GITEA_DATA="${GITEA_DATA:-/var/lib/gitea}" + +# Сколько бэкапов хранить (0 = не удалять старые) +KEEP_BACKUPS="${KEEP_BACKUPS:-7}" + +# Отправка на удалённый сервер (опционально) +REMOTE_BACKUP="${REMOTE_BACKUP:-}" # user@host:/path/to/backups + +# ============================================ +# ФУНКЦИИ +# ============================================ + +log() { + echo -e "\033[1;32m[$(date '+%Y-%m-%d %H:%M:%S')]\033[0m $1" +} + +warn() { + echo -e "\033[1;33m[WARN]\033[0m $1" +} + +error() { + echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 + exit 1 +} + +cleanup() { + if [ -n "$BACKUP_DIR" ] && [ -d "$BACKUP_DIR" ]; then + rm -rf "$BACKUP_DIR" + fi +} + +trap cleanup EXIT + +# ============================================ +# ПРОВЕРКИ +# ============================================ + +if [ "$EUID" -ne 0 ]; then + error "Запустите от root: sudo $0" +fi + +if ! command -v "$GITEA_BIN" &>/dev/null; then + error "Gitea не найдена: $GITEA_BIN" +fi + +if ! systemctl is-active --quiet postgresql; then + error "PostgreSQL не запущен" +fi + +# ============================================ +# ПОДГОТОВКА +# ============================================ + +TIMESTAMP=$(date +%Y%m%d-%H%M%S) +BACKUP_DIR="$BACKUP_BASE/gitea-backup-$TIMESTAMP" +ARCHIVE_NAME="gitea-backup-$TIMESTAMP.tar.gz" + +mkdir -p "$BACKUP_DIR" +mkdir -p "$BACKUP_BASE" + +log "==========================================" +log " Бэкап Gitea (LXC)" +log "==========================================" +log "" +log "Директория: $BACKUP_DIR" +log "Архив: $BACKUP_BASE/$ARCHIVE_NAME" +log "" + +# Сохраняем версию +GITEA_VERSION=$("$GITEA_BIN" --version 2>&1 | head -1) +echo "$GITEA_VERSION" > "$BACKUP_DIR/gitea-version.txt" +log "Версия Gitea: $GITEA_VERSION" + +# ============================================ +# ШАГ 1: ДАМП POSTGRESQL +# ============================================ + +log "Создание дампа PostgreSQL..." +sudo -u postgres pg_dump -d "$DB_NAME" --no-owner --no-acl > "$BACKUP_DIR/database.sql" +log " ✓ database.sql ($(du -h "$BACKUP_DIR/database.sql" | cut -f1))" + +# ============================================ +# ШАГ 2: ОСТАНОВКА GITEA (для консистентности) +# ============================================ + +GITEA_WAS_RUNNING=false +if systemctl is-active --quiet gitea; then + GITEA_WAS_RUNNING=true + log "Остановка Gitea..." + systemctl stop gitea + sleep 2 +fi + +# ============================================ +# ШАГ 3: GITEA DUMP +# ============================================ + +log "Создание gitea dump..." + +# gitea dump запускается от пользователя git, поэтому используем его директорию +DUMP_TEMP="$GITEA_DATA/tmp-dump" +mkdir -p "$DUMP_TEMP" +chown git:git "$DUMP_TEMP" + +# gitea dump создаёт архив с репозиториями и данными +sudo -u git "$GITEA_BIN" dump \ + --config "$GITEA_CONFIG" \ + --work-path "$GITEA_DATA" \ + --file "$DUMP_TEMP/gitea-dump.zip" \ + --tempdir "$DUMP_TEMP" \ + --skip-db \ + --type zip 2>&1 | tee "$BACKUP_DIR/dump.log" || { + warn "gitea dump завершился с предупреждениями (см. dump.log)" +} + +# Проверяем на фатальные ошибки +if grep -q "\[F\]" "$BACKUP_DIR/dump.log" 2>/dev/null; then + warn "Обнаружена фатальная ошибка в gitea dump:" + grep "\[F\]" "$BACKUP_DIR/dump.log" +fi + +# Перемещаем результат в директорию бэкапа +if [ -f "$DUMP_TEMP/gitea-dump.zip" ]; then + mv "$DUMP_TEMP/gitea-dump.zip" "$BACKUP_DIR/" + log " ✓ gitea-dump.zip ($(du -h "$BACKUP_DIR/gitea-dump.zip" | cut -f1))" +else + warn "gitea-dump.zip не создан, копируем данные вручную..." + cp -a "$GITEA_DATA" "$BACKUP_DIR/data" + log " ✓ data/ (ручное копирование)" +fi + +# Очищаем временную директорию +rm -rf "$DUMP_TEMP" + +# ============================================ +# ШАГ 4: КОПИРОВАНИЕ КОНФИГУРАЦИИ +# ============================================ + +log "Копирование конфигурации..." +cp "$GITEA_CONFIG" "$BACKUP_DIR/app.ini" +log " ✓ app.ini" + +# ============================================ +# ШАГ 5: ПЕРЕЗАПУСК GITEA +# ============================================ + +if [ "$GITEA_WAS_RUNNING" = true ]; then + log "Запуск Gitea..." + systemctl start gitea + log " ✓ Gitea запущена" +fi + +# ============================================ +# ШАГ 6: СОЗДАНИЕ АРХИВА +# ============================================ + +log "Создание архива..." +cd "$BACKUP_BASE" +tar -czf "$ARCHIVE_NAME" -C "$BACKUP_BASE" "$(basename $BACKUP_DIR)" + +ARCHIVE_SIZE=$(du -h "$BACKUP_BASE/$ARCHIVE_NAME" | cut -f1) +log " ✓ $ARCHIVE_NAME ($ARCHIVE_SIZE)" + +# Удаляем временную директорию +rm -rf "$BACKUP_DIR" +trap - EXIT + +# ============================================ +# ШАГ 7: РОТАЦИЯ СТАРЫХ БЭКАПОВ +# ============================================ + +if [ "$KEEP_BACKUPS" -gt 0 ]; then + log "Ротация бэкапов (храним $KEEP_BACKUPS)..." + cd "$BACKUP_BASE" + ls -t gitea-backup-*.tar.gz 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) | xargs -r rm -f + CURRENT_COUNT=$(ls -1 gitea-backup-*.tar.gz 2>/dev/null | wc -l) + log " ✓ Текущих бэкапов: $CURRENT_COUNT" +fi + +# ============================================ +# ШАГ 8: ОТПРАВКА НА УДАЛЁННЫЙ СЕРВЕР +# ============================================ + +if [ -n "$REMOTE_BACKUP" ]; then + log "Отправка на удалённый сервер: $REMOTE_BACKUP" + if scp "$BACKUP_BASE/$ARCHIVE_NAME" "$REMOTE_BACKUP/"; then + log " ✓ Отправлено" + else + warn "Не удалось отправить бэкап" + fi +fi + +# ============================================ +# ИТОГИ +# ============================================ + +log "" +log "==========================================" +log " ✅ Бэкап завершён!" +log "==========================================" +log "" +log "Файл: $BACKUP_BASE/$ARCHIVE_NAME" +log "Размер: $ARCHIVE_SIZE" +log "" +log "Содержимое архива:" +log " - database.sql (PostgreSQL дамп)" +log " - gitea-dump.zip (репозитории, LFS, данные)" +log " - app.ini (конфигурация)" +log " - gitea-version.txt" +log "" + +# Возвращаем путь к архиву (для скриптов) +echo "$BACKUP_BASE/$ARCHIVE_NAME" diff --git a/backup-scripts/backup-proxmox.sh b/backup-scripts/backup-proxmox.sh new file mode 100755 index 0000000..66ae0a4 --- /dev/null +++ b/backup-scripts/backup-proxmox.sh @@ -0,0 +1,207 @@ +#!/bin/bash +# +# Скрипт бэкапа Gitea LXC контейнера с Proxmox хоста +# Запускать НА PROXMOX хосте +# +# Выполняет: +# 1. Бэкап на уровне приложения (gitea dump + pg_dump) внутри LXC +# 2. vzdump - полный бэкап контейнера (опционально) +# + +set -e + +# ============================================ +# НАСТРОЙКИ +# ============================================ + +# ID LXC контейнера с Gitea +LXC_ID="${LXC_ID:-300}" + +# Директория для хранения бэкапов на Proxmox +BACKUP_STORAGE="${BACKUP_STORAGE:-/var/lib/vz/dump}" + +# Делать ли полный vzdump контейнера (занимает много места) +DO_VZDUMP="${DO_VZDUMP:-false}" + +# Сжатие для vzdump: zstd, gzip, lzo, none +VZDUMP_COMPRESS="${VZDUMP_COMPRESS:-zstd}" + +# Сколько бэкапов хранить +KEEP_BACKUPS="${KEEP_BACKUPS:-7}" + +# Сколько vzdump хранить (они большие!) +KEEP_VZDUMP="${KEEP_VZDUMP:-3}" + +# Удалённый сервер для копирования (опционально) +REMOTE_BACKUP="${REMOTE_BACKUP:-}" # user@host:/path + +# ============================================ +# ФУНКЦИИ +# ============================================ + +log() { + echo -e "\033[1;34m[$(date '+%Y-%m-%d %H:%M:%S')]\033[0m $1" +} + +warn() { + echo -e "\033[1;33m[WARN]\033[0m $1" +} + +error() { + echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 + exit 1 +} + +# ============================================ +# ПРОВЕРКИ +# ============================================ + +if ! command -v pct &>/dev/null; then + error "Этот скрипт должен запускаться на Proxmox хосте" +fi + +if ! pct status "$LXC_ID" &>/dev/null; then + error "LXC контейнер $LXC_ID не найден" +fi + +LXC_STATUS=$(pct status "$LXC_ID" | awk '{print $2}') +if [ "$LXC_STATUS" != "running" ]; then + error "LXC контейнер $LXC_ID не запущен (статус: $LXC_STATUS)" +fi + +mkdir -p "$BACKUP_STORAGE" + +# ============================================ +# ПЕРЕМЕННЫЕ +# ============================================ + +TIMESTAMP=$(date +%Y%m%d-%H%M%S) +GITEA_BACKUP_DIR="/var/backups/gitea" + +log "==========================================" +log " Бэкап Gitea LXC (ID: $LXC_ID)" +log "==========================================" +log "" + +# ============================================ +# ШАГ 1: БЭКАП НА УРОВНЕ ПРИЛОЖЕНИЯ +# ============================================ + +log "Запуск бэкапа Gitea внутри LXC..." + +# Копируем скрипт бэкапа в контейнер +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +if [ -f "$SCRIPT_DIR/backup-gitea-lxc.sh" ]; then + pct push "$LXC_ID" "$SCRIPT_DIR/backup-gitea-lxc.sh" /root/backup-gitea-lxc.sh + pct exec "$LXC_ID" -- chmod +x /root/backup-gitea-lxc.sh +fi + +# Запускаем бэкап внутри контейнера +BACKUP_OUTPUT=$(pct exec "$LXC_ID" -- bash -c "KEEP_BACKUPS=$KEEP_BACKUPS /root/backup-gitea-lxc.sh" 2>&1) || { + echo "$BACKUP_OUTPUT" + error "Бэкап внутри LXC завершился с ошибкой" +} + +echo "$BACKUP_OUTPUT" + +# Получаем путь к созданному архиву (последняя строка вывода) +LXC_BACKUP_FILE=$(echo "$BACKUP_OUTPUT" | tail -1) + +if [ -z "$LXC_BACKUP_FILE" ] || ! pct exec "$LXC_ID" -- test -f "$LXC_BACKUP_FILE"; then + # Ищем последний бэкап + LXC_BACKUP_FILE=$(pct exec "$LXC_ID" -- ls -t "$GITEA_BACKUP_DIR"/gitea-backup-*.tar.gz 2>/dev/null | head -1) +fi + +if [ -n "$LXC_BACKUP_FILE" ]; then + log "Копирование бэкапа из LXC..." + BACKUP_NAME=$(basename "$LXC_BACKUP_FILE") + pct pull "$LXC_ID" "$LXC_BACKUP_FILE" "$BACKUP_STORAGE/$BACKUP_NAME" + log " ✓ $BACKUP_STORAGE/$BACKUP_NAME" + + # Удаляем архив из LXC (хранятся только на Proxmox) + pct exec "$LXC_ID" -- rm -f "$LXC_BACKUP_FILE" + log " ✓ Удалён из LXC (хранится только на Proxmox)" +else + warn "Не удалось найти архив бэкапа в LXC" +fi + +# ============================================ +# ШАГ 2: VZDUMP (полный бэкап контейнера) +# ============================================ + +if [ "$DO_VZDUMP" = "true" ]; then + log "" + log "Создание полного бэкапа контейнера (vzdump)..." + + vzdump "$LXC_ID" \ + --compress "$VZDUMP_COMPRESS" \ + --storage local \ + --mode snapshot \ + --notes "Gitea backup $TIMESTAMP" \ + 2>&1 | while read line; do log " $line"; done + + log " ✓ vzdump завершён" +fi + +# ============================================ +# ШАГ 3: ОТПРАВКА НА УДАЛЁННЫЙ СЕРВЕР +# ============================================ + +if [ -n "$REMOTE_BACKUP" ] && [ -n "$BACKUP_NAME" ]; then + log "" + log "Отправка на удалённый сервер: $REMOTE_BACKUP" + if scp "$BACKUP_STORAGE/$BACKUP_NAME" "$REMOTE_BACKUP/"; then + log " ✓ Отправлено" + else + warn "Не удалось отправить" + fi +fi + +# ============================================ +# ШАГ 4: РОТАЦИЯ БЭКАПОВ +# ============================================ + +if [ "$KEEP_BACKUPS" -gt 0 ]; then + log "" + log "Ротация gitea бэкапов (храним $KEEP_BACKUPS)..." + cd "$BACKUP_STORAGE" + ls -t gitea-backup-*.tar.gz 2>/dev/null | tail -n +$((KEEP_BACKUPS + 1)) | xargs -r rm -f + log " ✓ Готово" +fi + +# Ротация vzdump (они большие!) +if [ "$KEEP_VZDUMP" -gt 0 ] && [ "$DO_VZDUMP" = "true" ]; then + log "Ротация vzdump бэкапов (храним $KEEP_VZDUMP)..." + cd "$BACKUP_STORAGE" + # Удаляем старые .tar.zst, .tar.gz, .tar.lzo и соответствующие .log файлы + for ext in tar.zst tar.gz tar.lzo vma.zst vma.gz vma.lzo; do + ls -t vzdump-lxc-${LXC_ID}-*.$ext 2>/dev/null | tail -n +$((KEEP_VZDUMP + 1)) | while read f; do + rm -f "$f" "${f%.${ext}}.log" + log " Удалён: $(basename $f)" + done + done + log " ✓ Готово" +fi + +# ============================================ +# ИТОГИ +# ============================================ + +log "" +log "==========================================" +log " ✅ Бэкап завершён!" +log "==========================================" +log "" +log "Бэкапы Gitea:" +ls -lh "$BACKUP_STORAGE"/gitea-backup-*.tar.gz 2>/dev/null | tail -5 || echo " (нет)" +log "" + +if [ "$DO_VZDUMP" = "true" ]; then + log "Бэкапы vzdump:" + ls -lh "$BACKUP_STORAGE"/vzdump-lxc-${LXC_ID}-*.* 2>/dev/null | tail -3 || echo " (нет)" + log "" +fi + +log "Следующий бэкап по расписанию или вручную:" +log " $0" +log "" diff --git a/backup-scripts/restore-gitea.sh b/backup-scripts/restore-gitea.sh new file mode 100755 index 0000000..c842558 --- /dev/null +++ b/backup-scripts/restore-gitea.sh @@ -0,0 +1,494 @@ +#!/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 "==========================================" diff --git a/backup-scripts/setup-backup-cron.sh b/backup-scripts/setup-backup-cron.sh new file mode 100755 index 0000000..676b9b7 --- /dev/null +++ b/backup-scripts/setup-backup-cron.sh @@ -0,0 +1,60 @@ +#!/bin/bash +# +# Настройка автоматического бэкапа Gitea +# Запускать на Proxmox хосте +# + +set -e + +LXC_ID="${LXC_ID:-300}" +BACKUP_TIME="${BACKUP_TIME:-12:00}" # Время бэкапа (HH:MM) +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +echo "Настройка автоматического бэкапа Gitea" +echo "" +echo "LXC контейнер: $LXC_ID" +echo "Время бэкапа: $BACKUP_TIME ежедневно" +echo "" + +# Копируем скрипты +echo "Копирование скриптов..." +cp "$SCRIPT_DIR/backup-proxmox.sh" /usr/local/bin/gitea-backup +cp "$SCRIPT_DIR/backup-gitea-lxc.sh" /usr/local/bin/gitea-backup-lxc +chmod +x /usr/local/bin/gitea-backup /usr/local/bin/gitea-backup-lxc + +# Копируем скрипт в LXC +pct push "$LXC_ID" "$SCRIPT_DIR/backup-gitea-lxc.sh" /root/backup-gitea-lxc.sh +pct exec "$LXC_ID" -- chmod +x /root/backup-gitea-lxc.sh + +# Парсим время +HOUR=$(echo "$BACKUP_TIME" | cut -d: -f1) +MINUTE=$(echo "$BACKUP_TIME" | cut -d: -f2) + +# Создаём cron задачу +CRON_FILE="/etc/cron.d/gitea-backup" +cat > "$CRON_FILE" << EOF +# Автоматический бэкап Gitea +# Создано: $(date) + +# Ежедневный бэкап в $BACKUP_TIME +$MINUTE $HOUR * * * root LXC_ID=$LXC_ID /usr/local/bin/gitea-backup >> /var/log/gitea-backup.log 2>&1 + +# Еженедельный полный vzdump (воскресенье в 13:00) +0 13 * * 0 root LXC_ID=$LXC_ID DO_VZDUMP=true /usr/local/bin/gitea-backup >> /var/log/gitea-backup.log 2>&1 +EOF + +chmod 644 "$CRON_FILE" + +echo "" +echo "✅ Cron задача создана: $CRON_FILE" +echo "" +echo "Расписание:" +echo " - Ежедневно в $BACKUP_TIME: gitea dump + pg_dump" +echo " - Воскресенье в 13:00: + полный vzdump контейнера" +echo "" +echo "Логи: /var/log/gitea-backup.log" +echo "" +echo "Ручной запуск:" +echo " gitea-backup # Только данные" +echo " DO_VZDUMP=true gitea-backup # + полный бэкап контейнера" +echo "" diff --git a/migration-scripts/backup-gitea-for-migration.sh b/migration-scripts/backup-gitea-for-migration.sh new file mode 100755 index 0000000..e751445 --- /dev/null +++ b/migration-scripts/backup-gitea-for-migration.sh @@ -0,0 +1,383 @@ +#!/bin/bash +# +# Скрипт бэкапа Gitea из Docker +# Основан на рекомендациях: https://docs.gitea.com/administration/backup-and-restore +# +# Использует официальную команду `gitea dump` для создания консистентного бэкапа. +# Для PostgreSQL дополнительно делает нативный дамп БД (рекомендовано Gitea). +# +# База данных: PostgreSQL +# Запускать на исходном сервере (192.168.0.38) +# + +set -e + +# ============================================ +# НАСТРОЙКИ - ОТРЕДАКТИРУЙТЕ ПОД ВАШУ КОНФИГУРАЦИЮ +# ============================================ + +# Имя Docker контейнера Gitea +# Для docker-compose обычно: gitea-server-1, gitea-gitea-1 или gitea_server_1 +GITEA_CONTAINER="${GITEA_CONTAINER:-gitea-server-1}" + +# Имя контейнера PostgreSQL +# Для docker-compose: gitea-db-1, gitea_db_1 +DB_CONTAINER="${DB_CONTAINER:-gitea-db-1}" + +# Credentials для PostgreSQL +DB_USER="${DB_USER:-gitea}" +DB_NAME="${DB_NAME:-gitea}" +DB_PASSWORD="${DB_PASSWORD:-}" + +# Директория для бэкапа +BACKUP_DIR="${BACKUP_DIR:-/tmp/gitea-backup-$(date +%Y%m%d-%H%M%S)}" + +# Формат архива: zip или tar.gz +ARCHIVE_TYPE="${ARCHIVE_TYPE:-zip}" + +# ============================================ +# ПУТИ GITEA (автоопределяются, но можно переопределить) +# ============================================ +# Для rootless образа (docker.gitea.com/gitea:*-rootless): +# - Конфиг: /etc/gitea/app.ini +# - Бинарник: /usr/local/bin/gitea +# - Данные: /var/lib/gitea +# Для обычного образа (gitea/gitea:*): +# - Конфиг: /data/gitea/conf/app.ini +# - Бинарник: /app/gitea/gitea или /usr/local/bin/gitea +# - Данные: /data +GITEA_CONFIG="${GITEA_CONFIG:-}" +GITEA_BIN="${GITEA_BIN:-}" + +# Rootless режим (автоопределяется) +ROOTLESS="${ROOTLESS:-auto}" + +# ============================================ +# ФУНКЦИИ +# ============================================ + +log() { + echo -e "\033[1;32m[$(date '+%Y-%m-%d %H:%M:%S')]\033[0m $1" +} + +warn() { + echo -e "\033[1;33m[WARN]\033[0m $1" +} + +error() { + echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 + exit 1 +} + +check_container() { + if ! docker ps --format '{{.Names}}' | grep -q "^${1}$"; then + if docker ps -a --format '{{.Names}}' | grep -q "^${1}$"; then + warn "Контейнер '$1' существует, но не запущен" + return 1 + else + error "Контейнер '$1' не найден" + fi + fi + return 0 +} + +detect_gitea_paths() { + log "Автоопределение путей и режима Gitea..." + + # Определяем rootless режим по образу + if [ "$ROOTLESS" = "auto" ]; then + IMAGE=$(docker inspect "$GITEA_CONTAINER" --format '{{.Config.Image}}' 2>/dev/null || echo "") + if echo "$IMAGE" | grep -q "rootless"; then + ROOTLESS="true" + log " Обнаружен rootless образ: $IMAGE" + else + ROOTLESS="false" + log " Обнаружен стандартный образ: $IMAGE" + fi + fi + + # Пробуем найти app.ini (порядок зависит от режима) + if [ -z "$GITEA_CONFIG" ]; then + if [ "$ROOTLESS" = "true" ]; then + CONFIG_PATHS="/etc/gitea/app.ini /var/lib/gitea/custom/conf/app.ini /data/gitea/conf/app.ini" + else + CONFIG_PATHS="/data/gitea/conf/app.ini /etc/gitea/app.ini /app/gitea/custom/conf/app.ini" + fi + + for config_path in $CONFIG_PATHS; do + if docker exec "$GITEA_CONTAINER" test -f "$config_path" 2>/dev/null; then + GITEA_CONFIG="$config_path" + log " Найден конфиг: $GITEA_CONFIG" + break + fi + done + fi + + # Пробуем найти бинарник gitea + if [ -z "$GITEA_BIN" ]; then + if [ "$ROOTLESS" = "true" ]; then + BIN_PATHS="/usr/local/bin/gitea /usr/bin/gitea /app/gitea/gitea" + else + BIN_PATHS="/app/gitea/gitea /usr/local/bin/gitea /usr/bin/gitea" + fi + + for bin_path in $BIN_PATHS; do + if docker exec "$GITEA_CONTAINER" test -x "$bin_path" 2>/dev/null; then + GITEA_BIN="$bin_path" + log " Найден бинарник: $GITEA_BIN" + break + fi + done + fi + + # Устанавливаем дефолты если не найдено + GITEA_CONFIG="${GITEA_CONFIG:-/etc/gitea/app.ini}" + GITEA_BIN="${GITEA_BIN:-/usr/local/bin/gitea}" +} + +# ============================================ +# ОСНОВНОЙ СКРИПТ +# ============================================ + +log "==========================================" +log " Бэкап Gitea (официальный метод)" +log "==========================================" +log "" +log "Контейнер: $GITEA_CONTAINER" +log "БД контейнер: $DB_CONTAINER (PostgreSQL)" +log "Директория бэкапа: $BACKUP_DIR" +log "" + +# Создаём директорию бэкапа +mkdir -p "$BACKUP_DIR" + +# Проверяем наличие контейнера +if ! check_container "$GITEA_CONTAINER"; then + error "Контейнер Gitea должен быть запущен для определения путей" +fi + +# Автоопределение путей +detect_gitea_paths + +# Получаем версию Gitea +GITEA_VERSION=$(docker exec "$GITEA_CONTAINER" "$GITEA_BIN" --version 2>/dev/null | head -1 || echo "unknown") +log "Версия Gitea: $GITEA_VERSION" +echo "$GITEA_VERSION" > "$BACKUP_DIR/gitea-version.txt" + +# Сохраняем информацию о Docker +log "Сохранение информации о Docker конфигурации..." +docker inspect "$GITEA_CONTAINER" > "$BACKUP_DIR/docker-inspect.json" 2>/dev/null || true +docker inspect "$GITEA_CONTAINER" --format '{{json .Mounts}}' 2>/dev/null | jq '.' > "$BACKUP_DIR/docker-mounts.json" 2>/dev/null || true + +# ============================================ +# ШАГ 1: Нативный дамп PostgreSQL +# Рекомендация Gitea: использовать нативные инструменты +# ============================================ + +log "Создание нативного дампа PostgreSQL..." + +if [ -n "$DB_CONTAINER" ]; then + if [ -n "$DB_PASSWORD" ]; then + docker exec -e PGPASSWORD="$DB_PASSWORD" "$DB_CONTAINER" \ + pg_dump -U "$DB_USER" -d "$DB_NAME" --no-owner --no-acl \ + > "$BACKUP_DIR/gitea-db-native.sql" 2>/dev/null + else + docker exec "$DB_CONTAINER" \ + pg_dump -U "$DB_USER" -d "$DB_NAME" --no-owner --no-acl \ + > "$BACKUP_DIR/gitea-db-native.sql" 2>/dev/null + fi + log " ✓ PostgreSQL дамп создан: gitea-db-native.sql" +else + warn "DB_CONTAINER не указан, пропускаем нативный дамп" +fi + +# ============================================ +# ШАГ 2: Остановка Gitea (рекомендуется для консистентности) +# ============================================ + +log "Остановка Gitea для консистентного бэкапа..." +GITEA_WAS_RUNNING=false +if docker ps --format '{{.Names}}' | grep -q "^${GITEA_CONTAINER}$"; then + GITEA_WAS_RUNNING=true + docker stop "$GITEA_CONTAINER" >/dev/null + log " ✓ Gitea остановлена" + sleep 2 +fi + +# ============================================ +# ШАГ 3: Создание бэкапа с помощью `gitea dump` +# Официальный метод согласно документации +# ============================================ + +log "Создание бэкапа через 'gitea dump'..." + +# Временно запускаем контейнер для выполнения dump +docker start "$GITEA_CONTAINER" >/dev/null 2>&1 || true +sleep 3 + +# Определяем параметры для gitea dump +DUMP_ARGS="-c $GITEA_CONFIG" +DUMP_ARGS="$DUMP_ARGS --type $ARCHIVE_TYPE" + +# Для rootless временная директория должна быть доступна пользователю git +if [ "$ROOTLESS" = "true" ]; then + DUMP_ARGS="$DUMP_ARGS --tempdir /var/lib/gitea" + DUMP_SEARCH_PATHS="/var/lib/gitea /tmp /home/git" +else + DUMP_ARGS="$DUMP_ARGS --tempdir /tmp" + DUMP_SEARCH_PATHS="/tmp /app/gitea /data" +fi + +# Пропускаем встроенный дамп БД (уже сделали нативный) +if [ -f "$BACKUP_DIR/gitea-db-native.sql" ]; then + DUMP_ARGS="$DUMP_ARGS --skip-db" + log " (пропуск встроенного дампа БД - используем нативный)" +fi + +# Выполняем gitea dump +log " Выполнение: gitea dump $DUMP_ARGS" +if [ "$ROOTLESS" = "true" ]; then + docker exec "$GITEA_CONTAINER" "$GITEA_BIN" dump $DUMP_ARGS 2>&1 | tee "$BACKUP_DIR/dump.log" || { + warn "gitea dump завершился с ошибкой, проверьте dump.log" + } +else + docker exec -u git "$GITEA_CONTAINER" "$GITEA_BIN" dump $DUMP_ARGS 2>&1 | tee "$BACKUP_DIR/dump.log" || { + warn "Повторная попытка без флага -u git..." + docker exec "$GITEA_CONTAINER" "$GITEA_BIN" dump $DUMP_ARGS 2>&1 | tee "$BACKUP_DIR/dump.log" + } +fi + +# Находим созданный архив +log " Поиск архива..." +DUMP_FILE="" +for search_path in $DUMP_SEARCH_PATHS; do + DUMP_FILE=$(docker exec "$GITEA_CONTAINER" sh -c "ls -t ${search_path}/gitea-dump-*.${ARCHIVE_TYPE} 2>/dev/null | head -1" || true) + if [ -n "$DUMP_FILE" ] && [ "$" != "" ]; then + break + fi +done + +# Если не нашли, ищем везде +if [ -z "$DUMP_FILE" ]; then + DUMP_FILE=$(docker exec "$GITEA_CONTAINER" find / -name "gitea-dump-*.${ARCHIVE_TYPE}" -type f 2>/dev/null | head -1 || true) +fi + +if [ -n "$DUMP_FILE" ] && [ "$DUMP_FILE" != "" ]; then + log " Найден архив: $DUMP_FILE" + docker cp "$GITEA_CONTAINER:$DUMP_FILE" "$BACKUP_DIR/gitea-dump.${ARCHIVE_TYPE}" + log " ✓ Архив скопирован: gitea-dump.${ARCHIVE_TYPE}" + + # Удаляем архив из контейнера + docker exec "$GITEA_CONTAINER" rm -f "$DUMP_FILE" 2>/dev/null || true +else + warn "Архив gitea dump не найден, делаем ручное копирование..." + + # Fallback: ручное копирование данных + log " Копирование данных вручную..." + if [ "$ROOTLESS" = "true" ]; then + docker cp "$GITEA_CONTAINER:/var/lib/gitea" "$BACKUP_DIR/data" 2>/dev/null || \ + docker cp "$GITEA_CONTAINER:/data" "$BACKUP_DIR/data" 2>/dev/null || \ + warn " Не удалось скопировать данные" + else + docker cp "$GITEA_CONTAINER:/data" "$BACKUP_DIR/data" 2>/dev/null || \ + docker cp "$GITEA_CONTAINER:/var/lib/gitea" "$BACKUP_DIR/data" 2>/dev/null || \ + warn " Не удалось скопировать данные" + fi +fi + +# ============================================ +# ШАГ 4: Копирование конфигурации отдельно +# ============================================ + +log "Копирование конфигурации..." +docker cp "$GITEA_CONTAINER:$GITEA_CONFIG" "$BACKUP_DIR/app.ini" 2>/dev/null && \ + log " ✓ app.ini скопирован" || \ + warn " Не удалось скопировать app.ini (возDUMP_FILEможно включён в архив)" + +# ============================================ +# ШАГ 5: Возврат в исходное состояние +# ============================================ + +if [ "$GITEA_WAS_RUNNING" = true ]; then + log "Перезапуск Gitea..." + docker restart "$GITEA_CONTAINER" >/dev/null + log " ✓ Gitea запущена" +else + log "Остановка Gitea (была остановлена до бэкапа)..." + docker stop "$GITEA_CONTAINER" >/dev/null 2>&1 || true +fi + +# ============================================ +# ШАГ 6: Поиск docker-compose +# ============================================ + +log "Поиск docker-compose файлов..." +COMPOSE_FILES=$(find /home /opt /root /srv -maxdepth 4 \ + \( -name "docker-compose*.yml" -o -name "docker-compose*.yaml" -o -name "compose*.yml" -o -name "compose*.yaml" \) \ + 2>/dev/null | xargs grep -l -i gitea 2>/dev/null || true) + +if [ -n "$COMPOSE_FILES" ]; then + mkdir -p "$BACKUP_DIR/compose" + for f in $COMPOSE_FILES; do + cp "$f" "$BACKUP_DIR/compose/" 2>/dev/null || true + done + log " ✓ Docker Compose файлы скопированы" +fi + +# ============================================ +# ШАГ 7: Создание итогового архива +# ============================================ + +log "Создание итогового архива..." +ARCHIVE_NAME="gitea-backup-$(date +%Y%m%d-%H%M%S).tar.gz" +cd /tmp +tar -czf "$ARCHIVE_NAME" "$(basename $BACKUP_DIR)" + +log "" +log "==========================================" +log " ✅ Бэкап успешно завершён!" +log "==========================================" +log "" +log "Содержимое бэкапа:" +ls -lh "$BACKUP_DIR" +log "" +log "Итоговый архив:" +ls -lh "/tmp/$ARCHIVE_NAME" +log "" +log "Файлы:" +log " Директория: $BACKUP_DIR" +log " Архив: /tmp/$ARCHIVE_NAME" +log "" +log "Следующий шаг - скопируйте архив на новый сервер:" +log " scp /tmp/$ARCHIVE_NAME root@NEW_SERVER_IP:/tmp/" +log "" + +# Создаём файл с инструкцией +cat > "$BACKUP_DIR/RESTORE_INFO.txt" << EOF +Gitea Backup Information +======================== + +Created: $(date) +Gitea Version: $GITEA_VERSION +Database: PostgreSQL + +Contents: +- gitea-dump.${ARCHIVE_TYPE} - Official Gitea dump (repos, data, config) +- gitea-db-native.sql - Native PostgreSQL dump (recommended for restore) +- app.ini - Configuration file +- gitea-version.txt - Version information +- docker-inspect.json - Docker container configuration +- docker-mounts.json - Docker volume mounts +$([ -d "$BACKUP_DIR/compose" ] && echo "- compose/ - Docker Compose files") + +Restore Instructions: +1. Extract: tar -xzf $ARCHIVE_NAME +2. Restore PostgreSQL: psql -U gitea -d gitea < gitea-db-native.sql +3. Extract gitea-dump.${ARCHIVE_TYPE} and restore files +4. Update app.ini with new paths/domains +5. Start Gitea + +For detailed instructions see: https://docs.gitea.com/administration/backup-and-restore +EOF + +log "Информация о восстановлении сохранена в RESTORE_INFO.txt" diff --git a/migration-scripts/full-migration.sh b/migration-scripts/full-migration.sh new file mode 100755 index 0000000..e3a40de --- /dev/null +++ b/migration-scripts/full-migration.sh @@ -0,0 +1,363 @@ +#!/bin/bash +# +# Полный скрипт миграции Gitea +# Координирует весь процесс миграции +# + +set -e + +# ============================================ +# НАСТРОЙКИ - ОБЯЗАТЕЛЬНО ИЗМЕНИТЕ! +# ============================================ + +# Исходный сервер (VM с Docker Gitea) +SOURCE_HOST="192.168.0.38" +SOURCE_USER="tactile" + +# Целевой Proxmox хост +PROXMOX_HOST="192.168.0.33" +PROXMOX_USER="root" + +# LXC контейнер +LXC_ID="300" +LXC_IP="192.168.0.40" + +# Docker контейнеры Gitea на исходном сервере +GITEA_CONTAINER="gitea-server-1" +DB_CONTAINER="gitea-db-1" + +# Версия Gitea (должна совпадать с исходной или новее) +GITEA_VERSION="1.25.3" + +# Настройки PostgreSQL +DB_USER="gitea" +DB_NAME="gitea" +DB_PASSWORD="gitea" # ОБЯЗАТЕЛЬНО УКАЖИТЕ РЕАЛЬНЫЙ ПАРОЛЬ! + +# Локальная директория для временных файлов +WORK_DIR="/tmp/gitea-migration-$(date +%Y%m%d)" + +# ============================================ +# ФУНКЦИИ +# ============================================ + +log() { + echo -e "\n\033[1;34m========================================\033[0m" + echo -e "\033[1;34m $1\033[0m" + echo -e "\033[1;34m========================================\033[0m\n" +} + +step() { + echo -e "\033[1;32m[STEP]\033[0m $1" +} + +warn() { + echo -e "\033[1;33m[WARN]\033[0m $1" +} + +error() { + echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 + exit 1 +} + +confirm() { + read -p "$1 [y/N] " response + case "$response" in + [yY][eE][sS]|[yY]) return 0 ;; + *) return 1 ;; + esac +} + +# ============================================ +# ГЛАВНОЕ МЕНЮ +# ============================================ + +show_menu() { + echo "" + echo "==========================================" + echo " Миграция Gitea: Docker VM → LXC" + echo "==========================================" + echo "" + echo " Исходный сервер: $SOURCE_HOST" + echo " Контейнер: $GITEA_CONTAINER" + echo " БД контейнер: $DB_CONTAINER (PostgreSQL)" + echo " Версия Gitea: $GITEA_VERSION" + echo "" + echo " Целевой сервер: $LXC_IP (LXC ID:$LXC_ID на $PROXMOX_HOST)" + echo "" + echo " Этапы миграции:" + echo "" + echo " 1) Проверить подключение к серверам" + echo " 2) Создать бэкап на исходном сервере" + echo " 3) Создать LXC контейнер" + echo " 4) Установить Gitea в LXC" + echo " 5) Перенести бэкап на новый сервер" + echo " 6) Восстановить данные" + echo " 7) Проверить миграцию" + echo "" + echo " 0) Выполнить всё автоматически" + echo " q) Выход" + echo "" + read -p "Выберите действие: " choice + echo "" +} + +# ============================================ +# ЭТАП 1: ПРОВЕРКА ПОДКЛЮЧЕНИЯ +# ============================================ + +check_connections() { + log "Проверка подключений" + + step "Проверка SSH к исходному серверу ($SOURCE_HOST)..." + if ssh -o ConnectTimeout=5 -o BatchMode=yes "$SOURCE_USER@$SOURCE_HOST" "echo OK" 2>/dev/null; then + echo " ✅ Подключение успешно" + else + warn "Не удалось подключиться. Настройте SSH ключи:" + echo " ssh-copy-id $SOURCE_USER@$SOURCE_HOST" + return 1 + fi + + step "Проверка SSH к Proxmox ($PROXMOX_HOST)..." + if ssh -o ConnectTimeout=5 -o BatchMode=yes "$PROXMOX_USER@$PROXMOX_HOST" "echo OK" 2>/dev/null; then + echo " ✅ Подключение успешно" + else + warn "Не удалось подключиться. Настройте SSH ключи:" + echo " ssh-copy-id $PROXMOX_USER@$PROXMOX_HOST" + return 1 + fi + + step "Проверка Docker на исходном сервере..." + if ssh "$SOURCE_USER@$SOURCE_HOST" "docker ps" &>/dev/null; then + echo " ✅ Docker доступен" + echo "" + echo " Контейнеры Gitea:" + if ssh "$SOURCE_USER@$SOURCE_HOST" "docker ps --format ' {{.Names}}\t{{.Image}}\t{{.Status}}' | grep -i gitea"; then + echo "" + else + warn "Контейнеры с 'gitea' в имени не найдены" + echo " Все контейнеры:" + ssh "$SOURCE_USER@$SOURCE_HOST" "docker ps --format ' {{.Names}}\t{{.Image}}'" + fi + + # Проверяем настроенные контейнеры + if ssh "$SOURCE_USER@$SOURCE_HOST" "docker ps --format '{{.Names}}' | grep -q '^${GITEA_CONTAINER}$'"; then + echo " ✅ Контейнер $GITEA_CONTAINER найден" + else + warn "Контейнер $GITEA_CONTAINER не найден! Обновите GITEA_CONTAINER в настройках" + fi + + if [ -n "$DB_CONTAINER" ]; then + if ssh "$SOURCE_USER@$SOURCE_HOST" "docker ps --format '{{.Names}}' | grep -q '^${DB_CONTAINER}$'"; then + echo " ✅ Контейнер БД $DB_CONTAINER найден" + else + warn "Контейнер БД $DB_CONTAINER не найден! Обновите DB_CONTAINER в настройках" + fi + fi + else + warn "Docker не найден или не доступен" + fi + + echo "" + echo "Проверка завершена" +} + +# ============================================ +# ЭТАП 2: БЭКАП +# ============================================ + +create_backup() { + log "Создание бэкапа Gitea" + + step "Копирование скрипта бэкапа на исходный сервер..." + scp "$(dirname $0)/backup-gitea-for-migration.sh" "$SOURCE_USER@$SOURCE_HOST:/tmp/" + + step "Запуск бэкапа..." + # Передаём настройки контейнеров через переменные окружения + ssh "$SOURCE_USER@$SOURCE_HOST" "chmod +x /tmp/backup-gitea-for-migration.sh && \ + GITEA_CONTAINER='$GITEA_CONTAINER' \ + DB_CONTAINER='$DB_CONTAINER' \ + DB_USER='$DB_USER' \ + DB_NAME='$DB_NAME' \ + /tmp/backup-gitea-for-migration.sh" + + step "Получение имени архива..." + BACKUP_FILE=$(ssh "$SOURCE_USER@$SOURCE_HOST" "ls -t /tmp/gitea-backup-*.tar.gz 2>/dev/null | head -1") + + if [ -z "$BACKUP_FILE" ]; then + error "Архив бэкапа не найден" + fi + + echo " Архив: $BACKUP_FILE" + echo "" + echo "Бэкап создан" +} + +# ============================================ +# ЭТАП 3: СОЗДАНИЕ LXC +# ============================================ + +create_lxc() { + log "Создание LXC контейнера" + + step "Копирование скрипта на Proxmox..." + scp "$(dirname $0)/../lxc/create-lxc.sh" "$PROXMOX_USER@$PROXMOX_HOST:/tmp/" + + step "Создание контейнера..." + ssh "$PROXMOX_USER@$PROXMOX_HOST" "chmod +x /tmp/create-lxc.sh && CT_ID=$LXC_ID CT_IP=${LXC_IP}/24 /tmp/create-lxc.sh" + + echo "LXC контейнер создан" +} + +# ============================================ +# ЭТАП 4: УСТАНОВКА GITEA +# ============================================ + +install_gitea() { + log "Установка Gitea в LXC" + + step "Копирование скрипта установки..." + scp "$(dirname $0)/install-gitea-lxc.sh" "$PROXMOX_USER@$PROXMOX_HOST:/tmp/" + + step "Копирование в LXC контейнер..." + ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct push $LXC_ID /tmp/install-gitea-lxc.sh /root/install-gitea-lxc.sh" + + step "Запуск установки (Gitea v$GITEA_VERSION, PostgreSQL)..." + ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct exec $LXC_ID -- bash -c 'chmod +x /root/install-gitea-lxc.sh && \ + GITEA_VERSION=$GITEA_VERSION \ + GITEA_DOMAIN=$LXC_IP \ + DB_USER=$DB_USER \ + DB_NAME=$DB_NAME \ + DB_PASSWORD=$DB_PASSWORD \ + /root/install-gitea-lxc.sh'" + + echo "Gitea установлена" +} + +# ============================================ +# ЭТАП 5: ПЕРЕНОС БЭКАПА +# ============================================ + +transfer_backup() { + log "Перенос бэкапа" + + step "Получение последнего бэкапа..." + BACKUP_FILE=$(ssh "$SOURCE_USER@$SOURCE_HOST" "ls -t /tmp/gitea-backup-*.tar.gz 2>/dev/null | head -1") + + if [ -z "$BACKUP_FILE" ]; then + error "Архив бэкапа не найден. Сначала выполните этап 2" + fi + + step "Скачивание бэкапа локально..." + mkdir -p "$WORK_DIR" + scp "$SOURCE_USER@$SOURCE_HOST:$BACKUP_FILE" "$WORK_DIR/" + + LOCAL_BACKUP="$WORK_DIR/$(basename $BACKUP_FILE)" + + step "Загрузка на Proxmox..." + scp "$LOCAL_BACKUP" "$PROXMOX_USER@$PROXMOX_HOST:/tmp/" + + step "Копирование в LXC контейнер..." + ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct push $LXC_ID /tmp/$(basename $BACKUP_FILE) /tmp/$(basename $BACKUP_FILE)" + + echo "Бэкап перенесён: /tmp/$(basename $BACKUP_FILE)" +} + +# ============================================ +# ЭТАП 6: ВОССТАНОВЛЕНИЕ +# ============================================ + +restore_data() { + log "Восстановление данных" + + step "Копирование скрипта восстановления..." + scp "$(dirname $0)/restore-gitea.sh" "$PROXMOX_USER@$PROXMOX_HOST:/tmp/" + ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct push $LXC_ID /tmp/restore-gitea.sh /root/restore-gitea.sh" + + step "Получение имени бэкапа в LXC..." + BACKUP_IN_LXC=$(ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct exec $LXC_ID -- ls -t /tmp/gitea-backup-*.tar.gz 2>/dev/null | head -1") + + if [ -z "$BACKUP_IN_LXC" ]; then + error "Бэкап не найден в LXC. Сначала выполните этап 5" + fi + + step "Запуск восстановления..." + ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct exec $LXC_ID -- bash -c 'chmod +x /root/restore-gitea.sh && NEW_DOMAIN=$LXC_IP /root/restore-gitea.sh $BACKUP_IN_LXC'" + + echo "Данные восстановлены" +} + +# ============================================ +# ЭТАП 7: ПРОВЕРКА +# ============================================ + +verify_migration() { + log "Проверка миграции" + + step "Проверка статуса Gitea..." + ssh "$PROXMOX_USER@$PROXMOX_HOST" "pct exec $LXC_ID -- systemctl status gitea --no-pager" || true + + step "Проверка доступности веб-интерфейса..." + if curl -s --connect-timeout 5 "http://$LXC_IP:3000" | grep -q "Gitea"; then + echo " ✅ Веб-интерфейс доступен" + else + warn "Веб-интерфейс недоступен. Проверьте логи:" + echo " ssh $PROXMOX_USER@$PROXMOX_HOST 'pct exec $LXC_ID -- journalctl -u gitea -n 50'" + fi + + echo "" + echo "==========================================" + echo " Миграция завершена!" + echo "==========================================" + echo "" + echo " Gitea доступна: http://$LXC_IP:3000" + echo "" + echo " Не забудьте:" + echo " - Проверить авторизацию" + echo " - Проверить репозитории" + echo " - Обновить DNS записи" + echo " - Обновить git remote на клиентах" + echo "" +} + +# ============================================ +# MAIN +# ============================================ + +mkdir -p "$WORK_DIR" + +while true; do + show_menu + + case "$choice" in + 1) check_connections ;; + 2) create_backup ;; + 3) create_lxc ;; + 4) install_gitea ;; + 5) transfer_backup ;; + 6) restore_data ;; + 7) verify_migration ;; + 0) + log "Полная автоматическая миграция" + if confirm "Начать полную миграцию?"; then + check_connections || exit 1 + create_backup + create_lxc + install_gitea + transfer_backup + restore_data + verify_migration + fi + ;; + q|Q) + echo "Выход" + exit 0 + ;; + *) + echo "Неверный выбор" + ;; + esac + + echo "" + read -p "Нажмите Enter для продолжения..." +done diff --git a/migration-scripts/install-gitea-lxc.sh b/migration-scripts/install-gitea-lxc.sh new file mode 100755 index 0000000..6f73fab --- /dev/null +++ b/migration-scripts/install-gitea-lxc.sh @@ -0,0 +1,260 @@ +#!/bin/bash +# +# Скрипт установки Gitea в LXC контейнере +# Запускать внутри LXC контейнера +# База данных: PostgreSQL +# + +set -e + +# ============================================ +# НАСТРОЙКИ +# ============================================ + +# Версия Gitea (должна совпадать с версией из бэкапа!) +# Проверьте актуальную на https://github.com/go-gitea/gitea/releases +GITEA_VERSION="${GITEA_VERSION:-1.25.3}" + +# Порт Gitea +GITEA_PORT="${GITEA_PORT:-3000}" + +# SSH порт для Git +GITEA_SSH_PORT="${GITEA_SSH_PORT:-22}" + +# Домен/IP сервера (обновите на свой) +GITEA_DOMAIN="${GITEA_DOMAIN:-$(hostname -I | awk '{print $1}')}" + +# PostgreSQL настройки +DB_HOST="${DB_HOST:-127.0.0.1}" +DB_PORT="${DB_PORT:-5432}" +DB_USER="${DB_USER:-gitea}" +DB_NAME="${DB_NAME:-gitea}" +DB_PASSWORD="${DB_PASSWORD:-gitea}" + +# ============================================ +# ФУНКЦИИ +# ============================================ + +log() { + echo -e "\033[1;32m[$(date '+%H:%M:%S')]\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" +fi + +log "=== Установка Gitea v${GITEA_VERSION} ===" +log "Домен: $GITEA_DOMAIN" +log "Порт: $GITEA_PORT" +log "База данных: PostgreSQL ($DB_USER@$DB_NAME)" + +# ============================================ +# УСТАНОВКА ЗАВИСИМОСТЕЙ +# ============================================ + +log "Обновление системы..." +apt update && apt upgrade -y + +log "Установка зависимостей..." +apt install -y git curl wget ca-certificates gnupg unzip + +# ============================================ +# УСТАНОВКА POSTGRESQL +# ============================================ + +log "Установка PostgreSQL..." +apt install -y postgresql postgresql-contrib +systemctl enable postgresql +systemctl start postgresql + +# Создание пользователя и БД +log "Создание пользователя и базы данных PostgreSQL..." +sudo -u postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASSWORD';" 2>/dev/null || \ + log " Пользователь $DB_USER уже существует" +sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;" 2>/dev/null || \ + log " База данных $DB_NAME уже существует" +sudo -u postgres psql -c "ALTER USER $DB_USER WITH SUPERUSER;" 2>/dev/null || true +log " ✓ PostgreSQL настроен: $DB_USER@$DB_NAME" + +# ============================================ +# СОЗДАНИЕ ПОЛЬЗОВАТЕЛЯ GIT +# ============================================ + +log "Создание пользователя git..." +if ! id "git" &>/dev/null; then + adduser --system --shell /bin/bash --gecos 'Git Version Control' \ + --group --disabled-password --home /home/git git +fi + +# ============================================ +# СОЗДАНИЕ ДИРЕКТОРИЙ +# ============================================ + +log "Создание директорий..." +mkdir -p /var/lib/gitea/{custom,data,log} +mkdir -p /var/lib/gitea/data/gitea-repositories +mkdir -p /etc/gitea + +chown -R git:git /var/lib/gitea +chown root:git /etc/gitea +chmod 770 /etc/gitea + +# ============================================ +# СКАЧИВАНИЕ GITEA +# ============================================ + +log "Скачивание Gitea v${GITEA_VERSION}..." +GITEA_URL="https://dl.gitea.io/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64" + +wget -q --show-progress -O /usr/local/bin/gitea "$GITEA_URL" +chmod +x /usr/local/bin/gitea + +# Проверка +INSTALLED_VERSION=$(/usr/local/bin/gitea --version 2>&1 | head -1) +log "Установлено: $INSTALLED_VERSION" + +# ============================================ +# SYSTEMD СЕРВИС +# ============================================ + +log "Создание systemd сервиса..." +cat > /etc/systemd/system/gitea.service << 'EOF' +[Unit] +Description=Gitea (Git with a cup of tea) +After=syslog.target +After=network.target +After=postgresql.service + +[Service] +RestartSec=2s +Type=simple +User=git +Group=git +WorkingDirectory=/var/lib/gitea/ +ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini +Restart=always +Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea + +[Install] +WantedBy=multi-user.target +EOF + +# ============================================ +# БАЗОВАЯ КОНФИГУРАЦИЯ +# ============================================ + +log "Создание базовой конфигурации..." + +cat > /etc/gitea/app.ini << EOF +APP_NAME = Gitea: Git with a cup of tea +RUN_USER = git +RUN_MODE = prod +WORK_PATH = /var/lib/gitea + +[database] +DB_TYPE = postgres +HOST = ${DB_HOST}:${DB_PORT} +NAME = $DB_NAME +USER = $DB_USER +PASSWD = $DB_PASSWORD +SSL_MODE = disable +LOG_SQL = false + +[repository] +ROOT = /var/lib/gitea/data/gitea-repositories + +[server] +DOMAIN = $GITEA_DOMAIN +HTTP_PORT = $GITEA_PORT +ROOT_URL = http://$GITEA_DOMAIN:$GITEA_PORT/ +DISABLE_SSH = false +SSH_DOMAIN = $GITEA_DOMAIN +SSH_PORT = $GITEA_SSH_PORT +SSH_LISTEN_PORT = $GITEA_SSH_PORT +LFS_START_SERVER = true +LFS_CONTENT_PATH = /var/lib/gitea/data/lfs +OFFLINE_MODE = false + +[mailer] +ENABLED = false + +[service] +REGISTER_EMAIL_CONFIRM = false +ENABLE_NOTIFY_MAIL = false +DISABLE_REGISTRATION = false +ALLOW_ONLY_EXTERNAL_REGISTRATION = false +ENABLE_CAPTCHA = false +REQUIRE_SIGNIN_VIEW = false +DEFAULT_KEEP_EMAIL_PRIVATE = false +DEFAULT_ALLOW_CREATE_ORGANIZATION = true +DEFAULT_ENABLE_TIMETRACKING = true +NO_REPLY_ADDRESS = noreply.$GITEA_DOMAIN + +[openid] +ENABLE_OPENID_SIGNIN = true +ENABLE_OPENID_SIGNUP = true + +[session] +PROVIDER = file + +[log] +MODE = console +LEVEL = info +ROOT_PATH = /var/lib/gitea/log + +[security] +INSTALL_LOCK = false +EOF + +chown root:git /etc/gitea/app.ini +chmod 640 /etc/gitea/app.ini + +# ============================================ +# ЗАПУСК СЕРВИСА +# ============================================ + +log "Запуск Gitea..." +systemctl daemon-reload +systemctl enable gitea +systemctl start gitea + +# Ждём запуска +sleep 3 + +# Проверяем статус +if systemctl is-active --quiet gitea; then + log "✅ Gitea успешно запущена!" +else + error "Gitea не запустилась. Проверьте: journalctl -u gitea -e" +fi + +# ============================================ +# ИТОГИ +# ============================================ + +echo "" +echo "==========================================" +echo " Gitea установлена!" +echo "==========================================" +echo "" +echo " Web UI: http://$GITEA_DOMAIN:$GITEA_PORT" +echo " SSH: git@$GITEA_DOMAIN" +echo "" +echo " Первый пользователь станет администратором." +echo "" +echo " Конфигурация: /etc/gitea/app.ini" +echo " Данные: /var/lib/gitea/" +echo " Логи: journalctl -u gitea -f" +echo "" +echo "==========================================" + +# Для миграции: установить INSTALL_LOCK = true после восстановления diff --git a/migration-scripts/lxc/create-lxc.sh b/migration-scripts/lxc/create-lxc.sh new file mode 100755 index 0000000..8053890 --- /dev/null +++ b/migration-scripts/lxc/create-lxc.sh @@ -0,0 +1,159 @@ +#!/bin/bash +# +# Скрипт создания LXC контейнера для Gitea на Proxmox +# Запускать на хосте Proxmox (192.168.0.33) +# + +set -e + +# ============================================ +# НАСТРОЙКИ LXC КОНТЕЙНЕРА +# ============================================ + +# ID контейнера (проверьте что не занят) +CT_ID="${CT_ID:-300}" + +# Hostname +CT_HOSTNAME="${CT_HOSTNAME:-gitea}" + +# Ресурсы +CT_MEMORY="${CT_MEMORY:-2048}" +CT_CORES="${CT_CORES:-2}" +CT_DISK="${CT_DISK:-20}" + +# Сеть +CT_IP="${CT_IP:-192.168.0.40/24}" +CT_GW="${CT_GW:-192.168.0.1}" +CT_BRIDGE="${CT_BRIDGE:-vmbr0}" + +# Storage для rootfs и шаблонов +CT_STORAGE="${CT_STORAGE:-local-zfs}" +TEMPLATE_STORAGE="${TEMPLATE_STORAGE:-local}" + +# Шаблон (Debian 12 - актуальная версия) +# Доступные варианты: +# debian-12-standard_12.12-1_amd64.tar.zst - чистый Debian 12 (рекомендуется) +# debian-13-standard_13.1-2_amd64.tar.zst - Debian 13 (testing) +# ubuntu-24.04-standard_24.04-2_amd64.tar.zst - Ubuntu 24.04 LTS +# НЕ используйте debian-12-turnkey-gitea - он для новой установки, не для миграции +CT_TEMPLATE="${CT_TEMPLATE:-debian-12-standard_12.12-1_amd64.tar.zst}" + +# Пароль root (ОБЯЗАТЕЛЬНО ИЗМЕНИТЕ!) +CT_PASSWORD="${CT_PASSWORD:-ChangeMe123!}" + +# ============================================ +# ФУНКЦИИ +# ============================================ + +log() { + echo -e "\033[1;32m[$(date '+%H:%M:%S')]\033[0m $1" +} + +error() { + echo -e "\033[1;31m[ERROR]\033[0m $1" >&2 + exit 1 +} + +# ============================================ +# ПРОВЕРКИ +# ============================================ + +# Проверяем что мы на Proxmox +if ! command -v pct &> /dev/null; then + error "Этот скрипт должен запускаться на Proxmox хосте" +fi + +# Проверяем что ID не занят +if pct status "$CT_ID" &> /dev/null; then + error "Контейнер с ID $CT_ID уже существует" +fi + +log "=== Создание LXC контейнера для Gitea ===" +log "ID: $CT_ID" +log "Hostname: $CT_HOSTNAME" +log "IP: $CT_IP" +log "Memory: ${CT_MEMORY}MB" +log "Disk: ${CT_DISK}GB" + +# ============================================ +# СКАЧИВАНИЕ ШАБЛОНА (если нет) +# ============================================ + +TEMPLATE_PATH="/var/lib/vz/template/cache/$CT_TEMPLATE" +if [ ! -f "$TEMPLATE_PATH" ]; then + log "Скачивание шаблона $CT_TEMPLATE..." + pveam update + pveam download "$TEMPLATE_STORAGE" "$CT_TEMPLATE" +fi + +# ============================================ +# СОЗДАНИЕ КОНТЕЙНЕРА +# ============================================ + +log "Создание контейнера..." +pct create "$CT_ID" "${TEMPLATE_STORAGE}:vztmpl/${CT_TEMPLATE}" \ + --hostname "$CT_HOSTNAME" \ + --password "$CT_PASSWORD" \ + --memory "$CT_MEMORY" \ + --cores "$CT_CORES" \ + --rootfs "${CT_STORAGE}:${CT_DISK}" \ + --net0 "name=eth0,bridge=${CT_BRIDGE},ip=${CT_IP},gw=${CT_GW}" \ + --features "nesting=1" \ + --unprivileged 1 \ + --onboot 1 + +# ============================================ +# ЗАПУСК КОНТЕЙНЕРА +# ============================================ + +log "Запуск контейнера..." +pct start "$CT_ID" +sleep 5 + +# Проверка +if pct status "$CT_ID" | grep -q "running"; then + log "✅ Контейнер запущен" +else + error "Контейнер не запустился" +fi + +# ============================================ +# БАЗОВАЯ НАСТРОЙКА +# ============================================ + +log "Базовая настройка контейнера..." + +# Обновление системы +pct exec "$CT_ID" -- bash -c "apt update && apt upgrade -y" + +# Установка базовых пакетов +pct exec "$CT_ID" -- bash -c "apt install -y curl wget git sudo" + +# ============================================ +# ИТОГИ +# ============================================ + +# Получаем IP (без маски) +CT_IP_CLEAN=$(echo "$CT_IP" | cut -d'/' -f1) + +echo "" +echo "==========================================" +echo " LXC контейнер создан!" +echo "==========================================" +echo "" +echo " ID: $CT_ID" +echo " Hostname: $CT_HOSTNAME" +echo " IP: $CT_IP_CLEAN" +echo "" +echo " Вход в контейнер:" +echo " pct enter $CT_ID" +echo " или: ssh root@$CT_IP_CLEAN" +echo "" +echo " Следующий шаг:" +echo " Скопируйте install-gitea-lxc.sh в контейнер" +echo " и запустите его для установки Gitea" +echo "" +echo " pct push $CT_ID /path/to/install-gitea-lxc.sh /root/install-gitea-lxc.sh" +echo " pct exec $CT_ID -- bash /root/install-gitea-lxc.sh" +echo "" +echo "==========================================" diff --git a/migration-scripts/restore-gitea.sh b/migration-scripts/restore-gitea.sh new file mode 100755 index 0000000..c842558 --- /dev/null +++ b/migration-scripts/restore-gitea.sh @@ -0,0 +1,494 @@ +#!/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 "==========================================" diff --git a/migration-scripts/systemd/gitea.service b/migration-scripts/systemd/gitea.service new file mode 100644 index 0000000..e134c1c --- /dev/null +++ b/migration-scripts/systemd/gitea.service @@ -0,0 +1,42 @@ +[Unit] +Description=Gitea (Git with a cup of tea) +After=syslog.target +After=network.target +### +# Uncomment the appropriate line based on your database +### +#After=mysql.service +#After=mariadb.service +#After=postgresql.service + +[Service] +# Modify these two values and uncomment them if you have +# temporary files that need to persist after restart +#ExecStartPre=+/bin/rm -rf /run/gitea +#ExecStartPre=+/bin/mkdir -p /run/gitea + +# Чтобы использовать Systemd tmp.d / журнал: +# RuntimeDirectory=gitea +# Type=notify + +Type=simple +User=git +Group=git +WorkingDirectory=/var/lib/gitea/ + +# Путь к бинарнику и конфигурации +ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini + +Restart=always +RestartSec=2s + +# Окружение +Environment=USER=git HOME=/home/git GITEA_WORK_DIR=/var/lib/gitea + +# Hardening (опционально, но рекомендуется) +CapabilityBoundingSet=CAP_NET_BIND_SERVICE +AmbientCapabilities=CAP_NET_BIND_SERVICE +NoNewPrivileges=true + +[Install] +WantedBy=multi-user.target