Git Server on Raspberry Pi

Set up your own Git server on a Raspberry Pi using Gitea. Includes Docker deployment, SSH access, and backup configuration.

Andreas · April 12, 2026 · 8 min read

Introduction

Gitea is a lightweight Git server that runs in ~100 MB RAM. Self-host your repos without GitHub, GitLab, or Gitea Cloud. This guide covers Docker setup, SSH configuration, GitHub mirroring, and backup strategy. Perfect for private project storage or off-grid deployments.

Prerequisites

  • Raspberry Pi 4 (2GB+ RAM) or Pi 5
  • Docker and Docker Compose installed
  • 2GB free disk space minimum (10GB+ recommended for repos)
  • Domain name optional (local IP works fine for LANs)

Step 1 — Create Compose File

Create directory and compose file:

mkdir -p ~/docker/gitea
cd ~/docker/gitea
nano docker-compose.yml

Paste this configuration:

version: '3.8'

services:
  gitea:
    image: gitea/gitea:latest
    container_name: gitea
    ports:
      - "3000:3000"
      - "222:22"
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - GITEA__database__DB_TYPE=sqlite3
      - GITEA__server__ROOT_URL=http://pi-ip:3000
      - GITEA__server__SSH_PORT=222
      - GITEA__security__INSTALL_LOCK=false
      - TZ=UTC
    volumes:
      - gitea_data:/data
      - /etc/timezone:/etc/timezone:ro
    restart: unless-stopped
    networks:
      - gitea_network

volumes:
  gitea_data:

networks:
  gitea_network:
    driver: bridge

Replace pi-ip with your Pi's static IP (e.g., 192.168.1.100).

Step 2 — Launch Gitea

Start the container:

docker compose up -d

Verify it's running:

docker compose ps
docker compose logs -f gitea

Wait for [I] TCP listener (http:3000) starting on [::]:3000 message.

Step 3 — Initial Setup

Access web UI: http://pi-ip:3000

On first visit, you'll see setup page. Configure:

  • Database Type: SQLite3 (default, already set)
  • Site Name: My Gitea Server (or your choice)
  • Repository Root Path: /data/gitea-repositories
  • Run User: git
  • SSH Port: 222
  • Application URL: http://your-pi-ip:3000/

Create admin account:

  • Admin Username: admin
  • Admin Password: (generate strong password)
  • Admin Email: admin@example.com

Click Install Gitea.

Step 4 — Create Your First Repository

After setup, you're logged in. Click + icon → New Repository:

  • Repository Name: my-project
  • Visibility: Private (or Public)
  • Initialize with README: ✓ checked

Click Create Repository.

Step 5 — Configure SSH Access

Check container's SSH public key:

docker exec gitea cat /data/gitea/conf/ssh/gitea_host_key.pub

Save this (you may need it for reverse proxy setup).

From local machine, add SSH key to Gitea

Generate local key if you don't have one:

ssh-keygen -t ed25519 -C "your-email@example.com"

Log into Gitea web UI → Settings → SSH Keys. Add your public key (~/.ssh/id_ed25519.pub).

Clone via SSH

git clone ssh://git@pi-ip:222/admin/my-project.git

If using domain (via reverse proxy):

git clone ssh://git@gitea.example.com/admin/my-project.git

Step 6 — Mirror from GitHub

Create new repository in Gitea, then configure mirror:

  1. In Gitea, click +New Migration
  2. Clone Address: https://github.com/user/repo.git
  3. Repository Name: my-mirrored-repo
  4. Mirror: Toggle ON
  5. Create Repository

Gitea will pull updates from GitHub. To push back:

cd my-mirrored-repo
git remote add origin ssh://git@pi-ip:222/admin/my-mirrored-repo.git
git push -u origin main

Step 7 — Backup Strategy

Gitea stores everything in /data/gitea volume. Backup regularly:

Full backup

cd ~/docker/gitea
docker compose exec -u git gitea /app/gitea/gitea dump -c /etc/gitea/app.ini
docker cp gitea:/data/gitea-dump-*.zip ./backups/

Incremental (git repos only)

docker run --rm -v gitea_data:/data -v $(pwd)/backups:/backup \
  alpine tar czf /backup/gitea-$(date +%Y%m%d).tar.gz -C /data gitea-repositories

Restore from backup

docker compose down
docker volume rm gitea_data
docker volume create gitea_data
docker run --rm -v gitea_data:/data -v $(pwd)/backups:/backup \
  alpine tar xzf /backup/gitea-20240412.tar.gz -C /data
docker compose up -d

Step 8 — Add Reverse Proxy (Optional)

For external access via domain + HTTPS, use Traefik:

services:
  traefik:
    image: traefik:v2.11
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - traefik_config:/etc/traefik
    restart: unless-stopped

  gitea:
    # ... existing config ...
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gitea.rule=Host(`gitea.example.com`)"
      - "traefik.http.routers.gitea.entrypoints=web,websecure"
      - "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
      - "traefik.http.services.gitea.loadbalancer.server.port=3000"

Then update GITEA__server__ROOT_URL=https://gitea.example.com.

Step 9 — Useful Git Operations

Push to Gitea

git remote add origin ssh://git@pi-ip:222/admin/my-project.git
git push -u origin main

Pull latest

git pull origin main

List all repos (API)

curl http://pi-ip:3000/api/v1/admin/repos -H "Authorization: token <token>"

Get token from Settings → Applications.

Resource Usage

Metric Value
Idle RAM ~80 MB
With 5 users ~110 MB
SQLite DB (100 repos) ~150 MB
Git repo storage Variable (typically 10-500 MB per repo)

Troubleshooting

SSH key not working

Verify Gitea sees your key: Gitea UI → Settings → SSH Keys. Check /data/gitea/log/gitea.log for SSH errors.

docker compose logs gitea | grep -i ssh

Can't connect to http://pi-ip:3000

Check firewall: sudo ufw status. Allow port 3000 if needed:

sudo ufw allow 3000/tcp

Mirror pull hangs

Public GitHub mirror might rate-limit. Add GitHub token in mirror settings (GitHub → Settings → Developer settings → Personal access tokens).

Disk full

Check volume size: docker volume inspect gitea_data. Old backups in ./backups/ can be deleted to free space.

Summary

Gitea gives you a private Git server with GitHub-like UI, SSH access, and mirroring—all in ~100 MB RAM. Regular backups to external storage protect against disk failure. For production homelabs, pair with Traefik for remote HTTPS access and a reverse proxy for clean URLs.

Comments