Self-Hosting Git with Gitea: A Lightweight GitHub Alternative
GitHub is free for public repositories and generous with private ones. GitLab offers a complete DevOps platform. So why would anyone self-host their own Git forge?
Gitea is a lightweight, self-hosted Git service that runs on minimal resources while providing the features most developers actually use: repositories, pull requests, issues, CI/CD, and package registries.
This guide covers when self-hosted Git makes sense, how Gitea compares to the alternatives, and how to set it up properly.
Why Self-Host Git?
Let's be honest about the trade-offs upfront:
Good reasons to self-host
- Data sovereignty — Your code never leaves your infrastructure. Required by some industries and compliance frameworks (HIPAA, SOC 2, defense contracts).
- No vendor lock-in — GitHub's terms of service have changed before. Self-hosting means you own the platform.
- Internal tooling — If you need Git hosting behind a corporate firewall with no cloud dependency.
- Cost at scale — GitHub Enterprise at $21/user/month gets expensive with 100+ developers. Gitea is free.
- Learning — Running your own forge teaches you about Git protocols, CI/CD infrastructure, and systems administration.
Bad reasons to self-host
- You think GitHub is "too expensive" — GitHub Free gives you unlimited private repos. If you're a small team, just use GitHub.
- You want better features — GitHub and GitLab have vastly more features than any self-hosted alternative. Gitea is catching up but isn't there yet.
- Security theater — Self-hosting doesn't automatically make your code more secure. You need to maintain the server, apply updates, and handle backups. GitHub has a world-class security team; you probably don't.
Gitea vs. the Competition
| Feature | Gitea | Forgejo | GitLab CE | GitHub |
|---|---|---|---|---|
| Resource usage | ~100 MB RAM | ~100 MB RAM | 4+ GB RAM | N/A (SaaS) |
| Setup time | 5 minutes | 5 minutes | 30-60 minutes | N/A |
| Built-in CI/CD | Yes (Actions) | Yes (Actions) | Yes (powerful) | Yes (Actions) |
| Package registry | Yes | Yes | Yes | Yes |
| Issue tracking | Basic | Basic | Advanced | Advanced |
| Code review | Good | Good | Excellent | Excellent |
| Container registry | Yes | Yes | Yes | Yes |
| License | MIT | GPL | MIT (CE) | Proprietary |
Gitea vs. Forgejo: Forgejo is a Gitea fork created after governance concerns. They're functionally identical for most users. Forgejo is community-governed; Gitea is backed by a company. Pick whichever you prefer — the setup is the same.
Gitea vs. GitLab CE: GitLab is far more feature-rich (built-in CI/CD pipelines, security scanning, project management) but requires 10-40x more resources. If you need GitLab's features, use GitLab. If you want something lightweight, use Gitea.
Installation
Gitea is a single binary with an embedded database option, but Docker is the easiest path for production:
# docker-compose.yml
services:
gitea:
image: gitea/gitea:1.22
restart: unless-stopped
ports:
- "3000:3000" # Web
- "2222:22" # SSH
volumes:
- gitea_data:/data
environment:
GITEA__database__DB_TYPE: sqlite3
GITEA__server__ROOT_URL: https://git.example.com/
GITEA__server__SSH_DOMAIN: git.example.com
GITEA__server__SSH_PORT: 2222
volumes:
gitea_data:
That's it. Run docker compose up -d, visit port 3000, and complete the setup wizard.
For teams of 10+ or if you need better performance, switch to PostgreSQL:
services:
gitea:
image: gitea/gitea:1.22
restart: unless-stopped
ports:
- "3000:3000"
- "2222:22"
volumes:
- gitea_data:/data
environment:
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: db:5432
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: ${DB_PASSWORD}
depends_on:
- db
db:
image: postgres:16-alpine
restart: unless-stopped
volumes:
- db_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: gitea
POSTGRES_USER: gitea
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
gitea_data:
db_data:
Gitea Actions: CI/CD
Gitea Actions is compatible with GitHub Actions workflow syntax. Most simple GitHub Actions workflows run on Gitea without modification.
Enable it in app.ini:
[actions]
ENABLED = true
Then register a runner:
docker run -d \
--name gitea-runner \
-e GITEA_INSTANCE_URL=https://git.example.com \
-e GITEA_RUNNER_REGISTRATION_TOKEN=<token> \
-v /var/run/docker.sock:/var/run/docker.sock \
gitea/act_runner:latest
Your .gitea/workflows/ci.yml (or .github/workflows/ci.yml) files work the same way:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm install
- run: npm test
Note: Complex GitHub Actions that use GitHub-specific APIs (like actions/cache with GitHub's cache service) won't work without modification.
Migrating from GitHub
Gitea has a built-in migration tool that imports:
- Repository (code, branches, tags)
- Issues and comments
- Pull requests
- Labels and milestones
- Releases
Go to New Migration → GitHub, enter a personal access token, and select the repositories to import. It handles the rest.
For bulk migration, use the API:
curl -X POST "https://git.example.com/api/v1/repos/migrate" \
-H "Authorization: token YOUR_GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"clone_addr": "https://github.com/owner/repo",
"auth_token": "GITHUB_PAT",
"repo_name": "repo",
"mirror": true,
"service": "github"
}'
Set "mirror": true to keep the Gitea copy in sync with GitHub — useful during transition periods.
Resource Usage
This is where Gitea really shines:
| Metric | Gitea | GitLab CE |
|---|---|---|
| Idle RAM | 80-150 MB | 3-6 GB |
| Disk (empty) | ~100 MB | ~2 GB |
| Cold start | 2-3 seconds | 2-5 minutes |
| Min VPS | $5/month (1 GB) | $20+/month (4 GB) |
Gitea runs comfortably on a Raspberry Pi. GitLab requires a proper server.
Backup
Gitea includes a built-in backup command:
docker exec gitea gitea dump -c /data/gitea/conf/app.ini
This creates a zip archive containing the database, repositories, and configuration. Store it off-site.
For continuous backups, the Git repositories in /data/git/repositories/ can be incrementally backed up with rsync or restic.
The Bottom Line
Self-hosting Git makes sense in specific scenarios: compliance requirements, large teams where per-user costs add up, or environments where cloud access is restricted. For most individual developers and small teams, GitHub Free is hard to beat.
If you do decide to self-host, Gitea is the best balance of features and resource efficiency. It won't give you GitHub's ecosystem of integrations and community, but it gives you a fast, reliable Git forge that you control completely.