Резервное копирование и восстановление сервера Gitea
Резервное копирование и восстановление Gitea правильным способом
Резервные копии Gitea затрагивают три подвижные части — базу данных, git-репозитории и файлы приложения — и с 2024 года встроенная команда gitea dump обрабатывает все их одним разом.

В статье Тестирование Gitea мы установили сервер gitea. Это продолжение: как именно создать резервную копию и, что более важно, восстановить её, когда что-то пойдёт не так.
Для полного сбора инструментов для разработчиков, включая рабочие процессы Git и управление Docker, см. Инструменты разработчика: Полное руководство по современным рабочим процессам разработки.
Если вы устанавливаете Gitea впервые, ознакомьтесь со статьёй Выбор бесплатного git-сервера для локального размещения — Gitea побеждает! для деталей установки и Gitea SSL с Apache в качестве reverse proxy для безопасного развертывания.
Когда стоит отрепетировать это
Теперь, в качестве меры предосторожности от неприятностей, — подходящее время, чтобы отрепетировать процедуру создания резервной копии и восстановления — до того, как вы действительно в этом нуждаетесь, а не после того, как выйдет из строя диск.
Лучше перестраховаться, чем сожалеть.
Где хранятся данные
Инстанс Gitea по сути состоит из трёх компонентов, которые должны оставаться синхронизированными:
- код (git-репозитории)
- файловое хранилище (вложения, аватары, объекты LFS, индексаторы)
- база данных (пользователи, задачи, PR, настройки)
В нашей тестовой среде вместе они занимают чуть более 700 МБ:

