Aller au contenu
Culture DevOps medium

Sauvegarder et restaurer Forgejo

12 min de lecture

forgejo dump crée un fichier ZIP unique qui contient tout : la base de données, les dépôts Git, la configuration, les clés SSH, les avatars et les données LFS. Cette page explique comment créer, vérifier et restaurer ce backup, avec une automatisation cron pour ne plus y penser.

La procédure a été testée en lab : une instance Forgejo 14.0.3 sauvegardée, complètement détruite et restaurée depuis le ZIP. Résultat : HTTP 200, dépôts et configuration intacts.

forgejo dump produit un fichier .zip unique, sans dépendance à un outil externe. Connaître sa structure sert à deux choses : vérifier qu'un backup est complet avant de compter dessus, et savoir quoi restaurer où le jour de l'incident. Voici le contenu type :

Fichier dans le ZIPContenu
app.iniFichier de configuration principal
forgejo-db.sqlExport SQL complet de la base de données
data/Queues, indexeurs, LFS, clés SSH, avatars, sessions
repos/Tous les dépôts Git (format bare)

forgejo dump écrit son archive sous l'identité de l'utilisateur git, celui qui fait tourner le service. Le répertoire de destination doit donc lui appartenir avant la première exécution, faute de quoi la commande échoue au moment d'écrire le fichier, après avoir déjà travaillé plusieurs minutes. Le mode 750 évite qu'un utilisateur non privilégié puisse lire une archive contenant la base et les clés SSH.

Fenêtre de terminal
sudo mkdir -p /var/lib/forgejo/backups
sudo chown git:git /var/lib/forgejo/backups
sudo chmod 750 /var/lib/forgejo/backups

Deux modes coexistent, et le choix ne dépend que de votre tolérance à l'interruption. Service arrêté, l'archive est cohérente par construction : rien n'écrit pendant la copie. Service en marche, vous évitez la coupure mais acceptez qu'une écriture en cours ne soit pas dans l'archive. Les deux commandes sont identiques, seul l'arrêt préalable du service change.

Arrêter le service garantit la cohérence des données, notamment pour SQLite qui n'a pas de mécanisme de snapshot transactionnel externe.

Fenêtre de terminal
# Arrêter le service
sudo systemctl stop forgejo.service
# Créer le backup
sudo -u git forgejo dump \
-w /var/lib/forgejo \
-c /etc/forgejo/app.ini \
-f /var/lib/forgejo/backups/forgejo-dump-$(date +%Y%m%d-%H%M).zip
# Vérifier le fichier créé
ls -lh /var/lib/forgejo/backups/
# Relancer le service
sudo systemctl start forgejo.service

Un backup d'une instance vide pèse environ 2 Mo. Avec des dépôts réels, la taille correspond à la somme des dépôts + les données LFS.

Forgejo permet de créer un backup sans arrêter le service. Ce mode convient aux instances très actives qui ne peuvent pas tolérer une interruption, au prix d'un risque (très faible) d'incohérence des données en cours d'écriture.

Fenêtre de terminal
sudo -u git forgejo dump \
-w /var/lib/forgejo \
-c /etc/forgejo/app.ini \
-f /var/lib/forgejo/backups/forgejo-hot-$(date +%Y%m%d-%H%M).zip

unzip -l liste l'archive sans l'extraire : si app.ini, forgejo-db.sql et repos/ n'apparaissent pas tous les trois, le backup est inexploitable et il ne faut pas attendre le jour de la panne pour s'en apercevoir.

Fenêtre de terminal
# Lister les fichiers dans le ZIP
unzip -l /var/lib/forgejo/backups/forgejo-dump-20260328-1200.zip | head -30
# Vérifier que les éléments essentiels sont présents
unzip -l /var/lib/forgejo/backups/forgejo-dump-20260328-1200.zip | grep -E "app.ini|forgejo-db.sql|repos/"

Un backup manuel finit toujours par être oublié. Le script ci-dessous enchaîne les quatre gestes de la sauvegarde nocturne : arrêt du service, dump, redémarrage, purge des archives au-delà de la rétention. Il tourne sous root parce qu'il pilote systemctl, et il redescend sur l'utilisateur git pour la seule commande qui l'exige.

Le set -e en tête est ce qui empêche le pire scénario : sans lui, un échec du dump serait quand même suivi de la purge, qui effacerait les seules archives encore valides. Contrepartie à connaître : si le dump échoue, le script s'arrête avant systemctl start et Forgejo reste éteint, d'où l'intérêt de surveiller le fichier de log.

sudo tee /usr/local/bin/forgejo-backup.sh << 'EOF'
#!/bin/bash
set -e
BACKUP_DIR="/var/lib/forgejo/backups"
FORGEJO_WORK="/var/lib/forgejo"
FORGEJO_CONF="/etc/forgejo/app.ini"
RETENTION_DAYS=30
LOG="/var/log/forgejo-backup.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Début du backup Forgejo" >> "$LOG"
# Arrêt du service
systemctl stop forgejo.service
# Backup
BACKUP_FILE="${BACKUP_DIR}/forgejo-$(date +%Y%m%d-%H%M).zip"
sudo -u git forgejo dump \
-w "$FORGEJO_WORK" \
-c "$FORGEJO_CONF" \
-f "$BACKUP_FILE"
# Redémarrage
systemctl start forgejo.service
# Nettoyage des anciens backups
find "$BACKUP_DIR" -name "forgejo-*.zip" -mtime "+${RETENTION_DAYS}" -delete
SIZE=$(du -sh "$BACKUP_FILE" | cut -f1)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Backup terminé : $BACKUP_FILE ($SIZE)" >> "$LOG"
EOF
sudo chmod 750 /usr/local/bin/forgejo-backup.sh

La planification se fait dans le crontab de root, pas dans celui de git : le script appelle systemctl stop et systemctl start, hors de portée d'un utilisateur non privilégié.

Fenêtre de terminal
# Ouvrir le crontab root (le script utilise systemctl qui nécessite root)
sudo crontab -e

Ajoutez la ligne :

0 2 * * * /usr/local/bin/forgejo-backup.sh

Chaque exécution ajoute deux lignes horodatées : un début et une fin avec la taille de l'archive. Une ligne de début sans ligne de fin correspondante signale un dump interrompu, donc un service potentiellement resté arrêté.

Fenêtre de terminal
cat /var/log/forgejo-backup.log

La restauration écrase les données en place, elle ne fusionne rien : lancez-la sur une instance dont vous acceptez de perdre l'état courant. L'ordre des étapes n'est pas indifférent, le service doit être arrêté avant l'extraction et redémarré seulement une fois app.ini et data/ remis en place. Le point qui fait échouer la plupart des restaurations est la propriété des fichiers : tout ce qui est extrait ou copié doit appartenir à l'utilisateur git, sinon Forgejo redémarre sans accéder à ses propres dépôts.

  1. Préparer la restauration

    La restauration écrase les données existantes. Si votre instance est en production, assurez-vous d'avoir communiqué une fenêtre de maintenance.

    Fenêtre de terminal
    sudo systemctl stop forgejo.service
  2. Extraire le backup

    Le répertoire d'extraction doit appartenir à l'utilisateur git, sinon la restauration produira des fichiers avec de mauvaises permissions.

    Fenêtre de terminal
    BACKUP_FILE="/var/lib/forgejo/backups/forgejo-20260328-1200.zip"
    RESTORE_DIR="/tmp/forgejo-restore"
    # Créer le répertoire avec les bons droits
    sudo rm -rf "$RESTORE_DIR"
    sudo mkdir "$RESTORE_DIR"
    sudo chown git:git "$RESTORE_DIR"
    # Extraire
    sudo -u git unzip -q "$BACKUP_FILE" -d "$RESTORE_DIR"
    # Vérifier
    ls "$RESTORE_DIR"
    # Doit afficher : app.ini data/ repos/ forgejo-db.sql
  3. Restaurer la configuration

    Fenêtre de terminal
    sudo cp "$RESTORE_DIR/app.ini" /etc/forgejo/app.ini
    sudo chown git:git /etc/forgejo/app.ini
    sudo chmod 640 /etc/forgejo/app.ini
  4. Restaurer les données

    rsync -a préserve les permissions et écrase les fichiers existants :

    Fenêtre de terminal
    sudo rsync -a --chown=git:git "$RESTORE_DIR/data/" /var/lib/forgejo/data/

    Si le répertoire repos/ du backup est distinct de data/forgejo-repositories/ :

    Fenêtre de terminal
    sudo rsync -a --chown=git:git "$RESTORE_DIR/repos/" \
    /var/lib/forgejo/data/forgejo-repositories/
  5. Relancer le service et vérifier

    Fenêtre de terminal
    sudo systemctl start forgejo.service
    sudo systemctl status forgejo.service
    # Test HTTP
    curl -o /dev/null -sw "%{http_code}" http://localhost:3000/
    # Doit afficher 200
  6. Nettoyer les fichiers temporaires

    Fenêtre de terminal
    sudo rm -rf /tmp/forgejo-restore

