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.
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:
- In Gitea, click + → New Migration
- Clone Address:
https://github.com/user/repo.git - Repository Name:
my-mirrored-repo - Mirror: Toggle ON
- 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.