Gitea vs Forgejo vs GitHub: When Self-Hosted Git Stops Being a Weekend Project
Nate Holbrook
August 25, 2026
The first time you stand up Gitea on a Saturday, it feels like a magic trick. You point a domain at a box, paste a Docker Compose file, click through the installer, and twenty minutes later you have a login page that looks enough like GitHub to fool your muscle memory. You push a repo. The commit graph renders. You close the laptop and feel like you just cancelled a SaaS bill.
Then Monday happens. A colleague asks you to review a pull request from a phone. Dependabot is not there. The Actions tab is empty unless you wired a runner. Your 128 GB SSD is already 71 percent full because you mirrored three org repos “just to have a copy.” The TLS cert renews, the reverse proxy does not, and suddenly the forge you bragged about is a 502 that only you can fix.
That is the real comparison. Gitea versus Forgejo versus GitHub is not a feature matrix. It is a question about when a git host stops being a weekend project and starts being an on-call rotation of one.
What GitHub is actually selling you
People who leave GitHub usually list the wrong grievances. The search is slower than they remember. The UI got denser. Copilot upsells sit where blame used to be. Those are irritations. The product you are paying for is not a git remote. It is a pile of operational work you never agreed to do.
GitHub Actions minutes look cheap until a matrix build eats the free tier and you discover that self-hosted runners still need patching. Packages work until you hit the bandwidth conversation nobody had when the org was three people. Issues, Projects, CODEOWNERS, required reviewers, merge queues, secret scanning, and the social graph of stars and forks are not extras. They are why a private repo on github.com still feels lighter than a “simple” forge on your NAS.
I keep a rule on a sticky note above the rack: if the repo has more than one human who will be angry when it is down, it does not live only on my hardware. That rule has saved me more weekends than any backup script.
GitHub also hides identity work. SSO, org membership, and deploy keys are boring until a contractor leaves and you have to prove you rotated everything. Self-hosting makes those bytes and those accounts your problem on a Tuesday.
Gitea: the product that stayed a product
Gitea is still the fastest path from zero to a usable forge. The container is small. The installer is honest. SQLite is enough for a household. The web UI is familiar if you have lived in GitHub or GitLab. LFS works. Packages exist. Actions exist if you attach a runner. For a single operator who wants private repos, snippet paste, and a place to park Terraform modules, Gitea is still a good tool.
The catch is governance, not code. Gitea Ltd and the community split is not ancient history. It is why a lot of homelab writeups from 2023 now read like a fork recommendation. If you install Gitea today because a blog post told you to, you should know you are choosing a company-shaped project with a familiar name. That is not automatically bad. It is a relationship. Companies change licenses, change defaults, and change what “open” means when a cloud offering needs a moat.
On the box, Gitea’s failure modes are mundane. The SQLite file lives on the same volume as everything else until you move it. The built-in dump is easy to forget. Upgrades are usually fine until they are not, and the not is almost always “I skipped two releases and the migration panicked.” Actions runners are a second fleet. If you treat them like pets, they rot. If you treat them like cattle, you need a template and a place to put secrets that is not a world-readable env file in the compose directory.

I have watched Gitea look healthy in Uptime Kuma while git push hung for ninety seconds. The HTTP healthcheck hit the login page. The disk was fine. The problem was a stuck LFS transfer and a single worker that had decided to stop being useful. A TCP ping does not tell you that. A compose healthcheck that curls /api/healthz is better. A synthetic push of a tiny repo on a cron is the check that actually matches user pain.
Forgejo: the fork people actually mean
Forgejo started as a soft fork and became the default recommendation in a lot of self-hosting rooms for a reason that has nothing to do with commit hashes. People wanted a forge whose governance looked like a community project, not a company with a product roadmap that might diverge. If you are choosing in 2026 and you care about that, you are probably installing Forgejo even if you still say “Gitea” out of habit.
Day to day, the UIs are close enough that muscle memory transfers. That is a compliment and a trap. You will assume a setting exists because it existed last year in Gitea, or because GitHub taught you the noun. Then you will spend an evening in docs discovering that Actions, packages, and migration tools are almost the same and slightly not. “Almost” is where weekend projects go to die.
Forgejo Actions is the feature that makes the comparison with GitHub honest. You can run GitHub-compatible workflows on your own hardware. Compatible is not identical. Some actions assume github.com URLs, a runner image you did not build, or GITHUB_TOKEN permissions you have to recreate. You did not remove CI complexity. You moved it from a bill to a lab notebook.
Where Forgejo earns its keep is the same place Gitea does: private repos, fast LAN clones, and no surprise about who can see the family scripts. It does not replace GitHub’s social surface. You will not get drive-by issue hygiene or Dependabot-class noise unless you add Renovate and babysit another container. That graph is why public work still belongs on github.com.
The weekend-project failure modes
Every self-hosted forge I have helped a friend recover shared one of four stories. None of them are exotic.
Disk is the first pager
Git is compressible until it is not. LFS is never compressible in the way you hope. Container registries inside the forge are worse. A “small” homelab forge that also hosts your container images will fill a 512 GB volume faster than your media library if you tag every CI build. GitHub lets you ignore this until a billing email. Your NAS will not send a polite email. It will remount read-only or it will start serving 500s that look like a bug in the Go binary.
Put the git data on a volume you can grow. Put LFS and packages on a volume you can prune. Do not store dumps on the same disk as the live repos. That last sentence is the one people skip because the dump “is only twenty gigabytes.” Twenty gigabytes on a ninety-percent-full SSD is how you turn a backup into a crash.
Upgrades are not apt update
Compose pull && compose up feels like a package manager. It is not. Forges run schema migrations. They assume you read the release notes. They assume you are not jumping from a 1.21 image to whatever :latest means this week. Pin the tag. Read the migration notes. Take a dump before you pull. I have restored more forges from a skipped dump than from ransomware.
Forgejo and Gitea both document this. Operators still skip it because the last five upgrades were boring. Boring is how they train you.
CI is a second product
If you only need git push and a web diff, you can stop reading and install Forgejo. The moment you want tests on every pull request, you have adopted a CI platform. Forgejo Actions, Woodpecker, or a separate GitHub Actions runner pointed at a mirror are all valid. They are not free. Runners need images, secrets, and a cleanup policy. A runner that can reach your LAN is a privilege boundary. A runner that can push to the forge is a credential you will forget to rotate.
GitHub’s advantage here is not moral. It is that someone else already decided the defaults and will get paged when the control plane dies. You will get paged when your runner disk fills with dangling images at 2 a.m. because a workflow used :latest and never pruned.

