A self-hosted git server is one of three options: Gitea (lightweight, ~256 MB RAM, single binary), GitLab (full feature set, ~4 GB RAM, omnibus install), or a bare SSH repo on a shared host (zero install, just git init --bare). Pick by team size: 1-5 developers use bare SSH, 5-20 use Gitea, 20+ use GitLab or Gitea with CI.
Table of contents
- The three options at a glance
- Bare SSH repo (the 5-minute option)
- Gitea (the right balance)
- GitLab (the full feature set)
- Picking between them
- How this fits the rest of the stack
- FAQ
The three options at a glance
Bare SSH repo - the simplest. A git init --bare directory on any SSH-accessible host, push via git remote add origin ssh://user@host/path/to/repo. No web UI, no issue tracker, no CI. The team that needs a quick private git server for a single project uses this.
Gitea - the lightweight forge. Single binary, Postgres or SQLite backend, web UI, pull requests, issues, package registry, basic CI. Runs in 256 MB RAM. The team that needs more than bare git but does not want GitLab’s weight uses Gitea.
GitLab - the full feature set. Merge requests, CI runners, container registry, security scanning, audit events. The Omnibus install on Ubuntu is 15 minutes. The team that wants GitHub-equivalent features behind their firewall uses this.
Bare SSH repo (the 5-minute option)
On the server:
mkdir -p /srv/git/myrepo.git
cd /srv/git/myrepo.git
git init --bare
On the client:
git remote add origin ssh://user@server/srv/git/myrepo.git
git push -u origin main
That is the entire setup. The team that wants SSH key-only access adds authorized_keys with command="..." restrictions, or just trusts the host’s SSH config.
For multiple users, the team that has a git Unix group adds the user, sets group ownership on the repo, and configures git config --global --add safe.directory /srv/git/myrepo.git to suppress the dubious-ownership warning.
Gitea (the right balance)
Install: one binary. Download from gitea.io, drop in /usr/local/bin/gitea, create a git user, write a systemd unit, and start. Or use the Docker image.
Config at /etc/gitea/app.ini - the defaults work for a small team. The team that has 5+ developers sets the database to Postgres (not SQLite), enables LFS, and configures SMTP for notifications.
Migration from Gitea to GitLab or GitHub later: Gitea supports the standard git push protocol, and Gitea has built-in import from GitHub, GitLab, and others. The team that starts on Gitea and outgrows it has an exit.
GitLab (the full feature set)
See the self-hosted GitLab post for the full Omnibus install walkthrough. The summary: apt install, set external_url, run reconfigure, log in with the initial root password.
The team that uses GitLab uses it for the merge request workflow, the CI/CD, and the container registry. The team that does not need those three pieces picks Gitea.
Picking between them
1-5 developers, no CI needed: bare SSH. Fastest setup, no maintenance, no web UI to leave running. The team that outgrows it later migrates to Gitea (which can import bare git repos).
5-20 developers, want pull requests and a UI: Gitea. Light enough to run on a Raspberry Pi 4, full enough for most teams. The team that does not want to manage GitLab’s complexity starts here.
20+ developers, or need compliance / audit / security scanning: GitLab. The Omnibus is heavy but every feature is there.
Want zero ops: a managed git host (GitHub, GitLab.com, Bitbucket). The trade-off: the code is on a third party’s servers.
FAQ
Is Gitea the same as Gogs?
Gitea is a fork of Gogs. Both are lightweight self-hosted git services, but Gitea has more active development and more features. The team that picks one today picks Gitea - the project is more alive.
Can I move from bare SSH to Gitea later?
Yes. Add the bare repo to Gitea via the UI (Repository -> Migrate -> Other), point at the local path, and Gitea imports the history. The team that starts on bare SSH and outgrows it migrates in 10 minutes.
Do I need HTTPS for the git server?
For web UI: yes. For SSH-based git push/pull: no, SSH is its own secure transport. The team that exposes only SSH for git operations can skip the HTTPS layer entirely (most do).
What about CI?
Gitea has Gitea Actions (YAML workflows, similar to GitHub Actions). GitLab has built-in CI. Bare SSH has no CI - the team that needs CI adds a separate runner (Woodpecker, Drone, Jenkins).
Is this any different from running git on a local dev box?
The local dev box is a client, not a server. The team that uses GitHub or a local-only git workflow does not have a server. The self-hosted git server is for collaboration - multiple people pushing to a shared remote.
How this fits the rest of the stack
For a sense of what the full project costs before it commits, the RunxBuild hosting calculator shows the line items together. The API, the database, the storage, the worker, the bandwidth - each one is a separate number, and the team’s mental model for the platform is the sum of those numbers.
Useful related references: