Dein eigener Git-Server mit automatischem Deployment: Forgejo + Docker + Traefik
Wie man sein eigenes kleines Deployment System aufbauen kann ohne einem Konzern Geld in den Rachen zu werfen
Du hostest deine Projekte bei GitHub oder GitLab – aber hast du dich schon mal gefragt, wie es wäre, deinen eigenen Git-Server zu betreiben? Mit automatischen Deployments, SSL-Zertifikaten und voller Kontrolle über deine Daten?
In diesem Artikel zeige ich dir, wie du mit Forgejo, Docker und Traefik eine komplette CI/CD-Pipeline auf deinem eigenen Server einrichtest. Kein GitHub Actions, keine externen Dienste – alles läuft auf deiner eigenen Infrastruktur.
Warum ein eigener Git-Server?
Bevor wir ins Technische einsteigen: Lohnt sich das überhaupt?
Die Vorteile:
- Datensouveränität – Dein Code bleibt bei dir
- Keine Limits – Keine Runner-Minuten, keine Storage-Grenzen
- Lerneffekt – Du verstehst, was hinter den Kulissen passiert
- Kosten – Ein kleiner VPS - kostet weniger als GitHub Enterprise
Die Nachteile:
- Du bist für Wartung und Backups verantwortlich
- Initiales Setup braucht Zeit
Wenn du einen VPS herumliegen hast (oder einen mieten willst), ist das ein ideales Wochenendprojekt.
Die Architektur
Unser Setup besteht aus drei Hauptkomponenten:
┌─────────────────┐
│ Internet │
└────────┬────────┘
│
┌────────▼────────┐
│ Traefik │
│ (Reverse Proxy)│
│ SSL-Zertifikate│
└────────┬────────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐
│ Forgejo │ │ Deine App │ │ Weitere │
│ (Git+CI/CD)│ │ Container │ │ Apps... │
└─────────────┘ └─────────────┘ └─────────────┘
Traefik ist der Türsteher: Er empfängt alle Anfragen, kümmert sich um SSL-Zertifikate (automatisch via Let's Encrypt) und leitet die Anfragen an die richtigen Container weiter.
Forgejo ist dein Git-Server mit eingebautem CI/CD-Runner – quasi GitHub in einer einzigen Anwendung.
Deine Apps werden automatisch deployt, sobald du Code pushst.
Voraussetzungen
- Ein VPS mit Linux (Ubuntu/Debian empfohlen), mindestens 2 GB RAM
- Eine Domain mit Wildcard-DNS (z.B.
*.deine-domain.de→ VPS-IP) - Grundkenntnisse in Docker und der Kommandozeile
- SSH-Zugang zum Server
Teil 1: Traefik einrichten
Traefik ist das Herzstück unseres Setups. Er übernimmt:
- HTTPS-Terminierung mit automatischen Let's Encrypt-Zertifikaten
- Routing zu verschiedenen Containern basierend auf der Domain
- Load Balancing (falls du das mal brauchst)
Docker-Netzwerk erstellen
Zuerst brauchen wir ein Netzwerk, über das alle Container kommunizieren:
docker network create traefik-public
Traefik starten
Erstelle ein Verzeichnis und die Konfiguration:
mkdir -p /opt/traefik
cd /opt/traefik
docker-compose.yml:
services:
traefik:
image: traefik:v3
container_name: traefik
restart: unless-stopped
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.letsencrypt.acme.email=deine@email.de"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-certificates:/letsencrypt
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.deine-domain.de`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.service=api@internal"
# Basic Auth für Dashboard (optional aber empfohlen)
# - "traefik.http.routers.dashboard.middlewares=auth"
# - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$..."
volumes:
traefik-certificates:
networks:
traefik-public:
external: true
Starten mit:
docker compose up -d
Tipp: Ersetze deine@email.de und deine-domain.de mit deinen echten Werten. Die E-Mail wird nur für Let's Encrypt-Benachrichtigungen verwendet.
Teil 2: Forgejo installieren
Forgejo ist ein Fork von Gitea – leichtgewichtig, schnell und mit allem ausgestattet, was du brauchst.
Verzeichnis und Konfiguration
mkdir -p /opt/forgejo
cd /opt/forgejo
docker-compose.yml:
services:
forgejo:
image: codeberg.org/forgejo/forgejo:9
container_name: forgejo
restart: unless-stopped
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- forgejo-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
networks:
- traefik-public
ports:
- "2222:22" # SSH für Git
labels:
- "traefik.enable=true"
- "traefik.http.routers.forgejo.rule=Host(`git.deine-domain.de`)"
- "traefik.http.routers.forgejo.entrypoints=websecure"
- "traefik.http.routers.forgejo.tls.certresolver=letsencrypt"
- "traefik.http.services.forgejo.loadbalancer.server.port=3000"
volumes:
forgejo-data:
networks:
traefik-public:
external: true
Starten:
docker compose up -d
Öffne https://git.deine-domain.de und folge dem Setup-Wizard. Die Standardwerte sind meist okay – achte nur darauf, dass du dir ein Admin-Konto erstellst.
SSH-Konfiguration
Damit git clone git@git.deine-domain.de:user/repo.git funktioniert, brauchst du einen Eintrag in ~/.ssh/config:
Host git.deine-domain.de
HostName git.deine-domain.de
Port 2222
User git
IdentityFile ~/.ssh/id_rsa
Teil 3: Den CI/CD-Runner einrichten
Forgejo kann selbst als Runner fungieren – das ist das Geniale daran.
Runner registrieren
- Gehe in Forgejo zu Site Administration → Actions → Runners
- Klicke auf Create new Runner und kopiere das Token
Runner starten
Füge den Runner zu deiner Forgejo docker-compose.yml hinzu:
runner:
image: code.forgejo.org/forgejo/runner:6
container_name: forgejo-runner
restart: unless-stopped
depends_on:
- forgejo
volumes:
- forgejo-runner-data:/data
- /var/run/docker.sock:/var/run/docker.sock
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
command: >
sh -c '
forgejo-runner register --no-interactive
--instance https://git.deine-domain.de
--token DEIN_TOKEN
--name docker-runner
--labels docker:docker://node:20-alpine &&
forgejo-runner daemon
'
volumes:
# ... bestehende Volumes
forgejo-runner-data:
Ersetze DEIN_TOKEN mit dem kopierten Token und starte neu:
docker compose up -d
Der Runner sollte jetzt unter Site Administration → Actions → Runners als "Idle" erscheinen.
Teil 4: Deine erste automatische Deployment-Pipeline
Jetzt wird's spannend: Wir erstellen ein Projekt, das sich bei jedem Push automatisch deployt.
SSH-Key für Deployments
Der Runner braucht SSH-Zugang zum Server. Erstelle einen dedizierten Key:
ssh-keygen -t ed25519 -f ~/.ssh/deploy-key -N "" -C "ci-deploy"
Füge den Public Key zu den authorized_keys auf dem Server hinzu:
cat ~/.ssh/deploy-key.pub >> ~/.ssh/authorized_keys
Repository erstellen
- Erstelle ein neues Repository in Forgejo
- Gehe zu Settings → Actions → Secrets
- Füge
SSH_PRIVATE_KEYhinzu (Inhalt von~/.ssh/deploy-key) - Gehe zu Settings → Actions → Variables
- Füge hinzu:
APP_NAME: Name deiner App (z.B.meine-app)DOMAIN: Domain (z.B.meine-app.deine-domain.de)
Wichtig: Vermeide Unterstriche in Namen und Domains! Let's Encrypt mag die nicht, und du bekommst Zertifikatsfehler.
Die Pipeline
Erstelle im Repository die Datei .forgejo/workflows/deploy.yml:
name: Build and Deploy
on:
push:
branches:
- main
jobs:
deploy:
runs-on: docker
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H DEINE_SERVER_IP >> ~/.ssh/known_hosts
- name: Deploy
env:
APP_NAME: ${{ vars.APP_NAME }}
DOMAIN: ${{ vars.DOMAIN }}
run: |
SERVER="root@DEINE_SERVER_IP"
DEPLOY_PATH="/opt/apps/${APP_NAME}"
# Verzeichnis erstellen
ssh $SERVER "mkdir -p ${DEPLOY_PATH}"
# Dateien übertragen
tar --exclude='.git' --exclude='.forgejo' -czf - . | \
ssh $SERVER "cd ${DEPLOY_PATH} && tar -xzf -"
# Umgebungsvariablen setzen
ssh $SERVER "cat > ${DEPLOY_PATH}/.env << EOF
APP_NAME=${APP_NAME}
DOMAIN=${DOMAIN}
EOF"
# Container neu starten
ssh $SERVER "cd ${DEPLOY_PATH} && docker compose up -d --build"
echo "Deployed to https://${DOMAIN}"
Docker Compose für deine App
Die docker-compose.yml im Repository:
services:
app:
build: .
container_name: ${APP_NAME}
restart: unless-stopped
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.${APP_NAME}.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.${APP_NAME}.entrypoints=websecure"
- "traefik.http.routers.${APP_NAME}.tls.certresolver=letsencrypt"
networks:
traefik-public:
external: true
Dockerfile
Für eine einfache statische Seite:
FROM nginx:alpine
COPY public/ /usr/share/nginx/html/
Für eine Node.js-App:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
Push und beobachten
git add .
git commit -m "Initial deployment setup"
git push -u origin main
Gehe in Forgejo zu Actions und beobachte, wie dein Code automatisch deployt wird. Nach ein paar Sekunden ist deine App unter https://meine-app.deine-domain.de erreichbar – mit gültigem SSL-Zertifikat.
Der Workflow im Alltag
Ab jetzt ist Deployen trivial:
# Änderungen machen
git add .
git commit -m "Neues Feature"
git push
Das war's. Die Pipeline baut und deployed automatisch. Du kannst den Fortschritt in Forgejo unter Actions verfolgen.
Troubleshooting
SSL-Zertifikat fehlt oder ungültig:
- Prüfe, ob Unterstriche in der Domain sind (ersetze
_durch-) - Schau in die Traefik-Logs:
docker logs traefik
Pipeline startet nicht:
- Ist die Workflow-Datei in
.forgejo/workflows/? - Pushst du auf den
main-Branch? - Ist der Runner online? (Admin → Actions → Runners)
SSH-Fehler:
- Ist der Private Key korrekt im Secret hinterlegt?
- Ist der Public Key auf dem Server?
- Stimmt die Server-IP in der Pipeline?
Container startet nicht:
- Logs prüfen:
docker logs CONTAINER_NAME - Ist das
traefik-publicNetzwerk vorhanden?
Fazit
Mit Forgejo, Traefik und Docker hast du eine komplette DevOps-Infrastruktur auf deinem eigenen Server. Kein Vendor Lock-in, volle Kontrolle, und du lernst dabei, wie die Tools funktionieren, die du sonst als Black Box nutzt.
Das Setup braucht initial etwas Zeit, aber danach ist es wartungsarm und skaliert gut. Du kannst beliebig viele Projekte hinzufügen – jedes mit eigener Domain und automatischem Deployment.
Nächste Schritte:
- Richte automatische Backups für Forgejo ein
- Füge ein Monitoring hinzu (z.B. Uptime Kuma)
- Experimentiere mit verschiedenen App-Typen
Viel Spaß beim Selbsthosten!