Skip to content

Serveur Gitea

Serveur : Hetzner VPS — 89.167.14.242 / 2a01:4f9:c014:fa7b::1 Domaine : gitea.mindlet.app (web) / ssh-gitea.mindlet.app (git SSH) Date de mise en place : 1er février 2026


  1. Architecture générale
  2. Configuration DNS et Cloudflare
  3. Sécurisation du serveur
  4. Configuration Gitea
  5. Firewall (UFW)
  6. Fail2ban
  7. Guide d’administration
  8. Arborescence des fichiers

flowchart TB
    subgraph Internet
        Client[Client]
    end

    subgraph Cloudflare["Cloudflare (Proxy)"]
        WAF[WAF / DDoS Protection]
    end

    subgraph VPS["Hetzner VPS — 89.167.14.242"]
        subgraph Security["Sécurité"]
            UFW[UFW Firewall]
            F2B[Fail2ban IPS]
        end

        subgraph DockerEnv["Docker"]
            GiteaContainer["Gitea Container<br/>• Web UI :3000<br/>• SSH :22→222<br/>• SQLite DB"]
        end
    end

    Client -->|"HTTPS :443"| WAF
    Client -->|"SSH :222<br/>(direct)"| VPS
    WAF -->|"HTTP :3000"| GiteaContainer
ProtocoleCheminPorts
HTTPS (web)Client → Cloudflare (TLS termination) → VPS:3000 → Container:3000443 → 3000
SSH (git)Client → VPS:222 → Container:22 (direct, pas de proxy Cloudflare)222 → 22
SSH (admin)Client → VPS:22 → sshd host22

Les commandes git push / git clone via SSH vers gitea.mindlet.app:222 aboutissaient à un timeout. Cause : le domaine était en mode Proxied (nuage orange) dans Cloudflare, qui ne transmet que le trafic HTTP/HTTPS.

EnregistrementTypeValeurProxy
gitea.mindlet.appA / AAAACloudflare proxyON (orange)
ssh-gitea.mindlet.appA89.167.14.242OFF (gris)
ssh-gitea.mindlet.appAAAA2a01:4f9:c014:fa7b::1OFF (gris)

Configuration Gitea pour afficher les bonnes URLs de clone :

GITEA__server__SSH_DOMAIN: ssh-gitea.mindlet.app

Pourquoi deux domaines ? Le sous-domaine SSH expose l’IP réelle mais est protégé par fail2ban et authentification par clé. L’interface web reste protégée par Cloudflare.


Fichier : /etc/ssh/sshd_config.d/hardening.conf

PermitRootLogin prohibit-password
PasswordAuthentication no
PermitEmptyPasswords no
MaxAuthTries 3
MaxSessions 5
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
DirectiveJustification
PermitRootLogin prohibit-passwordRoot uniquement par clé SSH
PasswordAuthentication noClés SSH obligatoires, pas de brute force possible
MaxAuthTries 33 essais max par connexion
X11Forwarding noServeur headless, pas de GUI
AllowAgentForwarding noEmpêche le pivot via agent SSH compromis
AllowTcpForwarding noPas de tunnel/proxy SSH
UtilisateurFichier
root/root/.ssh/authorized_keys
antocreadev/home/antocreadev/.ssh/authorized_keys
Terminal window
# Connexion admin
ssh root@89.167.14.242
ssh antocreadev@89.167.14.242

Fichier : /root/gitea/docker-compose.yml

Les variables GITEA__section__CLÉ sont converties en directives app.ini.

VariableValeurJustification
DISABLE_REGISTRATIONtruePas d’inscription publique
REQUIRE_SIGNIN_VIEWtrueAuthentification obligatoire
ENABLE_CAPTCHAtrueProtection formulaires
ENABLE_OPENID_SIGNINfalseFerme le vecteur OpenID
ENABLE_OPENID_SIGNUPfalseFerme le vecteur OpenID
REVERSE_PROXY_TRUSTED_PROXIESIPs CloudflareSeul Cloudflare peut définir X-Forwarded-For
GITEA__log__MODE: "console,file"
GITEA__log.file__FILE_NAME: "/data/gitea/log/gitea.log"

Fichier log sur l’hôte : /root/gitea/gitea/gitea/log/gitea.log (surveillé par fail2ban)


PortAccèsJustification
22/tcpMondeSSH admin (clé + fail2ban)
80/tcpMondeRedirection HTTP → HTTPS
443/tcpMondeHTTPS via Cloudflare
222/tcpMondeSSH Git (clé uniquement)
3000/tcpIPs CloudflarePort interne Gitea

Empêche l’accès direct en contournant Cloudflare (protection DDoS, WAF, headers).

Maintenance : Cloudflare peut ajouter de nouvelles plages IP. Voir cloudflare.com/ips.


Fichier : /etc/fail2ban/jail.local

JailPortLogSeuilBan
sshd22/var/log/auth.log3 échecs / 10 min3h
gitea80, 443, 3000/root/gitea/gitea/gitea/log/gitea.log5 échecs / 10 min1h

Fichier : /etc/fail2ban/filter.d/gitea.conf

[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =
Terminal window
# Statut global
fail2ban-client status
# IPs bannies
fail2ban-client status sshd
fail2ban-client status gitea
# Débannir
fail2ban-client set sshd unbanip 1.2.3.4
# Tester un filtre
fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf

Terminal window
docker exec -u git gitea gitea admin user create \
--username "nouveau_dev" \
--password "MotDePasseTemporaire123!" \
--email "dev@example.com" \
--must-change-password

Ou via l’interface : Site Administration → User Accounts → Create User Account

  1. Se connecter sur https://gitea.mindlet.app
  2. Settings → SSH / GPG Keys → Add Key
  3. Coller le contenu de ~/.ssh/id_ed25519.pub
Terminal window
git clone ssh://git@ssh-gitea.mindlet.app:222/organisation/repo.git
cd repo
git push origin main
Terminal window
# Supprimer de Gitea
docker exec -u git gitea gitea admin user delete --username "ancien_dev"
# Supprimer l'accès SSH VPS (si applicable)
deluser ancien_dev
rm -rf /home/ancien_dev
Terminal window
curl -s https://www.cloudflare.com/ips-v4
curl -s https://www.cloudflare.com/ips-v6
ufw status | grep 3000
Terminal window
cd /root/gitea
# Modifier la version dans docker-compose.yml
docker compose pull
docker compose down && docker compose up -d
Terminal window
# Arrêter pour cohérence
docker compose -f /root/gitea/docker-compose.yml down
# Sauvegarder
tar czf /root/backup-gitea-$(date +%Y%m%d).tar.gz -C /root/gitea gitea/
# Redémarrer
docker compose -f /root/gitea/docker-compose.yml up -d

Ou via Gitea (sauvegarde à chaud) :

Terminal window
docker exec -u git gitea gitea dump -c /data/gitea/conf/app.ini

/root/gitea/
├── docker-compose.yml # Configuration Docker Compose
└── gitea/ # Volume Docker (/data)
└── gitea/
├── conf/app.ini # Configuration Gitea
├── gitea.db # Base SQLite
└── log/gitea.log # Logs (surveillé par fail2ban)
/etc/ssh/sshd_config.d/
└── hardening.conf # Durcissement SSH
/etc/fail2ban/
├── jail.local # Jails (sshd + gitea)
└── filter.d/gitea.conf # Filtre regex Gitea