La fréquence se déduit de la question « combien de travail acceptez-vous de perdre », la rétention de « jusqu'à quand pourriez-vous devoir remonter ». Une corruption silencieuse ou une suppression de dépôt passée inaperçue se découvre parfois des semaines plus tard, ce qui justifie de garder un point hebdomadaire au-delà des sauvegardes quotidiennes. Ces valeurs sont des points de départ à ajuster.

Volume de changementsFréquence backupRétention
Petite instance, peu de commitsQuotidien30 jours
Instance active (>10 développeurs)2x/jour14 jours + backup hebdo 3 mois
Instance critiqueToutes les heures (hot)7 jours + backup quotidien 1 mois

Externalisez les backups : copiez les ZIP vers un stockage distant (S3, NFS, autre serveur) pour vous protéger contre la perte du serveur Forgejo lui-même.

Les trois pannes ci-dessous ont la même origine : un décalage entre l'utilisateur qui exécute la commande et le propriétaire des fichiers. Forgejo travaille sous git, les commandes d'administration sous root, et chaque sudo mal placé produit un répertoire que l'autre ne peut plus écrire. Le réflexe de diagnostic est toujours ls -la sur le répertoire concerné.

Le répertoire de destination appartient encore à root : forgejo dump prépare l'archive puis échoue au moment de l'écrire.

Fenêtre de terminal
ls -la /var/lib/forgejo/backups/
# Vérifier que le répertoire appartient à git
sudo chown git:git /var/lib/forgejo/backups

Même cause côté restauration : sudo -u git unzip ne peut rien créer dans un répertoire d'extraction resté la propriété de root.

Fenêtre de terminal
# Vérifier les droits du répertoire d'extraction
ls -la /tmp/forgejo-restore/
sudo chown git:git /tmp/forgejo-restore/

Vérifiez que REPOSITORY_ROOT dans app.ini correspond au chemin où vous avez restauré les dépôts :

Fenêtre de terminal
sudo grep -A5 "^\[repository\]" /etc/forgejo/app.ini
# ROOT = /var/lib/forgejo/data/forgejo-repositories
  • forgejo dump produit un ZIP complet : config, DB SQL, dépôts, LFS, avatars
  • Le répertoire de destination du backup doit appartenir à l'utilisateur git
  • Le service doit être arrêté pour un backup cohérent (surtout avec SQLite)
  • La restauration suit le principe : extraire (en tant que git) → copier app.inirsync data/ → démarrer
  • Avec PostgreSQL/MySQL, la base de données n'est pas dans le ZIP, sauvegardez-la séparément
  • Externaliser les backups est indispensable pour se protéger d'une perte serveur

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn