gitea dump rassemble les dépôts Git, la base de données, la configuration et
les fichiers LFS dans une seule archive ZIP. L'instance doit être arrêtée pendant
le dump, faute de quoi l'archive n'est pas garantie cohérente. La restauration est
manuelle mais déterministe.
Le cycle complet de ce guide, sauvegarde puis destruction puis restauration, a été rejoué sur Gitea 1.27.3 avec SQLite3 comme base de données. Les étapes sont identiques pour PostgreSQL ou MySQL, sauf pour la restauration de la base.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Identifier ce que l'archive
gitea dumpembarque, et ce qu'elle laisse dehors - Produire une sauvegarde cohérente, instance arrêtée
- Automatiser le cycle par une tâche
cronqui tourne sous le bon compte - Restaurer dans l'ordre qu'impose
app.ini, configuration avant dépôts - Prouver la restauration autrement qu'en regardant la taille de l'archive
Ce que contient une sauvegarde
Section intitulée « Ce que contient une sauvegarde »Une archive gitea dump est autoportante : elle réunit tout ce qu'il faut
pour reconstruire l'instance, et il n'y a rien d'autre à sauvegarder à côté.
Le tableau ci-dessous sert à vérifier qu'une archive est complète avant de
la juger bonne.
| Contenu | Chemin source | Rôle |
|---|---|---|
| Dépôts Git | REPOSITORY ROOT | Tous les dépôts bare |
| Base de données | data/gitea.db | Données applicatives (users, issues, PRs...) |
| Fichiers LFS | data/lfs/ | Objets Git LFS |
| Configuration | app.ini | Paramètres de l'instance |
| Paquets | data/packages/ | Registre de paquets |
| Données | data/ | Autres données (avatars, attachements...) |
La ligne app.ini compte autant que les autres. Ce fichier porte
SECRET_KEY, la clé qui chiffre les données sensibles en base, dont les
secrets à deux facteurs : perdue, elles sont indéchiffrables. Il porte aussi
trois jetons d'authentification, INTERNAL_TOKEN pour la communication
interne, JWT_SECRET pour OAuth2 et LFS_JWT_SECRET pour LFS. Une archive
Gitea est donc elle-même un secret, à stocker et à transférer comme tel.
Préparer le répertoire de backup
Section intitulée « Préparer le répertoire de backup »Les archives se déposent dans un répertoire qui appartient à git, le
compte sous lequel tourne le dump. Le mode 750 le ferme aux autres
utilisateurs de la machine, ce qui découle directement du point précédent :
une archive qui contient les secrets de l'instance n'a rien à faire dans un
répertoire lisible par tous.
# Créer le répertoire dédié aux archivessudo mkdir -p /var/lib/gitea/backupssudo chown git:git /var/lib/gitea/backupssudo chmod 750 /var/lib/gitea/backupsCréer une sauvegarde
Section intitulée « Créer une sauvegarde »L'instance doit être arrêtée pendant le dump. La documentation Gitea est explicite sur ce point : « To ensure the consistency of the Gitea instance, it must be shutdown during backup ». La raison est une course entre la base de données et les dépôts. Pendant une migration ou un simple push, une transaction s'écrit en base pendant que le dépôt Git est copié : l'archive contient alors une base qui affirme l'existence d'un dépôt incomplet. Le dump se termine sans erreur, et l'incohérence ne se découvre qu'à la restauration.
# 1. Arrêter l'instance : sans cela, la cohérence n'est pas garantiesudo systemctl stop gitea.service
# 2. Dump, en tant qu'utilisateur gitsudo -u git GITEA_WORK_DIR=/var/lib/gitea \ gitea dump \ --config /etc/gitea/app.ini \ --work-path /var/lib/gitea \ --file /var/lib/gitea/backups/gitea-$(date +%Y%m%d-%H%M%S).zip \ --type zip
# 3. Redémarrer, puis confirmer que le service répondsudo systemctl start gitea.servicesudo systemctl is-active gitea.serviceLa fenêtre d'indisponibilité dure le temps du dump, quelques secondes sur une petite forge, plusieurs minutes dès que les dépôts pèsent. Si cette interruption n'est pas acceptable, la parade n'est pas de dumper à chaud : elle consiste à prendre un instantané cohérent au niveau du stockage (LVM, ZFS, volume cloud) et de la base de données, puis à dumper depuis cet instantané.
La commande affiche la progression et se termine par :
Finish dumping in file /var/lib/gitea/backups/gitea-20260328-194600.zipL'archive réunit la configuration, les données, les dépôts et un
dump SQL de la base. Ce dernier, gitea-db.sql, est présent même avec
SQLite, où le fichier .db figure déjà sous data/ : une restauration peut
donc repartir de l'un ou de l'autre, ce qui compte quand la base est
corrompue plutôt que perdue.
Vérifiez le contenu de l'archive :
sudo -u git unzip -l /var/lib/gitea/backups/gitea-20260328-194600.zip | head -20Automatiser avec cron
Section intitulée « Automatiser avec cron »Une commande unique en crontab ne convient pas ici, puisque la sauvegarde
suppose d'arrêter puis de redémarrer le service. Un gitea dump lancé seul
dans cron automatiserait la procédure incohérente décrite plus haut, et un
échec au milieu laisserait la forge arrêtée jusqu'au lendemain. On passe
donc par un script, dont le trap garantit le redémarrage même en cas
d'erreur.
#!/usr/bin/env bashset -euo pipefail
DEST=/var/lib/gitea/backupsARCHIVE="$DEST/gitea-$(date +%Y%m%d-%H%M%S).zip"
# Quoi qu'il arrive ensuite, la forge redémarre : une sauvegarde ratée ne# doit jamais se solder par une indisponibilité prolongée.trap 'systemctl start gitea.service' EXIT
systemctl stop gitea.servicesudo -u git GITEA_WORK_DIR=/var/lib/gitea \ gitea dump --config /etc/gitea/app.ini \ --work-path /var/lib/gitea --file "$ARCHIVE" --type zip
# Relire ce qu'on vient d'écrire : une archive illisible n'est pas une# sauvegarde, et `unzip -t` le dit tout de suite.unzip -t "$ARCHIVE" > /dev/null
find "$DEST" -name 'gitea-*.zip' -mtime +30 -deleteCe script tourne en root, et non sous le compte git : il arrête et
redémarre le service, ce qu'un utilisateur non privilégié ne peut pas faire.
Une tâche posée dans la crontab de git sortirait dès la première ligne, sur
un refus de systemd. Le répertoire /etc/cron.d/ règle le problème, puisque
son format porte l'utilisateur d'exécution en sixième colonne :
sudo chmod 750 /usr/local/bin/gitea-backup.sh# Sauvegarde Gitea quotidienne à 2h00, exécutée en root0 2 * * * root /usr/local/bin/gitea-backup.sh >> /var/log/gitea-backup.log 2>&1Le lendemain, c'est le journal qui dit si la tâche a tourné, et l'archive qui dit si elle a réussi. Contrôlez les deux, car une tâche qui ne se déclenche pas ne laisse aucune trace ailleurs :
sudo tail -n 20 /var/log/gitea-backup.logls -lh /var/lib/gitea/backups/Restaurer depuis une sauvegarde
Section intitulée « Restaurer depuis une sauvegarde »La restauration reconstruit l'instance à partir de l'archive, et c'est le seul moyen de prouver que la sauvegarde vaut quelque chose : un dump qui se termine sans erreur ne dit rien de sa restaurabilité. Elle suppose que
Gitea est déjà installé (binaire + service systemd), mais non configuré (pas d'app.ini).
-
Arrêter le service
Fenêtre de terminal sudo systemctl stop gitea.service -
Vider les répertoires de données existants
Fenêtre de terminal sudo rm -rf /var/lib/gitea/datasudo rm -rf /etc/gitea/app.iniLes dépôts partent avec
data/, puisque Gitea les y range par défaut. Si votreapp.inidéclare unROOThors dedata/, supprimez aussi ce répertoire : l'étape 6 explique comment le lire.Ces répertoires sont recréés aux étapes 5 et 6, et c'est cette recréation qu'on saute le plus volontiers. Sans elle, les copies échouent sur
No such file or directory, la restauration ne dépose rien, et le service redémarre quand même : vous croyez avoir restauré une forge, vous avez redémarré une forge vide. -
Extraire l'archive
Fenêtre de terminal # Créer un répertoire temporaire pour l'extractionsudo -u git mkdir -p /tmp/gitea-restoresudo -u git unzip /var/lib/gitea/backups/gitea-20260328-194600.zip \-d /tmp/gitea-restore -
Restaurer la configuration, avant tout le reste
L'ordre compte :
app.iniporte le chemin des dépôts, dont l'étape 6 a besoin.Fenêtre de terminal sudo cp /tmp/gitea-restore/app.ini /etc/gitea/app.inisudo chown root:git /etc/gitea/app.inisudo chmod 660 /etc/gitea/app.ini # 660 pour le 1er démarrage post-restauration -
Recréer le répertoire de données, puis le remplir
install -dpose le répertoire avec son propriétaire et ses droits en une commande, là où unmkdirlaisserait un répertoire appartenant àrootque Gitea ne saurait pas écrire. Le point final dedata/.copie le contenu du répertoire, fichiers cachés compris, et non le répertoire lui-même.Fenêtre de terminal sudo install -d -o git -g git -m 750 /var/lib/gitea/datasudo cp -a /tmp/gitea-restore/data/. /var/lib/gitea/data/Avec SQLite, cette seule commande restaure aussi la base, puisque
gitea.dbvit sousdata/. Avec PostgreSQL ou MySQL, il faut en plus rejouergitea-db.sqldans une base vide, avecpsqloumysql. -
Restaurer les dépôts à l'emplacement que déclare
app.iniPar défaut, Gitea range les dépôts sous
data/, dansdata/gitea-repositories: la cléROOTde la section[repository]vaut{APP_DATA_PATH}/gitea-repositories, etAPP_DATA_PATHvaut lui-mêmedata/. Beaucoup d'installations déclarent pourtant un autre chemin. Plutôt que d'en recopier un, lisez celui que votre configuration déclare :Fenêtre de terminal ROOT=$(sudo grep -A20 '^\[repository\]' /etc/gitea/app.ini \| sed -n 's/^ROOT *= *//p' | head -1)ROOT=${ROOT:-/var/lib/gitea/data/gitea-repositories}echo "$ROOT"sudo install -d -o git -g git -m 750 "$ROOT"sudo cp -a /tmp/gitea-restore/repos/. "$ROOT"/sudo chown -R git:git /var/lib/gitea/data "$ROOT"Le repli couvre le cas où la clé
ROOTn'est pas écrite dansapp.ini: Gitea applique alors son défaut,data/gitea-repositories. Se tromper de chemin ici ne produit aucune erreur : les dépôts atterrissent là où Gitea ne les lit jamais, le service redémarre, les comptes répondent, et tous les dépôts manquent. -
Redémarrer et vérifier
Fenêtre de terminal sudo systemctl start gitea.servicesleep 5sudo systemctl is-active gitea.service# activecurl -o /dev/null -s -w "%{http_code}\n" http://localhost:3000/# 200Un service actif ne prouve pas une restauration réussie. Comparez le contenu à ce que vous aviez avant, sans quoi vous validez une forge vide qui démarre très bien :
Fenêtre de terminal # Les comptes sont-ils revenus ?sudo -u git gitea admin user list --config /etc/gitea/app.ini | tail -n +2 | wc -l# Et les dépôts ? (jeton d'un compte administrateur)curl -s -H "Authorization: token $TOKEN" \http://localhost:3000/api/v1/user/repos | grep -c '"name"'Poussez la vérification jusqu'à un clone réel d'un dépôt restauré : c'est la seule façon de savoir que les objets Git sont intacts, et pas seulement référencés par la base.
-
Durcir les permissions
Fenêtre de terminal sudo chmod 640 /etc/gitea/app.inisudo chmod 750 /etc/giteasudo systemctl restart gitea.service -
Nettoyer les fichiers temporaires
Fenêtre de terminal rm -rf /tmp/gitea-restore
Sauvegarder vers un stockage distant
Section intitulée « Sauvegarder vers un stockage distant »Pour une stratégie robuste, transférez les archives vers un stockage distant après chaque backup.
# Exemple avec rsync vers un serveur distantrsync -az --progress \ /var/lib/gitea/backups/ \ backup-user@backup.example.com:/backups/gitea/
# Exemple avec rclone vers S3 / Backblaze B2 / etc.rclone copy /var/lib/gitea/backups/ remote:bucket/gitea-backups/À retenir
Section intitulée « À retenir »gitea dumpsauvegarde tout, dépôts, base, configuration et LFS, en une seule commande- L'instance doit être arrêtée pendant le dump : à chaud, la cohérence de l'archive n'est pas garantie
- La restauration suppose Gitea installé mais non configuré, sans
app.ini - Restaurez
app.inien premier : c'est lui qui déclare où vont les dépôts,data/gitea-repositoriespar défaut - L'archive porte
SECRET_KEY, sans laquelle les données chiffrées sont perdues, et les jetonsINTERNAL_TOKEN,JWT_SECRETetLFS_JWT_SECRET: protégez-la comme un secret - La tâche planifiée tourne en root, pas sous
git, puisqu'elle arrête le service - Le script fourni conserve 30 jours d'archives ; l'historique long vit sur le stockage distant