git commit before)Before we begin, let's be crystal clear about what software you must have installed β and what you can safely ignore.
| Software | Linux Path | Windows Path |
|---|---|---|
| Docker Engine | Required. Install via sudo apt install docker.io |
Not required (Gitea runs as a native binary) |
| Docker Compose | Required. Install via sudo apt install docker-compose-v2 |
Not required |
| Git for Windows | Not needed (Git is built into Docker images) | Required. Download from gitforwindows.org |
| Administrator / sudo access | Required (to install Docker and run containers) | Required (to register a Windows Service) |
Each developer who will use the Gitea server needs these on their local machine:
Git Bash) that works on Windows.ssh to verify. No installation needed.This list surprises most people. You can skip installing all of these:
Gitea is famously lightweight. Here's what you actually need:
A $5/month VPS (1 GB RAM, 1 core, 25 GB SSD) can comfortably serve dozens of developers and run CI pipelines.
If your team is 4 people, GitHub Free sounds like a good deal β unlimited public and private repositories, right? But here's what it doesn't tell you:
Gitea is a lightweight, open-source Git service written in Go. It feels exactly like GitHub β Issues, Pull Requests, Code Reviews, Actions, Wikis β but runs on hardware you control. A Raspberry Pi 4 can serve a 4-person team without breaking a sweat.
To appreciate what Gitea does, it helps to understand how we got here. Version control went through three eras:
In the early days, developers copied files into timestamped directories (project-backup-2024-01-01, project-backup-2024-01-02...). Tools like RCS (Revision Control System) used local patch files to track changes β but only on a single machine. If that hard drive died, your entire project history vanished.
Systems like CVS, Subversion (SVN), and Perforce introduced a central server that held the canonical repository. Developers "checked out" files, edited them, and "checked in" changes. The server was the single source of truth.
This was a leap forward, but it had a fatal flaw: if the server went offline, nobody could commit. If the server's hard drive crashed without a backup, the entire project history was lost.
Linus Torvalds built Git for the Linux kernel development workflow. The breakthrough: every developer has a complete copy of the entire repository β full history, all branches, all tags β on their local machine.
Local Machine ββpushβββΆ Central Server (Gitea)
βββpull/fetchββ
(full history) (full history + collaboration hub)
If the central server dies, any developer's machine can restore it. This is the world Gitea lives in β the Git protocol is already distributed; Gitea just adds the collaboration layer (Issues, PRs, CI) on top.
If you're going to self-host, which platform do you choose? Here's an honest comparison for a 4-person team.
Think of GitHub as a luxury hotel β everything is taken care of, but you pay per night and follow their rules. GitLab CE is a full-service office building with heating, security, and a cafeteria β great for 50+ people but overkill (and power-hungry) for 4. Gitea and Forgejo are a cozy flat you own β small, cheap, and fully under your control.
| Feature / Platform | Gitea | GitLab CE | Forgejo | GitHub |
|---|---|---|---|---|
| RAM Required | ~40 MB (idle) | ~4 GB (minimum) | ~40 MB (idle) | N/A (SaaS) |
| Install Method | 1 binary or Docker | Full stack (Ruby, Postgres, Redis) | 1 binary or Docker | Sign up online |
| Built-in CI/CD | Gitea Actions (GitHub Actions compatible YAML) | GitLab CI (mature, powerful) | Forgejo Actions (forked from Gitea) | GitHub Actions (2,000 min/mo free) |
| UI Familiarity | 1:1 GitHub clone | Different layout, more menus | 1:1 GitHub clone | Industry standard |
| Governance | Community (open) | Commercial (GitLab Inc.) | Community (non-profit, forked from Gitea) | Commercial (Microsoft) |
| Docker Setup | 2 minutes (1 yml file) | 20+ minutes (multiple containers) | 2 minutes (1 yml file) | N/A |
| Cost for 4 users | $5/month (VPS) + $0 licensing | $10-20/month (larger VPS) + $0 licensing | $5/month (VPS) + $0 licensing | $16/month (Team plan) + $0 (Free limitations) |
Verdict for this tutorial: Gitea. It's the most mature, has the largest community, natively supports GitHub Actions-compatible CI/CD, and the UI will be instantly familiar to anyone who's used GitHub.
For 4 people, you do not need Kubernetes, load balancers, or high-availability clusters. A single machine running Docker Compose is the right architecture.
Internet βββΆ [Your VPS / Server]
β
βββ Port 3000 (Web UI)
βββ Port 2222 (SSH for Git operations)
β
βββ Docker Compose
β
βββ gitea/gitea:1.26.4
βββ (optional) postgres:16
For 4 people, SQLite is perfect. Gitea's SQLite support stores the entire database in a single file (/data/gitea/gitea.db). Zero maintenance. Zero configuration. Zero extra containers.
Postgres only becomes necessary when you have:
For a 4-person team, SQLite handles everything effortlessly. You can migrate to Postgres later if you grow.
./gitea-data/ βββ data/ # Database (SQLite), avatars, attachments βββ git/ # All your Git repositories (bare repos) βββ ssh/ # SSH keys for your team
Backing up Gitea means backing up this single folder. That's it.
This is the recommended path for production use. We'll use Docker Compose for automatic restarts, easy updates, and clean separation.
Ensure your Linux server has Docker and Docker Compose installed:
sudo apt update && sudo apt install docker.io docker-compose-v2 -y
mkdir ~/gitea && cd ~/gitea
version: '3.8'
services:
server:
image: gitea/gitea:1.26.4
container_name: gitea-server
environment:
- USER_UID=1000
- USER_GID=1000
restart: always
volumes:
- ./gitea-data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "3000:3000" # Web interface
- "2222:22" # SSH (use 2222 to avoid conflict with host SSH)
docker compose up -d
Gitea is now running. Open your browser to http://your-server-ip:3000.
docker compose logs -f shows real-time logs. docker compose ps shows the container status. If you see "Web server is ready", you're good.
If you don't have a Linux server, or you want to run Gitea on a Windows machine as a lightweight team server, here's the manual path. No Docker required.
Go to dl.gitea.com/gitea/ and download the latest Windows executable for your architecture (e.g., gitea-1.26.4-windows-4.0-amd64.exe). Rename it to gitea.exe.
C:\gitea\ βββ gitea.exe βββ custom\ βββ data\
Open an Administrator Command Prompt or PowerShell:
cd C:\gitea .\gitea.exe web
Gitea starts in the foreground. Visit http://localhost:3000 β you should see the setup wizard. Press Ctrl+C to stop it for now.
Run this command as Administrator to make Gitea start automatically on boot:
sc.exe create "Gitea" binPath="C:\gitea\gitea.exe web" start=auto sc.exe start Gitea
Gitea now runs as a background Windows service, restarting automatically if the machine reboots.
When you load Gitea for the first time (at http://your-server:3000 or http://localhost:3000), you'll see the setup wizard. Configure these settings for your 4-person team:
| Setting | Recommended Value | Why |
|---|---|---|
| Database Type | SQLite3 | Zero maintenance. A single file. Perfect for small teams. |
| Site Title | Our Team Forge (or your team name) |
Shows in the browser tab and email notifications. |
| Server Domain | Your server's IP or domain | Used in clone URLs. Set it correctly now β changing it later breaks existing clones. |
| SSH Server Port | 2222 (Linux/Docker) or 22 (Windows standalone) |
On Linux, port 22 is usually occupied by the host SSH server. |
| Gitea HTTP Port | 3000 |
Default. Don't change unless you have a conflict. |
| Gitea Base URL | http://your-server-ip:3000/ |
Must match the domain and port users will access. |
Don't clutter your Gitea dashboard with individual repos under personal namespaces. Instead, create an Organization for your team:
your-team-name (e.g., core-team)Now all repositories live under your-server:3000/core-team/project-x instead of your-server:3000/personal/project-x. This gives everyone consistent access.
For a small team, the biggest risk is someone force-pushing to main or merging broken code. Branch protection prevents this.
Navigate to: Settings β Branches β Branch Protection Rules β Add Rule
Configure for the main branch:
Gitea Actions uses GitHub Actions-compatible YAML syntax β so if you've written a .github/workflows file before, you already know how to write Gitea Actions. Gitea runs its own act_runner (a lightweight runner binary) to execute pipelines.
First, add a runner from the Gitea web UI: Settings β Actions β Runners β Create New Runner. Gitea gives you a registration token. Then, on your server:
docker run -d \ --name gitea-runner \ -e GITEA_INSTANCE_URL=http://server:3000 \ -e GITEA_RUNNER_REGISTRATION_TOKEN=YOUR_TOKEN_FROM_UI \ -v /var/run/docker.sock:/var/run/docker.sock \ gitea/act_runner:latest
Create .gitea/workflows/ci.yml in your repository:
name: Test and Deploy
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test
deploy:
needs: test
runs-on: ubuntu-latest
steps:
- run: echo "Deploying to production..."
Gitea Actions automatically picks up this file and runs the pipeline on every push. The syntax is identical to GitHub Actions β no learning curve.
Your 4-person team is likely on Windows laptops. Here's how they connect to the Gitea server.
Each developer downloads and installs Git from gitforwindows.org. During installation:
git config --global user.name "Your Name" git config --global user.email "[email protected]"
From the repository page in Gitea, copy the HTTPS clone URL and run:
git clone http://your-server-ip:3000/core-team/project-x.git
Windows will prompt for credentials. Type the Gitea username and password. Git for Windows caches credentials securely so you don't have to type them every time.
Here's the 5-command rhythm every developer on your team needs to know. Print this, tape it to your monitor.
| # | Command | What It Does |
|---|---|---|
| 1 | git status |
Check what files changed. Run this constantly to stay oriented. |
| 2 | git add <file> |
Stage specific changes. Use git add . only when you're sure everything should go in. |
| 3 | git commit -m "message" |
Take a snapshot locally. Write clear messages: "Fix login redirect bug" not "fix". |
| 4 | git push origin main |
Send your commits to Gitea. Now your teammates can see your code. |
| 5 | git pull origin main |
Get your teammates' latest changes before you start working. Do this every morning. |
# Morning: get everyone's latest changes git pull origin main # Make changes in your editor... # Check what you changed git status # Stage the changes git add . # Commit with a clear message git commit -m "Add user authentication middleware" # Push to Gitea so your team can see it git push origin main
You now have a running Gitea server with repositories, team structure, branch protection, CI/CD, and a team that knows the daily workflow. Here's what to tackle next:
./gitea-data folder to an external location using rsync or a cron job.pull β edit β add β commit β push.