From GitHub to Git Home: Self-Hosting Your Repositories with Gitea
Own your code, history and all

Git was designed to be distributed. Every clone is a full copy of the history, which means no single server is special and no company holds your project hostage. Yet somewhere along the way the world decided that “git” and “GitHub” were synonyms, and a vast amount of the world’s source code now lives on infrastructure owned by a single corporation. That is convenient right up until it is not. If you have ever wanted a home for your repositories that you fully control, that runs on a Raspberry Pi or a spare VPS, and that boots in milliseconds, Gitea is the answer. This guide gets you from nothing to a running, self-hosted git forge you can push to over SSH.
1 Why Self-Host Your Git
The most obvious reason is ownership. When your code lives on someone else’s platform, you live by their terms of service, their pricing changes, their outages, and their decisions about what is and is not acceptable. Self-hosting puts the repository, the issues, the pull requests, and the entire history on hardware you control. If you can reach the box, you can reach your code.
Privacy is the second reason. Private repositories on a hosted service are private only in the sense that the company promises not to look. For genuinely sensitive work, internal tooling, client projects under NDA, or simply a personal preference to keep your half-finished experiments off the public cloud, running your own forge removes a whole category of trust assumptions.
Then there is sheer practicality. A self-hosted forge that you run is also a forge that you understand, back up, and bend to your needs. There is no rate limiting on your own clones, no surprise feature deprecation, and no monthly bill scaling with the number of collaborators.
2 What Gitea Actually Is
Gitea is a lightweight, self-hosted git service written in Go. It offers the things you actually use from a hosted forge: a web interface for browsing code, pull requests, issue tracking, a wiki, organisations and teams, fine-grained access control, and increasingly a built-in CI system. It looks and feels familiar enough that anyone who has used GitHub will be productive within minutes.
Its defining trait is how little it asks of your server. Because it ships as a single self-contained binary with no heavy runtime, it runs happily on a Raspberry Pi or the smallest VPS your provider sells, consuming a fraction of the resources of a full GitLab installation. GitLab is a magnificent, all-encompassing DevOps platform, but it expects gigabytes of RAM and a small zoo of background services. Gitea does the core job in a sliver of that footprint, which is why it has become the default choice for home labs and small teams.
3 Installing with Docker Compose
The cleanest way to run Gitea is with Docker Compose alongside a proper database. SQLite works for a solo setup, but PostgreSQL scales better and is the sensible default if more than one person will use it. Create a directory and a docker-compose.yml:
services:
server:
image: gitea/gitea:1.22
container_name: gitea
environment:
- USER_UID=1000
- USER_GID=1000
- GITEA__database__DB_TYPE=postgres
- GITEA__database__HOST=db:5432
- GITEA__database__NAME=gitea
- GITEA__database__USER=gitea
- GITEA__database__PASSWD=changeme
restart: always
volumes:
- ./gitea:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "2222:22"
depends_on:
- db
db:
image: postgres:16
container_name: gitea-db
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=changeme
- POSTGRES_DB=gitea
restart: always
volumes:
- ./postgres:/var/lib/postgresql/dataNote the SSH port mapped to 2222 on the host so it does not collide with the server’s own sshd on port 22. Bring it up:
docker compose up -d
docker compose logs -fGitea is now listening on port 3000.
4 First-Run Setup
Open http://your-server:3000 in a browser and you are greeted by the installation page. Most defaults are already correct because the compose file injected the database settings through environment variables, but a few fields matter.
- Confirm the database connection details match your compose file.
- Set the Server Domain and the Gitea Base URL to the address users will actually type, for example
git.example.com. Getting this wrong now means clone URLs come out malformed later. - Set the SSH Server Port to
2222to match the mapping above. - Expand the optional settings and create your administrator account immediately. If you skip this, the first user to register becomes admin, which is rarely what you want on a public-facing instance.
Submit, and after a moment of initialisation you land on a fully working forge with your admin account ready.
5 Creating a Repository and Pushing
Click the plus icon, choose New Repository, give it a name, and decide whether it is private. Gitea hands you the clone URLs exactly as GitHub does. To push an existing local project over HTTPS:
cd my-project
git remote add origin https://git.example.com/yourname/my-project.git
git push -u origin mainFor day-to-day work, SSH is smoother because it avoids typing credentials. Add your public key under Settings, SSH Keys, then remember that custom port:
git remote set-url origin \
ssh://[email protected]:2222/yourname/my-project.git
git pushTo avoid specifying the port every time, add a host entry to your ~/.ssh/config:
Host git.example.com
Port 2222
User gitNow plain git push over SSH just works.
6 Actions and Built-In CI
Recent Gitea versions include Gitea Actions, a CI system deliberately compatible with the GitHub Actions workflow syntax. That means many existing .github/workflows YAML files run with little or no modification. Actions are disabled by default and require a separate runner. Enable them in your configuration, then register a runner:
docker run -d --name gitea-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
-e GITEA_INSTANCE_URL=https://git.example.com \
-e GITEA_RUNNER_REGISTRATION_TOKEN=<token> \
gitea/act_runner:latestDrop a workflow file into .gitea/workflows/ (or reuse a .github/workflows/ one) and pushes trigger builds on your own hardware, with no third-party minutes to budget.
7 Mirroring from GitHub
You do not have to choose abruptly between platforms. Gitea can mirror an external repository, pulling changes on a schedule so your instance always holds a current copy. When creating a repository, choose New Migration, paste a GitHub URL, and tick This repository will be a mirror. Gitea will clone it and keep it synchronised.
This is an excellent migration strategy and an even better backup strategy: keep developing on GitHub for visibility while your self-hosted Gitea quietly mirrors everything, so if the upstream ever disappears you lose nothing. The reverse, push mirroring, lets your Gitea instance push to an external remote, handy for keeping a public GitHub copy of a project you primarily develop at home.
8 Backing It Up
A self-hosted service is only as trustworthy as its backups. Gitea’s state lives in two places: the data volume holding repositories and configuration, and the database. The simplest robust approach is to stop the containers and archive both directories:
docker compose stop
tar czf gitea-backup-$(date +%F).tar.gz gitea postgres
docker compose startFor a hot backup that avoids downtime, use Gitea’s built-in dump command, which bundles repositories, the database, and configuration into one archive:
docker compose exec server gitea dump -c /data/gitea/conf/app.iniWhichever route you take, copy the resulting archive off the machine. A backup that only exists on the server it is meant to protect is not a backup.
9 When GitHub Is Still the Right Call
Self-hosting is not a moral victory to be pursued at all costs. If your goal is maximum visibility for an open-source project, GitHub’s network effect is real: that is where contributors already are, where the ecosystem of integrations lives, and where a star count signals legitimacy. If you need bulletproof uptime without becoming your own sysadmin, a hosted platform absorbs that operational burden for you. And the moment you self-host, you own the patching, the backups, and the 3am pager when the disk fills. Many people run both: public projects on GitHub for reach, and private or personal work on Gitea for control. That hybrid is not a compromise; it is just using the right tool for each job.
10 Conclusion
Gitea gives you a real git forge that runs on hardware you control, sips resources, and feels instantly familiar. In one Docker Compose file you have repositories, issues, pull requests, CI, and mirroring, all owned outright. Push your first repo over SSH, set up a nightly backup, mirror your important GitHub projects as insurance, and you have brought your code home without giving up any of the conveniences that made hosted forges popular in the first place.