Ein eigener Git Server bietet volle Kontrolle über Ihre Code-Repositories. Von einfachen Bare-Repositories bis zu kompletten Lösungen wie Gitea oder GitLab.

Bare Repository (Einfachste Methode)

Repository erstellen

# Verzeichnis erstellen
mkdir -p /srv/git/projekt.git
cd /srv/git/projekt.git

# Bare Repository initialisieren
git init --bare

# Berechtigungen
chown -R git:git /srv/git

Git-User erstellen

# Benutzer für Git-Zugriff
useradd -m -s /usr/bin/git-shell git

# SSH-Verzeichnis
mkdir -p /home/git/.ssh
chmod 700 /home/git/.ssh

# Authorized Keys
touch /home/git/.ssh/authorized_keys
chmod 600 /home/git/.ssh/authorized_keys
chown -R git:git /home/git/.ssh

SSH-Key hinzufügen

# Öffentlichen Schlüssel hinzufügen
echo "ssh-rsa AAAA... user@host" >> /home/git/.ssh/authorized_keys

Repository nutzen

# Klonen
git clone git@server:/srv/git/projekt.git

# Remote hinzufügen
git remote add origin git@server:/srv/git/projekt.git
git push -u origin main

Git Daemon (Read-Only)

Installation und Konfiguration

# Systemd Service
cat > /etc/systemd/system/git-daemon.service << EOF
[Unit]
Description=Git Daemon
After=network.target

[Service]
ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
Restart=always
User=git
Group=git

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now git-daemon

Repository freigeben

# Datei erstellen für Export
touch /srv/git/projekt.git/git-daemon-export-ok

Klonen via Git-Protokoll

git clone git://server/projekt.git

Gitea (Leichtgewichtiger Git Server)

Installation mit Docker

# docker-compose.yml

version: "3"

services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=postgres
      - GITEA__database__HOST=db:5432
      - GITEA__database__NAME=gitea
      - GITEA__database__USER=gitea
      - GITEA__database__PASSWD=gitea
    volumes:
      - ./gitea-data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "3000:3000"
      - "2222:22"
    depends_on:
      - db
    restart: always

  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=gitea
      - POSTGRES_PASSWORD=gitea
      - POSTGRES_DB=gitea
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    restart: always

Native Installation

# Benutzer erstellen
useradd -m -s /bin/bash git

# Binary herunterladen
wget -O /usr/local/bin/gitea https://dl.gitea.io/gitea/1.21/gitea-1.21-linux-amd64
chmod +x /usr/local/bin/gitea

# Verzeichnisse
mkdir -p /var/lib/gitea/{custom,data,log}
mkdir -p /etc/gitea
chown -R git:git /var/lib/gitea /etc/gitea
chmod 750 /etc/gitea

Systemd Service

# /etc/systemd/system/gitea.service

[Unit]
Description=Gitea
After=network.target postgresql.service
Wants=postgresql.service

[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

Web-Setup

http://server:3000/install

Einstellungen:
- Datenbank: PostgreSQL/MySQL/SQLite
- SSH Port: 22 oder 2222
- Repository Root: /var/lib/gitea/repositories
- Admin-Account erstellen

GitLab (Enterprise Features)

Docker Installation

# docker-compose.yml

version: '3.6'

services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    hostname: gitlab.example.com
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.example.com'
        gitlab_rails['gitlab_shell_ssh_port'] = 2222
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        letsencrypt['enable'] = false
    ports:
      - '80:80'
      - '2222:22'
    volumes:
      - ./gitlab-config:/etc/gitlab
      - ./gitlab-logs:/var/log/gitlab
      - ./gitlab-data:/var/opt/gitlab
    restart: always

Package Installation

# Debian/Ubuntu
curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | bash
apt install gitlab-ce

# Konfigurieren
vi /etc/gitlab/gitlab.rb
# external_url 'https://gitlab.example.com'

# Anwenden
gitlab-ctl reconfigure

Initiales Passwort

# Root-Passwort anzeigen
cat /etc/gitlab/initial_root_password

# Oder bei Docker
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

SSH-Konfiguration

Server-seitig

# /etc/ssh/sshd_config

# Git-User darf nur git-shell nutzen
Match User git
    AllowTcpForwarding no
    X11Forwarding no
    PermitTTY no
    ForceCommand /usr/bin/git-shell -c "$SSH_ORIGINAL_COMMAND"

Client-seitig

# ~/.ssh/config

Host gitserver
    HostName server.example.com
    User git
    IdentityFile ~/.ssh/id_git
    Port 22

# Nutzung
git clone gitserver:projekt.git

Nginx Reverse Proxy

Für Gitea

# /etc/nginx/sites-available/gitea

server {
    listen 80;
    server_name git.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name git.example.com;

    ssl_certificate /etc/letsencrypt/live/git.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/git.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket Support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        client_max_body_size 100M;
    }
}

