📍 Article principal du sujet : Incus 6 LTS — gérer conteneurs système et VMs Linux pour PME ouest-africaine
Pour la vue d’ensemble, lisez d’abord l’article principal qui pose le contexte d’Incus.
Pour une équipe de développement ouest-africaine, deux options s’opposent quand vient la question de la forge git interne. Soit on paye GitHub Team à 4 USD par utilisateur par mois et on accepte que le code reste sur des serveurs américains. Soit on auto-héberge Gitea ou son fork Forgejo dans un conteneur Incus sur un VPS Hostinger, on garde la souveraineté du code, et on dépense quelques euros par mois pour servir une équipe entière. Ce tutoriel monte une forge complète : Gitea, base de données SQLite ou PostgreSQL, Caddy avec HTTPS, et un coureur Gitea Actions pour la CI/CD intégrée.
Gitea et Forgejo se sont établis en 2024-2025 comme les alternatives open source crédibles à GitHub pour les PME et les équipes internes. Forgejo est un fork communautaire de Gitea hébergé par Codeberg, ultra-aligné sur la philosophie libre. Gitea reste la version la plus déployée et bénéficie d’un écosystème de plugins plus large. Pour ce tutoriel, on choisit Gitea ; les commandes sont quasi-identiques pour Forgejo, seuls le binaire et le chemin de service diffèrent.
Pourquoi auto-héberger plutôt que GitHub/GitLab.com
Trois arguments pèsent côté PME ouest-africaine : coût, souveraineté, latence. Pour une équipe de cinq développeurs, GitHub Team revient à 20 USD par mois, soit 240 USD par an, soit environ 145 000 FCFA. La même équipe sur un Gitea auto-hébergé sur un Hostinger Cloud VPS 4 Go RAM dépense 60 USD par an, soit moins de la moitié. À dix développeurs, le ratio passe à un quart, et au-delà de vingt il devient marginal de payer une forge externe quand l’auto-hébergement coûte le même prix annuel qu’une seule licence Team.
La souveraineté n’est pas un argument abstrait : pour une startup qui développe une fintech ou une healthtech, garder le code source et l’historique sur un serveur sous contrôle direct évite des questions juridiques quand un contrat client impose la confidentialité. La latence enfin : pour un push depuis Dakar vers GitHub.com (datacenter US East), comptez 250-400 ms par commit ; vers un VPS Hostinger en Europe, on tombe à 80-120 ms — multiplié par les opérations git quotidiennes, le gain est tangible.
Prérequis
- VPS Linux 64 bits, 2 Go de RAM minimum (4 Go recommandé pour CI), 40 Go SSD
- Incus 6 LTS opérationnel — voir Installer Incus avec Zabbly
- Caddy installé sur l’hôte pour le reverse-proxy HTTPS
- Un nom de domaine pointant sur le VPS (ex :
git.exemple.org) - Niveau attendu : Linux confortable, notion de git serveur
- Temps estimé : 45 minutes pour Gitea de base, 30 minutes supplémentaires pour le runner Actions
Pour ce scénario, Hostinger Cloud VPS à 4 Go RAM est confortable pour 20 développeurs actifs avec runner CI/CD intégré. Sur 2 Go RAM (entrée de gamme), Gitea seul fonctionne très bien jusqu’à 10 utilisateurs ; pour ajouter le runner CI, il faut viser 4 Go.
Étape 1 — Créer le conteneur Gitea
incus profile create gitea
incus profile edit gitea
config:
limits.cpu.allowance: 100%
limits.memory: 1.5GB
limits.processes: 500
security.idmap.isolated: true
description: Profil Gitea forge git
devices:
eth0:
name: eth0
network: incusbr0
type: nic
root:
path: /
pool: default
size: 20GB
type: disk
name: gitea
used_by: []
incus launch images:debian/12 gitea-srv -p gitea
incus shell gitea-srv
Dans le conteneur, on installe Git, SQLite (ou PostgreSQL pour les déploiements plus larges), et un utilisateur dédié à Gitea pour exécuter le service avec les bons droits.
apt update && apt upgrade -y
apt install -y git sqlite3 wget gettext-base
adduser --system --shell /bin/bash --gecos 'Git Version Control' \
--group --disabled-password --home /home/git git
Étape 2 — Télécharger et installer le binaire Gitea
Gitea est livré comme un binaire Go autonome — pas de dépendances PHP/Ruby/Node à installer. On télécharge la version stable depuis le site officiel et on la dépose dans /usr/local/bin.
GITEA_VERSION=1.22.3
wget -O gitea https://dl.gitea.com/gitea/${GITEA_VERSION}/gitea-${GITEA_VERSION}-linux-amd64
chmod +x gitea
mv gitea /usr/local/bin/gitea
gitea --version
# Gitea version 1.22.3 built with Go ...
Cette unique commande installe la totalité du serveur — UI web, API REST, support SSH, runner intégré, le tout dans un binaire de 130 Mo environ. C’est l’un des arguments forts de Gitea face à GitLab CE qui demande 4 à 8 Go de RAM rien que pour démarrer.
Étape 3 — Préparer les répertoires et permissions
mkdir -p /var/lib/gitea/{custom,data,log}
chown -R git:git /var/lib/gitea/
chmod -R 750 /var/lib/gitea/
mkdir /etc/gitea
chown root:git /etc/gitea
chmod 770 /etc/gitea
Pourquoi ces permissions ? Le binaire Gitea tourne sous l’utilisateur git, donc tous les répertoires de données lui appartiennent. Le répertoire de config /etc/gitea reste à 770 pendant l’installation initiale (Gitea doit pouvoir y écrire son app.ini) puis sera durci à 750 une fois la config figée — étape importante de sécurité, sinon le binaire pourrait modifier sa propre config en exploitation.
Étape 4 — Service systemd
cat <<'EOF' > /etc/systemd/system/gitea.service
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target network.target
[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
systemctl daemon-reload
systemctl enable --now gitea
systemctl status gitea
Le service démarre Gitea sur le port par défaut 3000. Vérifiez avec ss -tlnp | grep 3000 que le port écoute bien. Si la commande renvoie une ligne avec :::3000 ou 0.0.0.0:3000, Gitea est prêt à recevoir des connexions HTTP.
Étape 5 — Configuration initiale via le navigateur
On sort du conteneur, on récupère son IP, et on configure Caddy pour proxifier le domaine public vers le port 3000 du conteneur.
exit
incus list -c n4 gitea-srv --format csv
# gitea-srv,10.124.10.61 (eth0)
cat <<'EOF' >> /etc/caddy/Caddyfile
git.exemple.org {
reverse_proxy 10.124.10.61:3000
encode gzip
request_body {
max_size 5GB
}
}
EOF
systemctl reload caddy
Le max_size 5GB autorise le push de gros dépôts ou l’upload de releases binaires. Si vous hébergez du code seulement (pas de releases), 100 Mo suffisent.
Pointez votre navigateur vers https://git.exemple.org. Au premier accès, Gitea affiche un assistant de configuration : type de base de données (SQLite suffisant pour moins de 50 utilisateurs, PostgreSQL au-delà), URL de base, désactivation des inscriptions (recommandé pour une forge interne), et création du compte admin. Cette première étape signe le fichier app.ini définitif. Une fois validée, le formulaire d’inscription public est désactivé et Gitea redirige vers le login.
Étape 6 — SSH pour les opérations git
Sur le port 22, le SSH système existant occupe déjà l’espace. On expose Gitea-SSH sur un port différent, par défaut 2222, et on configure les utilisateurs pour pousser via cette voie.
incus shell gitea-srv
sed -i 's/^SSH_PORT.*/SSH_PORT = 2222/' /etc/gitea/app.ini
sed -i 's/^DISABLE_SSH.*/DISABLE_SSH = false/' /etc/gitea/app.ini
sed -i 's/^START_SSH_SERVER.*/START_SSH_SERVER = true/' /etc/gitea/app.ini
systemctl restart gitea
exit
# Sur l'hôte, ouvrir le port 2222 vers le conteneur
incus config device add gitea-srv ssh-proxy proxy listen=tcp:0.0.0.0:2222 connect=tcp:127.0.0.1:2222
L’option proxy d’Incus crée un forward de port de l’hôte vers le conteneur, sans iptables manuel. Les utilisateurs peuvent maintenant ajouter leur clé SSH dans Gitea (Profile → SSH Keys) et cloner avec git@git.exemple.org:user/repo.git -p 2222 en spécifiant le port. Pour ne pas avoir à taper -p 2222 à chaque fois, on ajoute dans ~/.ssh/config côté client :
Host git.exemple.org
Port 2222
User git
Étape 7 — Activer Gitea Actions pour la CI/CD intégrée
Depuis Gitea 1.21+, le runner Actions est intégré et compatible avec les workflows GitHub Actions (au format YAML identique). Pour activer côté serveur :
incus shell gitea-srv
cat <<'EOF' >> /etc/gitea/app.ini
[actions]
ENABLED = true
DEFAULT_ACTIONS_URL = github
EOF
systemctl restart gitea
exit
Côté runner, on lance un second conteneur Incus dédié pour exécuter les jobs CI dans un environnement isolé, et on enregistre ce runner auprès du serveur Gitea via un token administrateur.
# Sur l'hôte
incus launch images:debian/12 gitea-runner
# Dans le runner
incus shell gitea-runner
apt update && apt install -y curl wget docker.io
RUNNER_VERSION=0.2.10
wget -O act_runner https://dl.gitea.com/act_runner/${RUNNER_VERSION}/act_runner-${RUNNER_VERSION}-linux-amd64
chmod +x act_runner
mv act_runner /usr/local/bin/
act_runner register --instance https://git.exemple.org --token TOKEN_ADMIN
# (le token admin est généré dans l'admin Gitea → Actions → Runners)
Le runner s’enregistre auprès du serveur Gitea et écoute les jobs envoyés. Un workflow type .gitea/workflows/test.yml au format GitHub Actions standard exécutera les étapes (build, test, deploy) dans le conteneur runner. Pour les projets avec dépendances Docker, activer privileged: true dans la config runner permet le DinD (Docker-in-Docker).
Étape 8 — Sauvegarde de la forge
L’avantage d’avoir tout dans un conteneur Incus se concrétise pour la sauvegarde : un snapshot capture la totalité (binaire, config, base de données SQLite, repositories, metadata Actions) en un seul artefact transportable.
incus snapshot create gitea-srv backup-$(date +%Y%m%d)
incus export gitea-srv /backups/gitea-$(date +%Y%m%d).tar.gz \
--snapshot=backup-$(date +%Y%m%d)
rclone copy /backups/gitea-*.tar.gz bunny:backups-itskills/gitea/
En cas de désastre (VPS perdu, datacenter coupé), restaurer revient à incus import sur un autre VPS, ajuster le DNS, et la forge est de retour avec tous ses repos et tous ses comptes en moins de quinze minutes — RTO réaliste hors du temps de propagation DNS.
Erreurs fréquentes
| Erreur | Cause | Solution |
|---|---|---|
| Erreur 500 à la première page | Permissions /var/lib/gitea incorrectes | chown -R git:git /var/lib/gitea et redémarrer |
| Push SSH refusé : git command not found | L’utilisateur git n’a pas le shell git | Utiliser le SSH intégré Gitea (port 2222) plutôt que le SSH système |
| Runner Actions ne reçoit pas de jobs | Token expiré ou URL différente | Régénérer le token côté admin, ré-enregistrer le runner |
| Performance lente au-delà de 100 utilisateurs | SQLite plafonne sous concurrence d’écriture | Migrer vers PostgreSQL avec gitea dump puis import dans la nouvelle DB |
| Push de gros dépôt qui timeout | request_body max_size trop bas dans Caddy | Augmenter à 5GB ou utiliser SSH au lieu de HTTPS pour les gros pushes |
Adaptation au contexte ouest-africain
Une équipe de quatre développeurs à Cotonou qui passe de GitHub Team à Gitea auto-hébergé sur un VPS Hostinger 4 Go économise environ 12 USD/mois. À l’année, c’est 145 000 FCFA récupérés sur le budget infra — l’équivalent du salaire d’un stagiaire pendant deux mois.
L’argument différenciant pour les écoles d’ingénieur et bootcamps est encore plus net : héberger une forge interne pour 60 étudiants sur un VPS unique évite les comptes GitHub étudiants à valider chaque année (avec les soucis de compte vérifié, d’email étudiant non reconnu, etc.). Le formateur a la main complète sur les permissions, peut créer/supprimer des comptes en masse, et garde un historique pédagogique pluriannuel.
Pour les équipes bilingues français-anglais typiques de Dakar ou Abidjan, l’interface Gitea est intégralement traduite en français — un confort qu’on n’a pas sur GitHub où l’UI reste majoritairement anglaise.
Tutoriels frères
- Auto-héberger Nextcloud dans un conteneur Incus — autre service self-hosted pour PME.
- WordPress multisite — un conteneur Incus par client — modèle similaire pour l’isolation.
- CI/CD GitLab avec runners Incus éphémères — l’alternative GitLab.
Pour aller plus loin
- 🔝 Retour à l’article principal sur Incus
- Documentation officielle Gitea
- Documentation officielle Forgejo (si vous préférez le fork communautaire)
- Pour pratiquer : Hostinger Cloud VPS 4 Go RAM
FAQ
Gitea ou Forgejo ?
Forgejo si la philosophie 100 % libre prime, Gitea pour l’écosystème de plugins plus large et la fréquence de release. Migration possible dans les deux sens, format de données identique.
Combien d’utilisateurs sur SQLite ?
Jusqu’à 50 utilisateurs actifs sans souci. Au-delà, migrer vers PostgreSQL — l’opération gitea dump + restore dans la nouvelle DB prend dix minutes.
Compatibilité workflows GitHub Actions ?
~90 % des workflows GitHub Actions standards fonctionnent tels quels dans Gitea Actions. Les actions tierces hébergées sur GitHub sont mirrorées automatiquement à la première utilisation.
Comment restreindre l’inscription ?
Dans app.ini, section [service] : DISABLE_REGISTRATION = true et REQUIRE_SIGNIN_VIEW = true. Les nouveaux comptes ne peuvent être créés que par un admin.
Le runner Actions consomme-t-il beaucoup ?
Au repos, 30 Mo. En exécution d’un job (compilation, tests), 200 à 800 Mo selon le projet. Sur 4 Go RAM, on peut faire tourner deux runners parallèles confortablement.