Building a Self-Hosted Git Server with Gitea
Why Self-Hosted Git?
Hosting your own Git server gives you:
- Complete control over your code and data
- No dependency on external services
- Privacy for sensitive projects
- Integration flexibility with your infrastructure
- Cost savings for large teams
What is Gitea?
Gitea is a self-hosted Git service written in Go. It’s lightweight, easy to deploy, and requires minimal resources—perfect for homelabs.
Key Features
- Minimal resource usage (can run on 1GB RAM)
- Simple installation with single binary or Docker
- Built-in issue tracking and pull requests
- Team collaboration features
- Webhook support for CI/CD integration
- Repository mirroring
Installation with Docker
1. Create Directories
mkdir -p ~/gitea/data ~/gitea/config
2. Docker Compose Setup
Create docker-compose.yml:
version: '3.8'
services:
db:
image: postgres:15-alpine
container_name: gitea-db
environment:
POSTGRES_DB: gitea
POSTGRES_USER: gitea
POSTGRES_PASSWORD: your_secure_password
volumes:
- ./data/postgres:/var/lib/postgresql/data
networks:
- gitea
restart: unless-stopped
gitea:
image: gitea/gitea:latest
container_name: gitea
depends_on:
- db
environment:
- DB_TYPE=postgres
- DB_HOST=db:5432
- DB_NAME=gitea
- DB_USER=gitea
- DB_PASSWD=your_secure_password
- GITEA__SECURITY__INSTALL_LOCK=true
- GITEA__SERVER__ROOT_URL=https://git.example.com/
- GITEA__SERVER__DOMAIN=git.example.com
- GITEA__SERVER__HTTP_PORT=3000
- GITEA__SERVER__SSH_PORT=2222
volumes:
- ./data/gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
networks:
- gitea
restart: unless-stopped
networks:
gitea:
driver: bridge
3. Launch Gitea
docker-compose up -d
docker-compose logs -f gitea
Initial Configuration
- Access Gitea at
http://localhost:3000 - Complete the installation wizard
- Create your admin account
Configuration File
After first run, edit app.ini:
nano ~/gitea/data/gitea/conf/app.ini
Important Settings
[database]
DB_TYPE = postgres
HOST = db:5432
NAME = gitea
USER = gitea
PASSWD = your_secure_password
[repository]
ROOT = /data/git/repositories
SCRIPT_TYPE = bash
[repository.upload]
ENABLED = true
TEMP_PATH = data/tmp/uploads
ALLOWED_TYPES = image/jpeg|image/png|application/zip|application/gzip
MAX_FILE_SIZE = 50
[server]
DOMAIN = git.example.com
ROOT_URL = https://git.example.com/
HTTP_PORT = 3000
SSH_PORT = 2222
START_SSH_SERVER = true
[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
Setting Up HTTPS with Nginx
Create nginx.conf:
upstream gitea {
server 127.0.0.1:3000;
}
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://gitea;
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;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $server_name;
}
}
SSH Configuration
Generate SSH Keys
ssh-keygen -t ed25519 -C "[email protected]"
Add Key to Gitea
- Login to Gitea
- Click profile avatar → Settings
- SSH/GPG Keys → Add Key
- Paste your public key
Clone via SSH
git clone ssh://[email protected]:2222/username/repo.git
Creating Repositories
- Click “+” icon in top navigation
- Click “New Repository”
- Configure:
- Repository name
- Description
- Visibility (public/private)
- Initialize with README
Team Management
Create Organization
- Click “+” → New Organization
- Enter organization name
- Invite users
User Roles
- Owner: Full access
- Team Lead: Team management
- Member: Read/write access
- Regular User: Read-only access
Webhooks for CI/CD
Configure Webhook
- Go to Repository Settings
- Click Webhooks
- Add Webhook:
- URL:
https://jenkins.example.com/github-webhook/ - Events: Push, Pull Request
- Active: Yes
- URL:
Backup and Recovery
Backup Script
#!/bin/bash
BACKUP_DIR="/backups/gitea"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
# Stop Gitea
docker-compose stop gitea
# Backup database and data
tar -czf "$BACKUP_DIR/gitea_$TIMESTAMP.tar.gz" ~/gitea/data
# Start Gitea
docker-compose start gitea
# Keep last 30 days of backups
find "$BACKUP_DIR" -name "gitea_*.tar.gz" -mtime +30 -delete
Schedule with cron:
# 2 AM daily
0 2 * * * /path/to/backup.sh
Performance Tuning
Database Optimization
-- Connect to PostgreSQL
VACUUM ANALYZE gitea;
-- Recreate indexes
REINDEX DATABASE gitea;
Gitea Settings
[cache]
ADAPTER = memory
INTERVAL = 60
[session]
PROVIDER = memory
[queue]
TYPE = level
Security Hardening
- Disable Registration: Set
DISABLE_REGISTRATION = true - Require Sign-In: Set
REQUIRE_SIGNIN_VIEW = true - SSH Key Only: Disable password login
- Enable 2FA: Settings → Security → Two-Factor Authentication
- API Rate Limiting: Configure in
app.ini
Troubleshooting
Cannot access Gitea
docker-compose logs gitea
docker-compose restart gitea
SSH Connection Issues
# Test SSH connection
ssh -vvv -p 2222 [email protected]
# Check SSH service
docker-compose exec gitea gitea admin user check
Conclusion
Gitea provides a lightweight, self-hosted Git solution perfect for homelab environments. It handles code collaboration, issue tracking, and CI/CD integration without the complexity of larger solutions.