Gitea: A Lightweight Self-Hosted Git Server on Your VPS
The Problem: Your Repos Live on Someone Else's Servers
Most of my personal projects used to live on free Git services. While the projects were public, that was fine. Once they went private — client code, internal scripts, experiments not ready for other eyes — I found myself depending on someone else's quotas, rules, and policies. There were collaborator limits, features locked behind paid plans, and the nagging feeling that important code sat on servers I didn't own.
The fix isn't to stop using Git, but to move the server onto your own VPS. That's where Gitea comes in. Gitea is an open source Git server whose interface looks familiar if you've used any popular Git service: repo lists, issues, pull requests, wikis, and a package registry. The difference is that it runs on your server, and it's famously light — comfortable on a small VPS with 1–2 GB of RAM, far below what GitLab demands.
Below I'll walk through installing it with Docker Compose, together with a PostgreSQL database, then creating your first repo, migrating old repos, and turning on its built-in CI.
Gitea vs GitLab vs GitHub: Which One to Pick
| Gitea | Self-Hosted GitLab | GitHub | |
|---|---|---|---|
| RAM needs | Light, comfortable on 1–2 GB | Heavy, needs several GB | Not applicable (hosted service) |
| Installation | One Compose file, done in minutes | A much bigger, more complex install | No installation needed |
| Core features | Repos, issues, pull requests, wiki, Actions | All of that plus full DevOps | All of that plus the largest ecosystem |
| Data control | Full, on your server | Full, on your server | On GitHub's servers |
| Best for | Personal use and small teams | Large teams needing full DevOps | Public collaboration and open source |
My rule of thumb is simple: if all you need is a place to store and manage your own code — not a corporate-grade DevOps platform — Gitea is more than enough, and your VPS won't break a sweat.
Step 1: Prepare the VPS and Docker
You need an Ubuntu VPS with Docker and the Compose plugin already installed. If you haven't set that up yet, follow our Docker Compose guide first, then come back here. Also make sure ports 3000 (web) and 222 (Git SSH) aren't already used by other services on your VPS.
Step 2: Write the Gitea + PostgreSQL Compose File
Create a project folder and the compose file inside it:
sudo mkdir -p /opt/gitea && sudo chown $USER:$USER /opt/gitea
cd /opt/gitea
nano docker-compose.ymlFill it with the following configuration. The db service is PostgreSQL, the server service is Gitea itself:
services:
db:
image: postgres:16-alpine
container_name: gitea-db
restart: unless-stopped
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=ganti-dengan-password-kuat
- POSTGRES_DB=gitea
volumes:
- ./postgres-data:/var/lib/postgresql/data
server:
image: gitea/gitea:1.24
container_name: gitea
restart: unless-stopped
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=ganti-dengan-password-kuat
volumes:
- ./gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000"
- "222:22"
depends_on:
- dbFour things that are easy to miss here:
- The password in both places must match exactly, and don't use the example above — generate a strong random password.
USER_UIDandUSER_GID1000 are the Gitea user's UID/GID inside the container; these match the first user on Ubuntu in most cases. If your data folders belong to a different user, adjust the numbers so the container can write to them.- The port mapping
"222:22"means Git SSH is reached via port 222 on the host, since port 22 is usually already taken by the server's own SSH. Later, your SSH clone URLs will use port 222. - All data — repos, database, configuration — lives in
./gitea-dataand./postgres-data. As long as those two folders are safe, Gitea can be rebuilt at any time.
Start the stack:
docker compose up -d
docker compose psIf both services show running, open http://IP-VPS-Anda:3000 in your browser. You'll be greeted by Gitea's installation wizard.
Step 3: Complete the Installation Wizard
On the installation page, fill in the following:
- Database type: PostgreSQL, with host
db, port5432, database namegitea, usergitea, and the same password as in the compose file. The host namedbmatters here: it's the name of the database service inside the Docker Compose network. - Gitea base URL: enter the address you'll actually use, for example
http://IP-VPS-Anda:3000for the initial stage. If you later add a domain and HTTPS, update this value so the clone URLs and email links Gitea generates stay correct. - Administrator account: create your first admin account here. This account will manage users and site settings.
Click install, wait for it to finish, then log in with that admin account. Your Gitea is live.
Step 4: Create Your First Repo and Push Code
From the dashboard, click the new repo button, give it a name, and choose whether it's public or private. Once the repo is created, Gitea shows its clone URLs. From your laptop:
git clone ssh://git@IP-VPS-Anda:222/username/nama-repo.git
cd nama-repo
echo "# Proyek pertama di Gitea sendiri" > README.md
git add README.md
git commit -m "Commit pertama"
git push origin mainNote the ssh://git@IP-VPS-Anda:222/...: the user is git, and the port is 222, matching the mapping in the compose file. Before your first push, make sure your public SSH key has been added in your Gitea account settings (profile menu → SSH Keys). Without it, the server will reject your SSH connection.
Step 5: Move Old Repos with Mirroring
Moving repos from an old service doesn't mean re-downloading every commit by hand. The cleanest way is a mirror clone:
git clone --mirror https://github.com/username/repo-lama.git
cd repo-lama.git
git push --mirror ssh://git@IP-VPS-Anda:222/username/repo-lama.gitThe --mirror flag copies all branches, tags, and commit history. Once the push finishes, verify in Gitea's web UI that all branches and tags are complete, and only then decide whether the old repo on the old service stays as an archive or gets deleted.
Step 6: Enable CI with Gitea Actions
Gitea has built-in CI called Gitea Actions, which works much like GitHub Actions: you write workflow YAML files in the .gitea/workflows folder inside a repo, and a runner executes them. To run it, you need one runner — a process running on a server (or another machine) that registers with your Gitea using a token from Site Administration → Actions → Runners.
For personal use, a single runner on the same VPS is plenty for light workflows like running tests or builds. One warning: the runner executes code from repos, so don't casually enable a runner for repos that people you don't trust can write to. For private repos, the risk is small and the payoff is large.
Maintaining Gitea: Backups and Updates
Backing up Gitea means backing up two folders: ./gitea-data and ./postgres-data, plus the docker-compose.yml file. Schedule that backup like any other service on your VPS — those folders hold every repo and its history.
To update, the process is the same as for any other Docker Compose service:
cd /opt/gitea
docker compose pull
docker compose up -dBefore a major update (for example, moving to a new major version), read Gitea's release notes first and make sure a fresh backup exists. It's a trivial habit, but it saves you from the worst-case scenario: a failed update with no copy to fall back on.
One last security note: don't leave raw Gitea HTTP on port 3000 exposed to the internet without protection for long-term use. Put a reverse proxy with HTTPS in front of it, or restrict access through a VPN — the same pattern as other self-hosted services on your VPS.
Final Checklist
-
docker compose psshowsgiteaandgitea-dbasrunning - The installation wizard is complete and you can log in as admin
- Your SSH key is added to your account, and clone + push over port 222 work
- One old repo has been migrated with
--mirror, including all its branches and tags - Backups of
./gitea-dataand./postgres-dataare scheduled - Web access is secured (HTTPS via reverse proxy, or restricted via VPN)
Closing
With Gitea, your code comes home to your own server without giving up convenience: you still get a pleasant web UI, still get pull requests and issues, and even still get CI. And because it's light, the small VPS you already have is very likely enough — no server upgrade just to host Git.
Also read: Deploy Otomatis ke VPS dengan GitHub Actions, Docker Compose untuk Self-Hosting dari Nol, and VPS Pertama: Setup Ubuntu dan Hardening SSH.
How many repos do you still have sitting on free services? Tell me in the comments — and which repo would you move to your own Gitea first?


Komentar
Posting Komentar