So You Want to Own Your Git History
Take a breath. Close those tabs. You’ve been down this rabbit hole for two hours — GitHub alternatives, self-hosted options, “but what if Microsoft does something weird again” anxiety spirals — and you still haven’t made a decision.
Here’s the good news: all three of the tools we’re covering today are genuinely solid. Here’s the slightly annoying news: they’re built for very different situations, and picking the wrong one is like hiring a forklift to move a couch. Technically it works, but you’re going to regret it.
Let’s talk about why you’d self-host git in the first place, then dig into the three main contenders.
Why Self-Host Git At All?
Fair question. GitHub is free, reliable, and everyone already has an account. So why bother?
A few reasons:
- Privacy and data ownership. Your code, your server, your rules. No scanning for “safety,” no terms of service surprises, no wondering what Microsoft is doing with your private repos.
- CI/CD ownership. When you control the platform, you control the pipeline. No surprise billing because a workflow ran 3,001 minutes.
- Vendor lock-in avoidance. GitHub Actions syntax is GitHub-specific. Your self-hosted runner config isn’t going anywhere.
- The home lab itch. Let’s be honest — some of us just want more things running on our servers. There’s no shame in it.
If you’re storing your dotfiles and a few side projects, you could absolutely get away with GitHub forever. But if you’ve got a home lab, a small team, compliance requirements, or just a philosophical objection to renting your infrastructure from a trillion-dollar company, read on.
Gitea: The Little Git Server That Could
Gitea started as a fork of Gogs (another lightweight self-hosted git solution) back in 2016. The goal was simple: a fast, lightweight, self-contained git server that could run on basically anything — including a Raspberry Pi.
And it delivers. Gitea is written in Go, ships as a single binary, and will run comfortably in 512MB of RAM. You can run it on a VPS that costs less than a cup of coffee per month. It looks like GitHub, supports most of what you actually use day-to-day (issues, pull requests, wikis, webhooks, basic CI via Gitea Actions), and doesn’t try to be everything to everyone.
The trade-off is that it’s always been a bit of a corporate-adjacent project. The governance was… murky. Which brings us to the elephant in the room.
Forgejo: Same DNA, Community Soul
In late 2022, there was drama. The short version: a company called Gitea Ltd was incorporated, and several long-time contributors were uncomfortable with the direction — specifically around whether Gitea would remain a community-first project or drift toward being a commercially-driven one.
The result was Forgejo, a hard fork of Gitea, governed by the Codeberg e.V. nonprofit. The project explicitly positions itself as a “soft fork” for now, meaning it stays largely compatible with Gitea but is free to diverge when the community wants to go a different direction.
What’s actually different?
Right now? Not a lot at the surface level. Forgejo tracks Gitea closely, fixes things faster in some areas, and has a stronger governance story. The UI is nearly identical. The Docker image swaps are largely 1:1. If you care about the software being controlled by the community that uses it rather than a corporate entity, Forgejo is your pick. If you just want working software and don’t follow open source politics, you’ll barely notice the difference.
Forgejo has been adding features like federation support (via ActivityPub — imagine GitHub where your instance can interact with other instances) which is genuinely interesting for the future of decentralized code hosting.
For new deployments in 2024+, Forgejo is the safer long-term bet for most home lab and small team use cases.
GitLab CE: The Full DevOps Platform (and Your RAM’s Worst Enemy)
GitLab Community Edition is a different beast entirely. Where Gitea and Forgejo are “git hosting with some extras,” GitLab CE is a full DevOps platform that happens to include git hosting.
We’re talking:
- Built-in CI/CD with a mature pipeline syntax
- Container registry (host your own Docker images)
- Issue tracking, milestones, boards
- Code review workflows
- Wiki, snippets, Pages
- Security scanning (in EE, but the CE foundation is there)
- LDAP/SSO integration
- Kubernetes integration
It’s impressive. It’s also going to demand a server that costs more than your car payment.
GitLab CE wants 4GB of RAM at minimum — and that’s “technically boots” territory. Realistically you’re looking at 8GB for a comfortable single-server install with a few users and active CI/CD pipelines. The official recommendation for production is 8GB+, with 4 CPU cores. This is not a Raspberry Pi project.
GitLab is the right tool when you genuinely need the full platform. If you’re running a small development team with CI/CD pipelines, container builds, and need proper user management — it’s worth the resource cost. If you’re a solo dev who just wants to store your dotfiles, it’s like buying a commercial dishwasher for a studio apartment.
Docker Compose: Let’s Actually Run These Things
Gitea
version: "3"
services:
gitea:
image: gitea/gitea:latest
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=sqlite3
restart: unless-stopped
volumes:
- ./gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
That’s it. SQLite for a small instance, swappable to Postgres when you need it. Boots in seconds, idles at ~50MB RAM.
Forgejo
version: "3"
services:
forgejo:
image: codeberg.org/forgejo/forgejo:latest
container_name: forgejo
environment:
- USER_UID=1000
- USER_GID=1000
- FORGEJO__database__DB_TYPE=sqlite3
restart: unless-stopped
volumes:
- ./forgejo-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
Nearly identical to Gitea. Swap the image, swap the env prefix, done. The compatibility is intentional — migration between the two is straightforward.
GitLab CE (Resource-Limited)
version: "3"
services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
hostname: gitlab.yourdomain.com
restart: unless-stopped
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://gitlab.yourdomain.com'
# Reduce resource usage for smaller servers
puma['worker_processes'] = 2
sidekiq['max_concurrency'] = 5
prometheus_monitoring['enable'] = false
gitlab_rails['env'] = {
'MALLOC_CONF' => 'dirty_decay_ms:1000,muzzy_decay_ms:1000'
}
ports:
- "80:80"
- "443:443"
- "2222:22"
volumes:
- ./gitlab-config:/etc/gitlab
- ./gitlab-logs:/var/log/gitlab
- ./gitlab-data:/var/opt/gitlab
shm_size: "256m"
deploy:
resources:
limits:
memory: 6g
Note the tuning options — disabling Prometheus monitoring, limiting Puma workers and Sidekiq concurrency. Without these, GitLab will happily consume every byte of RAM on your server and then stare at you blankly when you ask why.
Pointing Existing Repos at Your Self-Hosted Server
Once you’re running, migrating existing repos is just a remote swap:
# Add your self-hosted instance as a new remote
git remote add selfhosted http://your-server:3000/username/repo.git
# Or replace origin entirely
git remote set-url origin http://your-server:3000/username/repo.git
# Push everything
git push selfhosted --all
git push selfhosted --tags
Feature & Resource Comparison
| Feature | Gitea | Forgejo | GitLab CE |
|---|---|---|---|
| Min RAM | ~256MB | ~256MB | 4GB |
| Recommended RAM | 512MB | 512MB | 8GB+ |
| CI/CD | Gitea Actions | Forgejo Actions | Full GitLab CI |
| Container Registry | No (plugin) | No (plugin) | Yes (built-in) |
| Issue Tracking | Basic | Basic | Full (boards, milestones) |
| Merge/Pull Requests | Yes | Yes | Yes |
| Wiki | Yes | Yes | Yes |
| LDAP/SSO | Yes | Yes | Yes (more mature) |
| Federation | No | In progress | No |
| Community Governance | Corporate | Nonprofit | Corporate (Red Hat/IBM) |
| Setup Complexity | Low | Low | High |
| Docker Image Size | ~100MB | ~100MB | 2GB+ |
Migration Paths
Gitea → Forgejo: This is the easiest migration you’ll ever do. Stop the Gitea container, point the same data volume at a Forgejo container, start it. Done. They use the same database schema for now.
GitHub/GitLab → Gitea/Forgejo: Both have built-in migration tools that can import repos, issues, pull requests, and wikis from GitHub, GitLab, Bitbucket, and others. Go to the “New Migration” screen and pick your source. It’s not perfect for large orgs, but for personal use it’s genuinely smooth.
Gitea/Forgejo → GitLab: Manual work. Export repos, recreate issues manually or via API. There’s no magic button here — GitLab’s data model is different enough that full migration tooling doesn’t really exist in the free tier.
Which One Should You Actually Pick?
Solo developer / home lab / “I just want to store my dotfiles”: Forgejo. Small footprint, community-driven, runs on anything, will outlive the drama. Gitea is fine too if you’re already comfortable with it.
Small team (2-10 people) with basic CI needs: Forgejo with Forgejo Actions, or Gitea. Add a Woodpecker CI instance alongside it if you want more CI power without the GitLab overhead. You get 90% of the workflow without the RAM bill.
Organization that needs full CI/CD pipelines, container registry, proper user management, and compliance features: GitLab CE. Yes it’s heavy. Yes it’ll cost you RAM. But it’s genuinely the most complete self-hosted DevOps platform available for free, and once it’s running it’s rock solid. Just make sure your server can handle it — don’t try to run this on 4GB shared RAM alongside eight other services.
The “I’m not sure” case: Start with Forgejo. It’s the lowest-risk entry point. If you hit the ceiling and need more, migrating to GitLab later is always an option. Going the other direction is harder.
The Bottom Line
There’s no prize for running the most complicated stack. If Forgejo on a $5 VPS stores your code, runs your webhooks, and gets out of your way — that’s a win. If your team needs the full GitLab experience and you’ve got the hardware to back it, GitLab CE is genuinely excellent.
The “I just want to store my dotfiles” crowd and the “I need a full DevOps platform” crowd are on opposite ends of a spectrum, and all three tools exist to serve different points on it. Pick the one that matches where you actually are — not where you think you might be in five years after a hypothetical company acquisition that probably won’t happen.
Now go spin something up. Your dotfiles deserve a home.