Für GitLab

server {
    listen 443 ssl http2;
    server_name gitlab.example.com;

    ssl_certificate /etc/letsencrypt/live/gitlab.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/gitlab.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;

        proxy_read_timeout 300;
        proxy_connect_timeout 300;

        client_max_body_size 250M;
    }
}

Hooks

Server-seitige Hooks

# /srv/git/projekt.git/hooks/post-receive

#!/bin/bash
while read oldrev newrev refname; do
    branch=$(echo $refname | cut -d'/' -f3)

    if [ "$branch" == "main" ]; then
        # Deploy ausführen
        cd /var/www/html
        git pull origin main
        echo "Deployed to production"
    fi
done

Pre-receive Hook

#!/bin/bash
# /srv/git/projekt.git/hooks/pre-receive

# Commit-Message prüfen
while read oldrev newrev refname; do
    for commit in $(git rev-list $oldrev..$newrev); do
        msg=$(git log --format=%B -n 1 $commit)
        if ! [[ "$msg" =~ ^(feat|fix|docs|style|refactor|test|chore): ]]; then
            echo "Commit message must start with type: $msg"
            exit 1
        fi
    done
done

Backup

Bare Repositories

#!/bin/bash
# /usr/local/bin/git-backup.sh

BACKUP_DIR="/backup/git"
GIT_DIR="/srv/git"
DATE=$(date +%Y%m%d)

mkdir -p $BACKUP_DIR

for repo in $GIT_DIR/*.git; do
    name=$(basename $repo)
    tar -czf "$BACKUP_DIR/${name%.git}_$DATE.tar.gz" -C $GIT_DIR $name
done

# Alte Backups löschen
find $BACKUP_DIR -mtime +30 -delete

Gitea Backup

# Als gitea-User
sudo -u git gitea dump -c /etc/gitea/app.ini

# Erstellt gitea-dump-*.zip mit:
# - Datenbank
# - Repositories
# - Konfiguration

GitLab Backup

# Backup erstellen
gitlab-backup create

# Backups finden
ls /var/opt/gitlab/backups/

# Restore
gitlab-backup restore BACKUP=11234567890_2024_01_15_16.0.0

Migration

Von GitHub/GitLab zu eigenem Server

# Mirror-Clone
git clone --mirror https://github.com/user/repo.git

# Zu neuem Server pushen
cd repo.git
git push --mirror git@newserver:/srv/git/repo.git

Import in Gitea

1. Neues Repository erstellen
2. "Migration" wählen
3. URL eingeben
4. Token für private Repos

Zusammenfassung

| Lösung | Komplexität | Features | |--------|-------------|----------| | Bare Repository | Niedrig | Nur Git | | Git Daemon | Niedrig | Read-only | | Gitea | Mittel | Web UI, Issues, CI | | GitLab | Hoch | Enterprise, CI/CD |

| Port | Dienst | |------|--------| | 22/2222 | SSH (Git) | | 3000 | Gitea Web | | 80/443 | GitLab/Gitea Web | | 9418 | Git Daemon |

| Befehl | Funktion | |--------|----------| | git init --bare | Bare Repo erstellen | | gitea dump | Gitea Backup | | gitlab-backup create | GitLab Backup |

Fazit

Für kleine Teams reicht oft ein einfaches Bare Repository mit SSH-Zugang. Gitea bietet ein hervorragendes Preis-Leistungs-Verhältnis mit modernem Web-Interface und geringem Ressourcenverbrauch. GitLab ist die richtige Wahl für größere Teams, die Enterprise-Features wie CI/CD und Issue-Tracking benötigen. In jedem Fall ist ein durchdachtes Backup-Konzept essentiell.