19 KiB
Gitea, Traefik & CI/CD Setup - Komplette Anleitung
Stand: 2025-11-08
Status: ✅ Vollständig dokumentiert - Alle Probleme gelöst
Zweck: Referenz für zukünftige Deployments und Troubleshooting
Übersicht
Dieses Dokument dokumentiert alle Schritte, Probleme und Lösungen, die notwendig waren, um Gitea, Traefik und die CI/CD-Pipeline vollständig zum Laufen zu bringen. Diese Anleitung sollte bei jedem neuen Deployment oder bei ähnlichen Problemen als Referenz dienen.
📖 Verwandte Dokumentation:
Problem 1: Traefik Dashboard nicht erreichbar
Symptom
- Traefik Dashboard unter
https://traefik.michaelschiemer.denicht erreichbar - Passwort unbekannt oder vergessen
Lösung: Traefik-Passwort zurücksetzen
1. Neues Passwort-Hash generieren:
htpasswd -nb admin "dein_neues_passwort"
# Output: admin:$apr1$xyz123$abc456
2. Hash in docker-compose.yml aktualisieren:
Datei: deployment/stacks/traefik/docker-compose.yml
Wichtig: In Docker Compose Labels müssen $ Zeichen mit $$ escaped werden!
# Zeile 49
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$xyz123$$abc456"
3. Konfiguration synchronisieren und Traefik neu starten:
cd deployment/ansible
ansible-playbook -i inventory/production.yml playbooks/sync-stacks.yml \
--vault-password-file secrets/.vault_pass
ansible -i inventory/production.yml server -m shell \
-a "cd /home/deploy/deployment/stacks/traefik && docker compose restart traefik" \
--vault-password-file secrets/.vault_pass
Erfolgreich getestet mit Passwort: 4qcdnnqF7NV4bLZnXmJna7Sd2FCsd2zM
Problem 2: Gitea nicht erreichbar (504 Bad Gateway)
Symptom
- Gitea unter
https://git.michaelschiemer.deliefert 504 Bad Gateway - Traefik Logs zeigen: "Error while dialing backend"
- Gitea Container läuft, aber Traefik kann nicht verbinden
Root Cause
Die File-Provider-Konfiguration dynamic/gitea-service.yml überschreibt die Docker-Service-Definition und verursacht Konflikte. Traefik findet kein Backend, obwohl Gitea läuft.
Lösung: File-Provider-Konfiguration entfernen
1. Datei deaktivieren (lokal):
cd deployment/stacks/traefik/dynamic
mv gitea-service.yml gitea-service.yml.disabled
2. Konfiguration synchronisieren:
cd deployment/ansible
ansible-playbook -i inventory/production.yml playbooks/sync-stacks.yml \
--vault-password-file secrets/.vault_pass
3. Alte Datei auf Server entfernen:
ansible -i inventory/production.yml server -m file \
-a "path=/home/deploy/deployment/stacks/traefik/dynamic/gitea-service.yml state=absent" \
--vault-password-file secrets/.vault_pass
4. Traefik neu starten:
ansible -i inventory/production.yml server -m shell \
-a "cd /home/deploy/deployment/stacks/traefik && docker compose restart traefik" \
--vault-password-file secrets/.vault_pass
Warum funktioniert das?
- Docker-Labels definieren bereits den Service korrekt:
traefik.http.services.gitea.loadbalancer.server.port=3000 - Router referenziert explizit:
traefik.http.routers.gitea.service=gitea@docker - File-Provider-Definition überschreibt diese Konfiguration und verursacht Konflikte
Wichtig: Die Datei gitea-service.yml.disabled sollte nicht wieder aktiviert werden, da die Docker-Labels ausreichend sind.
Problem 3: Gitea im Restart-Loop (Redis-Verbindung)
Symptom
- Gitea Container startet, crasht sofort, startet wieder (Endlosschleife)
- Logs zeigen:
dial tcp 127.0.0.1:6379: connect: connection refused - Gitea versucht, sich mit
127.0.0.1:6379stattredis:6379zu verbinden
Root Cause
Gitea 1.25 interpretiert GITEA__cache__HOST=redis:6379 nicht korrekt und verbindet sich mit 127.0.0.1:6379. Die app.ini Datei im Volume enthält möglicherweise noch alte 127.0.0.1 Werte.
Lösung: Gitea app.ini bereinigen
1. Gitea Container stoppen:
cd deployment/ansible
ansible -i inventory/production.yml server -m shell \
-a "cd /home/deploy/deployment/stacks/gitea && docker compose stop gitea" \
--vault-password-file secrets/.vault_pass
2. app.ini im Volume aktualisieren (minimale Konfiguration):
Wichtig: Die [cache] Sektion muss komplett entfernt werden, da sie über ENV-Variablen gesteuert wird!
ansible -i inventory/production.yml server -m shell -a 'docker run --rm -v gitea-data:/data alpine sh -c "cat > /data/gitea/conf/app.ini << EOF
APP_NAME = Gitea: Git with a cup of tea
RUN_MODE = prod
[server]
PROTOCOL = http
DOMAIN = git.michaelschiemer.de
HTTP_ADDR = 0.0.0.0
HTTP_PORT = 3000
ROOT_URL = https://git.michaelschiemer.de/
DISABLE_SSH = false
START_SSH_SERVER = false
SSH_DOMAIN = git.michaelschiemer.de
SSH_PORT = 2222
SSH_LISTEN_PORT = 2222
[database]
DB_TYPE = postgres
HOST = postgres:5432
NAME = gitea
USER = gitea
PASSWD = gitea_password
SSL_MODE = disable
[security]
INSTALL_LOCK = true
[service]
DISABLE_REGISTRATION = true
[actions]
ENABLED = true
EOF
chown 1000:1000 /data/gitea/conf/app.ini && chmod 644 /data/gitea/conf/app.ini"' \
--vault-password-file secrets/.vault_pass
3. Gitea wieder starten:
ansible -i inventory/production.yml server -m shell \
-a "cd /home/deploy/deployment/stacks/gitea && docker compose up -d gitea" \
--vault-password-file secrets/.vault_pass
4. Cache-Konfiguration (aktuell deaktiviert):
Datei: deployment/stacks/gitea/docker-compose.yml
# Cache deaktiviert - Gitea 1.25 interpretiert GITEA__cache__HOST nicht korrekt
- GITEA__cache__ENABLED=false
- GITEA__cache__ADAPTER=memory
# Session und Queue nutzen weiterhin Redis
- GITEA__session__PROVIDER=redis
- GITEA__session__PROVIDER_CONFIG=network=tcp,addr=redis:6379,password=${REDIS_PASSWORD:-gitea_redis_password},db=0,pool_size=100,idle_timeout=180
- GITEA__queue__TYPE=redis
- GITEA__queue__CONN_STR=redis://:${REDIS_PASSWORD:-gitea_redis_password}@redis:6379/0
Hinweis: Cache kann später wieder aktiviert werden, wenn Gitea aktualisiert wird oder ein Workaround gefunden wird.
Problem 4: Gitea Repository fehlt
Symptom
- Repository
michael/michaelschiemerexistiert nicht in Gitea - Git Push schlägt fehl: "repository not found"
Lösung: Repository erstellen
1. Repository über Gitea API erstellen:
cd deployment/ansible
# Admin-Credentials aus Vault holen
ADMIN_USER=$(ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass 2>/dev/null | \
grep 'vault_gitea_admin_username:' | \
sed 's/.*vault_gitea_admin_username: *"\([^"]*\)".*/\1/')
ADMIN_PASS=$(ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass 2>/dev/null | \
grep 'vault_gitea_admin_password:' | \
sed 's/.*vault_gitea_admin_password: *"\([^"]*\)".*/\1/')
# Repository erstellen
curl -k -s -X POST \
-u "${ADMIN_USER}:${ADMIN_PASS}" \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0" \
-d '{
"name":"michaelschiemer",
"description":"Main application repository",
"private":false,
"auto_init":false
}' \
https://git.michaelschiemer.de/api/v1/user/repos
2. Git Remote konfigurieren:
cd /home/michael/dev/michaelschiemer
git remote set-url origin https://git.michaelschiemer.de/michael/michaelschiemer.git
git remote -v # Verifizieren
3. Push testen:
# Mit Admin-Credentials (temporär)
git remote set-url origin https://${ADMIN_USER}:${ADMIN_PASS}@git.michaelschiemer.de/michael/michaelschiemer.git
git push origin staging
Alternativ: Ansible Playbook verwenden:
cd deployment/ansible
ansible-playbook -i inventory/production.yml \
playbooks/setup-gitea-repository.yml \
--vault-password-file secrets/.vault_pass \
-e "repo_name=michaelschiemer" \
-e "repo_owner=michael" \
-e "repo_private=false"
Problem 5: Gitea Runner nicht registriert oder läuft nicht
Symptom
- Workflows werden nicht ausgeführt
- Runner erscheint nicht in Gitea UI
- Runner Container läuft, aber zeigt "unregistered runner" Fehler
Lösung: Runner registrieren und starten
1. Registration Token von Gitea holen:
- Gehe zu:
https://git.michaelschiemer.de/admin/actions/runners - Klicke auf "Create New Runner" oder "New Runner"
- Kopiere das Registration Token
2. Token in .env Datei aktualisieren:
Datei: deployment/gitea-runner/.env
cd deployment/gitea-runner
nano .env
# Setze: GITEA_RUNNER_REGISTRATION_TOKEN=<neues-token>
3. Alte Registrierung entfernen (falls vorhanden):
cd deployment/gitea-runner
docker compose down
rm -f data/.runner
4. Runner registrieren:
cd deployment/gitea-runner
./register.sh
5. Runner-Status prüfen:
# Container-Status
docker compose ps
# Runner-Logs
docker compose logs -f gitea-runner
# In Gitea UI prüfen
# https://git.michaelschiemer.de/admin/actions/runners
Erfolgreiche Registrierung zeigt:
✓ Runner registered successfully!
Runner is now active and will start accepting jobs.
Runner-Logs sollten zeigen:
level=info msg="Runner registered successfully."
level=info msg="declare successfully"
level=info msg="task 1 repo is michael/michaelschiemer"
Problem 6: Git Push schlägt fehl (Authentication)
Symptom
fatal: Authentication failed for 'https://git.michaelschiemer.de/...'- Push funktioniert nicht, obwohl Repository existiert
Lösung: Git Remote mit Credentials konfigurieren
Option 1: Temporär mit Admin-Credentials (für ersten Push):
cd /home/michael/dev/michaelschiemer
# Credentials aus Vault holen
ADMIN_USER=$(ansible-vault view deployment/ansible/secrets/production.vault.yml \
--vault-password-file deployment/ansible/secrets/.vault_pass 2>/dev/null | \
grep 'vault_gitea_admin_username:' | \
sed 's/.*vault_gitea_admin_username: *"\([^"]*\)".*/\1/')
ADMIN_PASS=$(ansible-vault view deployment/ansible/secrets/production.vault.yml \
--vault-password-file deployment/ansible/secrets/.vault_pass 2>/dev/null | \
grep 'vault_gitea_admin_password:' | \
sed 's/.*vault_gitea_admin_password: *"\([^"]*\)".*/\1/')
# Remote mit Credentials setzen
git remote set-url origin https://${ADMIN_USER}:${ADMIN_PASS}@git.michaelschiemer.de/michael/michaelschiemer.git
# Push
git push origin staging
Option 2: Personal Access Token verwenden (empfohlen für dauerhafte Nutzung):
- In Gitea: Settings > Applications > Generate New Token
- Scopes:
write:repository,read:repository - Token kopieren
- Git Remote konfigurieren:
git remote set-url origin https://michael:<token>@git.michaelschiemer.de/michael/michaelschiemer.git
Option 3: Git Credential Helper konfigurieren:
git config --global credential.helper store
git push origin staging
# Bei Aufforderung: Username und Passwort eingeben
# Credentials werden in ~/.git-credentials gespeichert
Checkliste für zukünftige Deployments
Vor dem ersten Deployment
-
Traefik-Passwort setzen/resetzen
- Hash generieren:
htpasswd -nb admin "passwort" - In
deployment/stacks/traefik/docker-compose.ymlaktualisieren (mit$$escapen) - Synchronisieren und Traefik neu starten
- Hash generieren:
-
Traefik File-Provider-Konfiguration prüfen
deployment/stacks/traefik/dynamic/gitea-service.ymlsollte nicht existieren- Falls vorhanden: deaktivieren oder löschen
- Docker-Labels sind ausreichend
-
Gitea app.ini bereinigen
- Keine
[cache]Sektion mit127.0.0.1Werten - Minimale Konfiguration verwenden
- Cache über ENV-Variablen steuern
- Keine
-
Gitea Repository erstellen
- Über API oder Ansible Playbook
- Git Remote konfigurieren
-
Gitea Runner registrieren
- Registration Token von Gitea Admin UI holen
- In
deployment/gitea-runner/.enveintragen ./register.shausführen- Status in Gitea UI prüfen
Nach dem Deployment
-
Gitea erreichbar?
https://git.michaelschiemer.desollte funktionieren- Keine 504 Fehler
-
Traefik Dashboard erreichbar?
https://traefik.michaelschiemer.demit korrektem Passwort
-
Runner läuft?
docker compose psindeployment/gitea-runner/- Runner erscheint als "Idle" in Gitea UI
-
CI-Images verfügbar?
docker exec gitea-runner-dind docker images | grep docker-build- Falls nicht: Image bauen und in docker-dind laden (siehe Problem 7)
-
Workflows werden ausgeführt?
- Test-Commit pushen
- In Gitea Actions UI prüfen:
https://git.michaelschiemer.de/michael/michaelschiemer/actions - Keine "pull access denied" Fehler
Wichtige Dateien und Konfigurationen
Traefik
Datei: deployment/stacks/traefik/docker-compose.yml
- Zeile 49: BasicAuth Passwort-Hash (mit
$$escapen)
Datei: deployment/stacks/traefik/dynamic/gitea-service.yml
- Sollte nicht existieren - Docker-Labels sind ausreichend
Gitea
Datei: deployment/stacks/gitea/docker-compose.yml
- Cache deaktiviert (Gitea 1.25 Bug)
- Session und Queue nutzen Redis
Datei: deployment/stacks/gitea/app.ini (im Volume)
- Minimale Konfiguration
- Keine
[cache]Sektion
Datei: deployment/ansible/templates/gitea-app.ini.j2
- Template für minimale app.ini
- Wird von Ansible verwendet
Gitea Runner
Datei: deployment/gitea-runner/.env
GITEA_INSTANCE_URL=https://git.michaelschiemer.deGITEA_RUNNER_REGISTRATION_TOKEN=<token>GITEA_RUNNER_NAME=dev-runner-01
Datei: deployment/gitea-runner/data/.runner
- Wird automatisch bei Registrierung erstellt
- Enthält Runner-Credentials
Häufige Fehler und Lösungen
Fehler: "runner registration token not found"
Ursache: Token ist ungültig oder abgelaufen
Lösung:
- Neues Token in Gitea Admin UI erstellen
- Token in
.envaktualisieren - Runner neu registrieren:
./register.sh
Fehler: "unregistered runner"
Ursache: Runner wurde nicht korrekt registriert oder Token ist ungültig
Lösung:
- Alte Registrierung entfernen:
rm -f data/.runner - Container stoppen:
docker compose down - Neues Token holen und in
.enveintragen - Neu registrieren:
./register.sh
Fehler: "dial tcp 127.0.0.1:6379: connect: connection refused"
Ursache: Gitea versucht, sich mit 127.0.0.1:6379 statt redis:6379 zu verbinden
Lösung:
- Gitea stoppen
app.iniim Volume bereinigen (keine[cache]Sektion mit127.0.0.1)- Cache in
docker-compose.ymldeaktivieren - Gitea neu starten
Fehler: "504 Bad Gateway" bei Gitea
Ursache: Traefik File-Provider überschreibt Docker-Service-Definition
Lösung:
deployment/stacks/traefik/dynamic/gitea-service.ymlentfernen- Konfiguration synchronisieren
- Traefik neu starten
Ansible Playbooks Referenz
Stacks synchronisieren
cd deployment/ansible
ansible-playbook -i inventory/production.yml playbooks/sync-stacks.yml \
--vault-password-file secrets/.vault_pass
Gitea Repository erstellen
cd deployment/ansible
ansible-playbook -i inventory/production.yml \
playbooks/setup-gitea-repository.yml \
--vault-password-file secrets/.vault_pass \
-e "repo_name=michaelschiemer" \
-e "repo_owner=michael" \
-e "repo_private=false"
Gitea app.ini aktualisieren
cd deployment/ansible
ansible-playbook -i inventory/production.yml \
playbooks/setup-gitea-initial-config.yml \
--vault-password-file secrets/.vault_pass \
-e "force_update_app_ini=true"
Zusammenfassung der kritischen Schritte
- ✅ Traefik-Passwort setzen - Hash in
docker-compose.yml(mit$$escapen) - ✅ File-Provider entfernen -
gitea-service.ymllöschen/deaktivieren - ✅ Gitea app.ini bereinigen - Keine
[cache]Sektion mit127.0.0.1 - ✅ Repository erstellen - Über API oder Ansible Playbook
- ✅ Runner registrieren - Token in
.env, dann./register.sh - ✅ Git Remote konfigurieren - Mit Credentials für ersten Push
- ✅ CI-Images bauen und laden -
docker-buildImage in docker-dind laden
Nach diesen Schritten sollte die CI/CD-Pipeline vollständig funktionieren!
Problem 7: Workflow schlägt fehl - "pull access denied" für docker-build Image
Symptom
- Workflow startet, aber schlägt fehl mit:
pull access denied, repository does not exist or may require authorization - Runner versucht,
registry.michaelschiemer.de/ci/docker-build:latestzu pullen - Fehler tritt auf, bevor der Workflow die Registry-Authentifizierung durchführt
Root Cause
Der Runner versucht, Container-Images für Jobs zu pullen, bevor der Workflow die Registry-Authentifizierung durchführt. Das Image existiert möglicherweise nicht in der Registry oder der Runner hat keine Registry-Credentials.
Lösung: CI-Image bauen und in docker-dind laden
1. CI-Image bauen:
cd /home/michael/dev/michaelschiemer
docker build -f docker/ci/Dockerfile.build \
-t registry.michaelschiemer.de/ci/docker-build:latest \
--platform linux/amd64 .
2. Image in docker-dind laden (temporäre Lösung):
docker save registry.michaelschiemer.de/ci/docker-build:latest | \
docker exec -i gitea-runner-dind docker load
3. Verifizieren:
docker exec gitea-runner-dind docker images | grep docker-build
4. Runner neu starten:
cd deployment/gitea-runner
docker compose restart gitea-runner
Alternative: Image in Registry pushen (empfohlen für Production):
# Bei Registry einloggen
cd deployment/ansible
REGISTRY_USER=$(ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass 2>/dev/null | \
grep 'vault_docker_registry_username:' | \
sed 's/.*vault_docker_registry_username: *"\([^"]*\)".*/\1/')
REGISTRY_PASS=$(ansible-vault view secrets/production.vault.yml \
--vault-password-file secrets/.vault_pass 2>/dev/null | \
grep 'vault_docker_registry_password:' | \
sed 's/.*vault_docker_registry_password: *"\([^"]*\)".*/\1/')
cd /home/michael/dev/michaelschiemer
echo "$REGISTRY_PASS" | docker login registry.michaelschiemer.de \
-u "$REGISTRY_USER" --password-stdin
# Image pushen
docker push registry.michaelschiemer.de/ci/docker-build:latest
Hinweis: Wenn der Push fehlschlägt (z.B. 499 Error), kann das Image lokal in docker-dind geladen werden. Für Production sollte das Image jedoch in der Registry sein.
Für zukünftige Deployments: Das Image sollte beim ersten Setup gebaut und in die Registry gepusht werden, oder das Build-Script deployment/gitea-runner/build-ci-image.sh verwenden.
Letzte Aktualisierung: 2025-11-08
Status: ✅ Vollständig dokumentiert und getestet