Backups that have never been restored
A green Borg job is not a forge. I have a dump cron, a restic snapshot of the data volume, and a quarterly restore onto a throwaway VM. The restore is the part that finds the missing secret, the wrong UID in the volume, and the fact that your dump script stopped writing after a path change in March. GitHub’s backup story is “we run the company.” Yours is “I can clone every repo onto a laptop and still reconstruct issues, wiki pages, and package names.” If you cannot reconstruct issues, you did not back up a forge. You backed up git, which you already had on every developer machine.
Test the restore by creating a throwaway user and a throwaway repo, dumping, wiping the volume, and bringing it back. If that sentence makes you tired, you are not ready to move the repos other people depend on.
When GitHub still wins, even if you resent it
Public open source is still GitHub’s home field. Discovery, forks, Actions marketplace, and the social proof of a star count are not things you recreate on a domain your friends have to bookmark. If you want drive-by contributors, you stay on github.com or you accept that you will mirror and lose half the conversation.
Compliance theater is another win. A client who asks for SOC2-shaped access logs does not want a screenshot of your Forgejo admin panel. They want a vendor. You can argue that your box is more private. You will lose the procurement argument.
Mobile review is a smaller but real win. GitHub’s iOS and Android apps are not beloved. They exist. Most self-hosted forges are a mobile browser and a hope that the diff wraps. If you review on a train, that matters more than your feelings about Microsoft.
Finally, you cannot outsource identity to “I know everyone who has an account” once you add a contractor. GitHub’s org model is clumsy. It is still less clumsy than you reinventing offboarding in a notes file.
When self-hosting actually pays off
The cases that stay clean are narrower than Reddit implies.
Private family and personal repos that should never sit on a US host you do not control. Internal notes, tax scripts, home-assistant configs with secrets you already leaked once to a gist. A forge on your LAN with Tailscale for the laptop is a reasonable design. You are the only pager and the blast radius is you.
LAN-speed clones of large binary-adjacent repos. Game projects, photo pipelines, and monorepos with LFS objects that punish a coffee-shop VPN. GitHub over a 20 Mbps uplink is a lifestyle. Forgejo on a 2.5 GbE NAS is a different lifestyle. Just do not pretend the LFS objects are backed up because the git packfiles are.
Air-gapped or angry-network shops. If the box cannot talk to the internet, GitHub is not a product you can buy. Gitea or Forgejo plus a local runner is the whole market. This is also where people forget that Actions still need base images, and those images have to come from somewhere. Mirror the images. Write that down. You will not remember in six months.
A teaching lab. Students push to your forge. You reset it. Nobody’s internship depends on your UPS. This is the original weekend-project use case and it is still valid.
Gitea or Forgejo if you have already left GitHub
If you want the path of least resistance, Gitea still installs cleanly. If you want the community fork, install Forgejo and pin a version. Do not run both “to compare” on the same disk. I have seen that ticket. It is not funny when both UIs share repos and disagree on issue numbers.
GitHub’s migrators get you history, issues, and pull requests in a form that is good enough. They do not get Actions history or the exact permission model. Mirror until you have a restore test and a runner test. Two remotes is not failure. Two remotes with no documented winner is.
A practical split that survives contact with a job
Here is the layout I actually run. Public work and anything with external collaborators stays on GitHub. Private personal repos live on Forgejo behind Tailscale. No port 3000 on the WAN. The box is a used ThinkCentre, not a Pi, because I got tired of SD cards dying during gc.
CI is one runner VM with a prune cron and an allowlist of repos. It has a token that can write checks and read code, not my password manager. Backups are a dump plus the data volume, off-box, with a quarterly restore on the calendar.
That split is boring. Boring is the point. The weekend project becomes a problem when you try to make it a GitHub replacement instead of a git remote with a UI. If you do not even want issues, that remote can be smaller still: soft-serve versus Gitea is the split when a personal host does not need a forge.
The honest close
Install Forgejo if you want a household forge and you care who steers the project. Install Gitea if you want the name you already know and you accept a company on the other end. Stay on GitHub when other people will be angry at an outage, when you need the social graph, or when you are not willing to restore from backup with a timer running.
The moment your forge has users who are not you, it is no longer a weekend project. It is a small site. Small sites need pinned versions, separate volumes, a restore drill, and a rule about what still lives on someone else’s metal. Everything else is a theme and a compose file, and those are the easy parts.