Gitea
Lightweight self-hosted Git service
Gitea is a lightweight, self-hosted Git service offering repositories, issues, pull requests, and CI integration. It targets developers and teams who want a fast, easy-to-run code platform. It is deployed via Docker or a single binary.
Gitea setup guides & articles
Hands-on coverage of Gitea from the blog.
Key features
- Fast single-binary Git server
- Issues, PRs and wiki
- Built-in package registry
- Gitea Actions CI
Quick deploy
A starting point for self-hosting Gitea - check the official docs for the full set of options.
- Image
gitea/gitea:latest - Web port
3000 - Persist
/data
Docker Compose
services:
gitea:
image: gitea/gitea:latest
ports:
- "3000:3000"
- "222:22"
environment:
- USER_UID=1000
- USER_GID=1000
volumes:
- ./data:/data
restart: unless-stoppeddocker run
docker run -d --name gitea \
-p 3000:3000 \
-p 222:22 \
-e USER_UID=1000 \
-e USER_GID=1000 \
-v ./data:/data \
--restart unless-stopped \
gitea/gitea:latestWatch out for
- Map container SSH to a spare host port (222 here) - clone URLs will include it
Pros & cons
Strengths
- Very lightweight
- Easy to deploy
- Familiar GitHub-like UI
Trade-offs
- Fewer features than GitLab
- Governance concerns spurred a fork
Gitea replaces
Last reviewed Aug 24, 2026 · 717 words
Gitea gives you a GitHub-shaped forge — repos, issues, pull requests, packages, CI — in a single Go binary that idles around 256 MB, which means the spare mini PC can host every repository you own with room to spare. The install is genuinely easy; this guide is about the four decisions that make the instance still pleasant in year three: SSH strategy, mirrors, Actions, and backups.
Decide the SSH story on day one
Git over SSH wants port 22, and your host's own sshd already owns it. Three options, in rising order of elegance: map the container to a spare port (222:22) and live with ssh://git@host:222/... clone URLs; run Gitea's built-in SSH on the alternate port and standardise it in every ~/.ssh/config (Host gitea + Port 222 makes URLs clean again); or give the container its own IP/DNS name so it can own a real port 22. The first is what everyone does, the second is the first done properly, and changing later means touching every clone's remote — hence day one. HTTP(S) cloning through your reverse proxy works regardless and is fine for read-heavy use.
Mirrors: the killer feature nobody sets up
Gitea can pull-mirror any GitHub/GitLab repository on a schedule — your starred projects, your own repos, the dependencies you'd hate to lose — turning your forge into automatic insurance against upstream deletion, license rug-pulls, and account lockouts. New Migration → select "mirror", done; Gitea re-syncs on an interval. The inverse, push mirroring, keeps your canonical Gitea repos mirrored to GitHub for visibility and contributions while your infrastructure stays primary. Together they answer the "but my stuff lives on GitHub" objection with "it lives in both places, and I control one of them" — the self-hosted git forge argument in practical form.
Actions: powerful, and the runner is the risk
Gitea Actions speaks GitHub Actions' workflow syntax, and most simple workflows port with a find-and-replace of action URLs. The architecture matters more than the syntax: the act_runner executes jobs, and a runner executes whatever code a repository's workflow tells it to — so treat runners as untrusted-code engines. Run them in Docker on a box you'd tolerate being compromised, never on the Gitea host itself with a mounted docker socket, and don't enable Actions for mirrored third-party repos (mirrored code you don't review shouldn't get compute). For a homelab, one containerised runner labeled for your own repos covers CI for everything you write, with build caches making second runs pleasantly fast.
One command backs up everything
gitea dump produces a single zip containing the database, repositories, config, and attachments — the complete instance. Schedule it, ship it off-box per 3-2-1, and practice the restore once (unzip, restore DB, point config at the repos — twenty minutes). Two settings worth flipping before others join: DISABLE_REGISTRATION = true after your accounts exist (a public forge signup page attracts spam bots with remarkable speed), and if the instance faces the internet at all, fail2ban or CrowdSec watching the login endpoint. Upgrades are the pull-and-restart kind, with release notes that rarely bite — check the breaking-changes section when crossing minor versions and you'll be fine.
The Forgejo question, briefly
Gitea has a community-governed hard fork, Forgejo, born from governance concerns when Gitea's trademark moved to a company; features remain close, migration Gitea→Forgejo is supported, and the reverse isn't. If that history changes your calculus, the full comparison walks through it — the short version is that existing happy Gitea instances have no urgent reason to move, and new values-driven installs should consider starting on Forgejo.
What I'd do
Gitea in Docker with 222:22 plus an ~/.ssh/config entry, registration closed, pull-mirrors of every repo I'd cry about losing, one sandboxed Actions runner, nightly gitea dump to the backup box, CrowdSec if exposed. The result costs less RAM than a browser tab and removes GitHub from the list of companies whose policy changes can touch your work — which, for infrastructure this cheap to run, is a remarkable trade.
Compare Gitea
11 head-to-head comparisons.
Similar git hosting & forges apps
Gogs
Git Hosting & ForgesPainless self-hosted Git service
Replaces GitHub, Bitbucket
GitLab CE
Git Hosting & ForgesComplete DevOps platform you can self-host
Replaces GitHub, Bitbucket
OneDev
Git Hosting & ForgesSelf-hosted Git server with CI/CD and kanban
Replaces GitHub, GitLab
GitBucket
Git Hosting & ForgesGit platform powered by Scala with GitHub-like UI
Replaces GitHub
GitLab Runner
Git Hosting & ForgesRun CI/CD jobs for GitLab on your own infrastructure
Replaces GitHub Actions runner
Soft Serve
Git Hosting & ForgesSelf-hostable Git server for the command line
Replaces GitHub