Поскольку эти три части ссылаются друг на друга, собственные документация Gitea чётко указывает на согласованность резервного копирования: инстанс должен быть остановлен на время создания резервной копии, иначе репозиторий, скопированный во время миграции, может оказаться несинхронизированным с тем, что, по мнению базы данных, произошло. Восстановление, по той же причине, тоже должно происходить как одна транзакция.
Простой способ — gitea dump
Это та часть, которая изменилась с предыдущей версии данной статьи: вместо ручной манипуляции с pg_dump, tar и отдельными папками, Gitea предоставляет единственную команду dump, которая упаковывает базу данных, репозитории, данные LFS, вложения и конфигурацию в один архив.
gitea dump -c /path/to/app.ini
Это создаёт файл с меткой времени, например gitea-dump-1610949662.zip, содержащий:
app.ini— копия файла конфигурацииcustom/— пользовательские настройки вcustom/data/— вложения, аватары, объекты LFS, индексаторы (и файл SQLite, если это ваша база данных)repos/— полная копия каталога репозиториевgitea-db.sql— SQL-дамп базы данныхlog/— логи (не нужны для восстановления)
Полезные флаги, о которых стоит знать:
--file name/-f name— имя выходного файла (-для stdout, удобно для прямой передачи черезscpили в объектное хранилище)--type— формат вывода:zip(по умолчанию),tar,tar.gz,tar.xz,tar.zstи т. д.--database/-d— принудительное задание SQL-диалекта вgitea-db.sql(sqlite3,mysql,mssql,postgres) — полезно при миграции между движками баз данных--skip-repository/-R,--skip-lfs-data,--skip-attachment-data,--skip-package-data,--skip-log,--skip-db— уменьшают дамп до того, что вам действительно нужно--tempdir/-t— место, где размещаются промежуточные файлы (по умолчанию/tmpили$TMPDIR) — убедитесь, что там достаточно свободного места для всего инстанса
Запуск gitea dump в Docker
Поскольку большинство self-hosted установок запускают Gitea через docker-compose, команда должна выполняться внутри контейнера, от пользователя git, из временного каталога контейнера:
cd ~/gitea-srv-local
# создать дамп внутри работающего контейнера
sudo docker exec -u git -it -w /tmp gitea bash -c \
'/usr/local/bin/gitea dump -c /data/gitea/conf/app.ini'
# скопировать полученный zip-файл из контейнера
sudo docker cp gitea:/tmp/gitea-dump-*.zip ./gitea-backups/
-w /tmp важен: dump должен писать и упаковывать свой временный рабочий каталог, и запуск его в любом месте без прав на запись приведёт к ошибке доступа.
Затем, как и раньше, заберите архив с машины:
scp uname@gitea-srv-ip-addr:~/gitea-srv-local/gitea-backups/gitea-dump-*.zip ~/gitea-backups/
Если вы предпочитаете дампировать базу данных с помощью нативных инструментов (собственная документация Gitea рекомендует это для MySQL/PostgreSQL, так как SQL-дамп на базе XORM внутри gitea dump имеет известные пограничные случаи при восстановлении), вы всё ещё можете сделать это параллельно:
sudo docker exec -t gitea-srv-local_db_1 bash -c \
'pg_dump gitea -U gitea --file=/var/lib/postgresql/backups/gitea-db-$(date +%Y-%m-%d).sql'
См. Шпаргалка по PostgreSQL для дополнительных вариантов pg_dump/pg_restore, а Шпаргалка по Docker Compose, если какой-либо из синтаксиса docker exec/docker cp выше кажется вам незнакомым.
Как — Восстановление
По-прежнему нет однокомандного восстановления — документация Gitea прямо говорит, что это остаётся ручным процессом возврата файлов на место и восстановления дампа базы данных. Но! Всегда сначала проверяйте оригинальную документацию, так как пути и структура контейнеров меняются от выпуска к выпуску.
# установить/запустить свежий gitea (та же версия, что и в резервной копии), затем остановить его
sudo docker-compose down
# распаковать дамп
unzip gitea-dump-1610949662.zip -d gitea-restore
cd gitea-restore
# восстановить репозитории и данные в том, который использует gitea
sudo cp -r repos/* ../gitea/git/
sudo cp -r data/* ../gitea/gitea/
sudo chown -R 1000:1000 ../gitea/git ../gitea/gitea
# запустить gitea обратно
sudo docker-compose up -d
# восстановить базу данных
sudo docker exec -i gitea-srv-local_db_1 psql -U gitea gitea < gitea-db.sql
Если вы дампировали базу данных отдельно с помощью pg_dump/pg_restore, восстановите этот дамп так же, как для любого другого инстанса Postgres — см. Шпаргалка по PostgreSQL для точных команд.
Пересоздание хуков после восстановления
Если вы восстановили данные в другую систему установки (бинарный файл против Docker) или в другой путь, git-хуки, встроенные в каждый репозиторий, всё ещё будут указывать на старые пути. Исправьте это с помощью:
sudo docker exec -u git -it gitea bash -c '/usr/local/bin/gitea admin regenerate hooks'
Пропуск этого шага — классическая причина того, что push начинает работать после восстановления без очевидной ошибки в интерфейсе.
Проверка восстановления
Прежде чем считать работу выполненной:
- Войдите в интерфейс и подтвердите, что пользователи, задачи и настройки выглядят правильно.
- Клонируйте один репозиторий и отправьте простой коммит, чтобы убедиться, что хуки работают.
- Запустите
gitea doctor check(добавьте--fix, если он укажет на что-то), чтобы заранее обнаружить несовпадения путей или прав.
Восстановление отдельного репозитория — restore-repo
Другая по-настоящему новая часть с последней версии данной статьи — это пара команд для резервного копирования и восстановления на уровне репозитория, отдельно от рабочего процесса dump/восстановления всего инстанса выше. Они полезны, когда вам нужно восстановить только один проект — например, кто-то принудительно удалил репозиторий — вместо отката всего сервера.
dump-repo извлекает отдельный репозиторий (а также, по желанию, его задачи, PR, вики и другую метаданные) в локальный каталог:
gitea dump-repo \
--git_service gitea \
--clone_addr https://gitea.example.com/owner/repo.git \
--auth_token <token> \
--repo_dir /backup/repos/owner/repo \
--units wiki,issues,labels,releases,milestones,pull_requests,comments
Затем restore-repo воспроизводит этот каталог обратно в инстансе, в выбранном owner/repo:
gitea restore-repo \
--repo_dir /backup/repos/owner/repo \
--owner_name owner \
--repo_name repo \
--units issues,labels,milestones,pull_requests,comments
Оба списка --units необязательны — если их опустить, будет перемещено всё поддерживаемое. По сути, эта пара является инструментом миграции (она также работает с GitHub/GitLab в качестве источника через --git_service), но прекрасно служит лёгкой альтернативой полному gitea dump на уровне отдельного репозитория, когда полное восстановление было бы избыточным.
Автоматизация
Ежедневный дамп плюс копия на другой машине — это двухстрочный cron-задачник, как только вышеуказанные ручные шаги заработают:
# /etc/cron.d/gitea-backup
0 2 * * * root docker exec -u git -w /tmp gitea gitea dump -c /data/gitea/conf/app.ini -f - > /home/uname/gitea-backups/gitea-dump-$(date +\%F).zip 2>> /var/log/gitea-backup.log
Сочетайте это с очисткой по сроку хранения (find ~/gitea-backups -mtime +14 -delete) и копированием в внешнее место через scp/rsync, чтобы отказ одного хоста не уничтожил резервные копии.
Устранение неполадок
permission deniedпри выполненииdump— вы не выполняете команду от пользователяgit, либо--tempdir/-wуказывает на каталог, в который пользователь контейнера не может писать.- Восстановление удалось, но
git pushне работает — хуки не были пересозданы; выполнитеgitea admin regenerate hooks. - Ошибки восстановления базы данных на большом инстансе — предпочитайте нативные
pg_dump/mysqldumpвложенному SQL в zip-файлеgitea dump; известно, что он имеет шероховатости при восстановлении для больших или необычных схем. - Восстановление в новую основную версию — выполните
gitea doctor check --all --fixи проверьте примечания к выпуску для шагов миграции той версии, прежде чем считать восстановление завершённым.
Для быстрого справочника по командам Git, см. Шпаргалка по GIT: Наиболее полезные команды GIT.